package yu_proto_old

import (
	"encoding"
	"encoding/binary"
	"errors"
	"fmt"
	"math"
	"reflect"
	"time"
)

// Constructors represents a map defining how to instantiate any interface
// types that Decode() might encounter while reading and decoding structured
// data. The keys are reflect.Type values denoting interface types. The
// corresponding values are functions expected to instantiate, and initialize
// as necessary, an appropriate concrete object type supporting that
// interface. A caller could use this capability to support
// dynamic instantiation of objects of the concrete type
// appropriate for a given abstract type.
type Constructors map[reflect.Type]func() interface{}

// String returns an easy way to visualize what you have in your constructors.
func (c *Constructors) String() string {
	var s string
	for k := range *c {
		s += k.String() + "=>" + "(func() interface {})" + "\t"
	}
	return s
}

// Decoder is the main struct used to decode a protobuf blob.
type decoder struct {
	nm Constructors
}

// Decode a protocol buffer into a Go struct.
// The caller must pass a pointer to the struct to decode into.
//
// Decode() currently does not explicitly check that all 'required' fields
// are actually present in the input buffer being decoded.
// If required fields are missing, then the corresponding fields
// will be left unmodified, meaning they will take on
// their default Go zero values if Decode() is passed a fresh struct.
func Decode(buf []byte, structPtr interface{}) error {
	return DecodeWithConstructors(buf, structPtr, nil)
}

// DecodeWithConstructors is like Decode, but you can pass a map of
// constructors with which to instantiate interface types.
func DecodeWithConstructors(buf []byte, structPtr interface{}, cons Constructors) (err error) {
	defer func() {
		if r := recover(); r != nil {
			switch e := r.(type) {
			case string:
				err = errors.New(e)
			case error:
				err = e
			default:
				err = errors.New("Failed to decode the field")
			}
		}
	}()
	if structPtr == nil {
		return nil
	}

	if bu, ok := structPtr.(encoding.BinaryUnmarshaler); ok {
		return bu.UnmarshalBinary(buf)
	}

	de := decoder{cons}
	val := reflect.ValueOf(structPtr)
	// if its NOT a pointer, it is bad return an error
	if val.Kind() != reflect.Ptr {
		return errors.New("Decode has been given a non pointer type")
	}
	return de.message(buf, val.Elem())
}

// Decode a Protocol Buffers message into a Go struct.
// The Kind of the passed value v must be Struct.
func (de *decoder) message(buf []byte, sval reflect.Value) error {
	if sval.Kind() != reflect.Struct {
		return errors.New("not a struct")
	}

	for i := 0; i < sval.NumField(); i++ {
		switch field := sval.Field(i); field.Kind() {
		case reflect.Interface:
			// Interface are not reset because the decoder won't
			// be able to instantiate it again in some scenarios.
		default:
			if field.CanSet() {
				field.Set(reflect.Zero(field.Type()))
			}
		}
	}

	// Decode all the fields
	fields := ProtoFields(sval.Type())
	fieldi := 0
	for len(buf) > 0 {
		// Parse the key
		key, n := binary.Uvarint(buf)
		if n <= 0 {
			return errors.New("bad protobuf field key")
		}
		buf = buf[n:]
		wiretype := int(key & 7)
		fieldnum := key >> 3

		// Lookup the corresponding struct field.
		// Leave field with a zero Value if fieldnum is out-of-range.
		// In this case, as well as for blank fields,
		// value() will just skip over and discard the field content.
		var field reflect.Value
		for fieldi < len(fields) && fields[fieldi].ID < int64(fieldnum) {
			fieldi++
		}

		if fieldi < len(fields) && fields[fieldi].ID == int64(fieldnum) {
			// For fields within embedded structs, ensure the embedded values aren't nil.
			index := fields[fieldi].Index
			path := make([]int, 0, len(index))
			for _, id := range index {
				path = append(path, id)
				field = sval.FieldByIndex(path)
				if field.Kind() == reflect.Ptr && field.IsNil() {
					field.Set(reflect.New(field.Type().Elem()))
				}
			}
		}

		// For more debugging output, uncomment the following three lines.
		// if fieldi < len(fields){
		//   fmt.Printf("Decoding FieldName %+v\n", fields[fieldi].Field)
		// }
		// Decode the field's value
		rem, err := de.value(wiretype, buf, field)
		if err != nil {
			if fieldi < len(fields) && fields[fieldi] != nil {
				return fmt.Errorf("Error while decoding field %+v: %v", fields[fieldi].Field, err)
			}

			return err
		}
		buf = rem
	}
	return nil
}

// Pull a value from the buffer and put it into a reflective Value.
func (de *decoder) value(wiretype int, buf []byte,
	val reflect.Value) ([]byte, error) {

	// Break out the value from the buffer based on the wire type
	var v uint64
	var n int
	var vb []byte
	switch wiretype {
	case 0: // varint
		v, n = binary.Uvarint(buf)
		if n <= 0 {
			return nil, errors.New("bad protobuf varint value")
		}
		buf = buf[n:]

	case 5: // 32-bit
		if len(buf) < 4 {
			return nil, errors.New("bad protobuf 32-bit value")
		}
		v = uint64(buf[0]) |
			uint64(buf[1])<<8 |
			uint64(buf[2])<<16 |
			uint64(buf[3])<<24
		buf = buf[4:]

	case 1: // 64-bit
		if len(buf) < 8 {
			return nil, errors.New("bad protobuf 64-bit value")
		}
		v = uint64(buf[0]) |
			uint64(buf[1])<<8 |
			uint64(buf[2])<<16 |
			uint64(buf[3])<<24 |
			uint64(buf[4])<<32 |
			uint64(buf[5])<<40 |
			uint64(buf[6])<<48 |
			uint64(buf[7])<<56
		buf = buf[8:]

	case 2: // length-delimited
		v, n = binary.Uvarint(buf)
		if n <= 0 || v > uint64(len(buf)-n) {
			return nil, errors.New(
				"bad protobuf length-delimited value")
		}
		vb = buf[n : n+int(v) : n+int(v)]
		buf = buf[n+int(v):]

	default:
		return nil, errors.New("unknown protobuf wire-type")
	}

	// We've gotten the value out of the buffer,
	// now put it into the appropriate reflective Value.
	if err := de.putvalue(wiretype, val, v, vb); err != nil {
		return nil, err
	}
	return buf, nil
}

func (de *decoder) decodeSignedInt(wiretype int, v uint64) (int64, error) {
	if wiretype == 0 { // encoded as varint
		sv := int64(v) >> 1
		if v&1 != 0 {
			sv = ^sv
		}
		return sv, nil
	} else if wiretype == 5 { // sfixed32
		return int64(int32(v)), nil
	} else if wiretype == 1 { // sfixed64
		return int64(v), nil
	} else {
		return -1, errors.New("bad wiretype for sint")
	}
}

func (de *decoder) putvalue(wiretype int, val reflect.Value,
	v uint64, vb []byte) error {
	// If val is not settable, it either represents an out-of-range field
	// or an in-range but blank (padding) field in the struct.
	// In this case, simply ignore and discard the field's content.
	if !val.CanSet() {
		return nil
	}
	switch val.Kind() {
	case reflect.Bool:
		if wiretype != 0 {
			return errors.New("bad wiretype for bool")
		}
		if v > 1 {
			return errors.New("invalid bool value")
		}
		val.SetBool(v != 0)

	case reflect.Int, reflect.Int32, reflect.Int64:
		// Signed integers may be encoded either zigzag-varint or fixed
		// Note that protobufs don't support 8- or 16-bit ints.
		if val.Kind() == reflect.Int && val.Type().Size() < 8 {
			return errors.New("detected a 32bit machine, please use either int64 or int32")
		}
		sv, err := de.decodeSignedInt(wiretype, v)
		if err != nil {
			fmt.Println("Error Reflect.Int for v=", v, "wiretype=", wiretype, "for Value=", val.Type().Name())
			return err
		}
		val.SetInt(sv)

	case reflect.Uint, reflect.Uint32, reflect.Uint64:
		// Varint-encoded 32-bit and 64-bit unsigned integers.
		if val.Kind() == reflect.Uint && val.Type().Size() < 8 {
			return errors.New("detected a 32bit machine, please use either uint64 or uint32")
		}
		if wiretype == 0 {
			val.SetUint(v)
		} else if wiretype == 5 { // ufixed32
			val.SetUint(uint64(uint32(v)))
		} else if wiretype == 1 { // ufixed64
			val.SetUint(uint64(v))
		} else {
			return errors.New("bad wiretype for uint")
		}

	case reflect.Float32:
		// Fixed-length 32-bit floats.
		if wiretype != 5 {
			return errors.New("bad wiretype for float32")
		}
		val.SetFloat(float64(math.Float32frombits(uint32(v))))

	case reflect.Float64:
		// Fixed-length 64-bit floats.
		if wiretype != 1 {
			return errors.New("bad wiretype for float64")
		}
		val.SetFloat(math.Float64frombits(v))

	case reflect.String:
		// Length-delimited string.
		if wiretype != 2 {
			return errors.New("bad wiretype for string")
		}
		val.SetString(string(vb))

	case reflect.Struct:
		// Embedded message
		if val.Type() == timeType {
			sv, err := de.decodeSignedInt(wiretype, v)
			if err != nil {
				return err
			}
			t := time.Unix(sv/int64(time.Second), sv%int64(time.Second))
			val.Set(reflect.ValueOf(t))
			return nil
		} else if enc, ok := val.Addr().Interface().(encoding.BinaryUnmarshaler); ok {
			return enc.UnmarshalBinary(vb[:])
		}
		if wiretype != 2 {
			return errors.New("bad wiretype for embedded message")
		}
		return de.message(vb, val)

	case reflect.Ptr:
		// Optional field
		// Instantiate pointer's element type.
		if val.IsNil() {
			val.Set(de.instantiate(val.Type().Elem()))
		}
		return de.putvalue(wiretype, val.Elem(), v, vb)

	case reflect.Slice, reflect.Array:
		// Repeated field or byte-slice
		if wiretype != 2 {
			return errors.New("bad wiretype for repeated field")
		}
		return de.slice(val, vb)
	case reflect.Map:
		if wiretype != 2 {
			return errors.New("bad wiretype for repeated field")
		}
		if val.IsNil() {
			// make(map[k]v):
			val.Set(reflect.MakeMap(val.Type()))
		}
		return de.mapEntry(val, vb)
	case reflect.Interface:
		data := vb[:]

		// Abstract field: instantiate via dynamic constructor.
		if val.IsNil() {
			id := GeneratorID{}
			var g InterfaceGeneratorFunc
			if len(id) < len(vb) {
				copy(id[:], vb[:len(id)])
				g = generators.get(id)
			}

			if g == nil {
				// Backwards compatible usage of the default constructors
				val.Set(de.instantiate(val.Type()))
			} else {
				// As pointers to interface are discouraged in Go, we use
				// the generator only for interface types
				data = vb[len(id):]
				val.Set(reflect.ValueOf(g()))
			}
		}

		// If the object support self-decoding, use that.
		if enc, ok := val.Interface().(encoding.BinaryUnmarshaler); ok {
			if wiretype != 2 {
				return errors.New("bad wiretype for bytes")
			}

			return enc.UnmarshalBinary(data)
		}

		// Decode into the object the interface points to.
		// XXX perhaps better ONLY to support self-decoding
		// for interface fields?
		return Decode(vb, val.Interface())

	default:
		panic("unsupported value kind " + val.Kind().String())
	}
	return nil
}

// Instantiate an arbitrary type, handling dynamic interface types.
// Returns a Ptr value.
func (de *decoder) instantiate(t reflect.Type) reflect.Value {

	// If it's an interface type, lookup a dynamic constructor for it.
	if t.Kind() == reflect.Interface {
		newfunc, ok := de.nm[t]
		if !ok {
			panic("no constructor for interface " + t.String())
		}
		return reflect.ValueOf(newfunc())
	}

	// Otherwise, for all concrete types, just instantiate directly.
	return reflect.New(t)
}

var sfixed32type = reflect.TypeOf(Sfixed32(0))
var sfixed64type = reflect.TypeOf(Sfixed64(0))
var ufixed32type = reflect.TypeOf(Ufixed32(0))
var ufixed64type = reflect.TypeOf(Ufixed64(0))

// Handle decoding of slices
func (de *decoder) slice(slval reflect.Value, vb []byte) error {
	// Find the element type, and create a temporary instance of it.
	eltype := slval.Type().Elem()
	val := reflect.New(eltype).Elem()

	// Decide on the wiretype to use for decoding.
	var wiretype int
	switch eltype.Kind() {
	case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Int,
		reflect.Uint32, reflect.Uint64, reflect.Uint:
		if (eltype.Kind() == reflect.Int || eltype.Kind() == reflect.Uint) && eltype.Size() < 8 {
			return errors.New("detected a 32bit machine, please either use (u)int64 or (u)int32")
		}
		switch eltype {

		case sfixed32type:
			wiretype = 5 // Packed 32-bit representation
		case sfixed64type:
			wiretype = 1 // Packed 64-bit representation
		case ufixed32type:
			wiretype = 5 // Packed 32-bit representation
		case ufixed64type:
			wiretype = 1 // Packed 64-bit representation
		default:
			wiretype = 0 // Packed varint representation
		}

	case reflect.Float32:
		wiretype = 5 // Packed 32-bit representation

	case reflect.Float64:
		wiretype = 1 // Packed 64-bit representation

	case reflect.Uint8: // Unpacked byte-slice
		if slval.Kind() == reflect.Array {
			if slval.Len() != len(vb) {
				return errors.New("array length and buffer length differ")
			}
			for i := 0; i < slval.Len(); i++ {
				// no SetByte method in reflect so has to pass down by uint64
				slval.Index(i).SetUint(uint64(vb[i]))
			}
		} else {
			slval.SetBytes(vb)
		}
		return nil

	default: // Other unpacked repeated types
		// Just unpack and append one value from vb.
		if err := de.putvalue(2, val, 0, vb); err != nil {
			return err
		}
		if slval.Kind() != reflect.Slice {
			return errors.New("append to non-slice")
		}
		slval.Set(reflect.Append(slval, val))
		return nil
	}

	// Decode packed values from the buffer and append them to the slice.
	for len(vb) > 0 {
		rem, err := de.value(wiretype, vb, val)
		if err != nil {
			return err
		}
		slval.Set(reflect.Append(slval, val))
		vb = rem
	}
	return nil
}

// Handles the entry k,v of a map[K]V
func (de *decoder) mapEntry(slval reflect.Value, vb []byte) error {
	mKey := reflect.New(slval.Type().Key())
	mVal := reflect.New(slval.Type().Elem())
	k := mKey.Elem()
	v := mVal.Elem()
	key, n := binary.Uvarint(vb)
	if n <= 0 {
		return errors.New("bad protobuf field key")
	}
	buf := vb[n:]
	wiretype := int(key & 7)

	var err error
	buf, err = de.value(wiretype, buf, k)
	if err != nil {
		return err
	}
	for len(buf) > 0 { // for repeated values (slices etc)
		key, n = binary.Uvarint(buf)
		if n <= 0 {
			return errors.New("bad protobuf field key")
		}
		buf = buf[n:]
		wiretype = int(key & 7)
		buf, err = de.value(wiretype, buf, v)
		if err != nil {
			return err
		}
	}

	if !k.IsValid() || !v.IsValid() {
		// We did not decode the key or the value in the map entry.
		// Either way, it's an invalid map entry.
		return errors.New("proto: bad map data: missing key/val")
	}
	slval.SetMapIndex(k, v)

	return nil
}
