package transcoder

import (
	"encoding/binary"

	"v.io/v23/vdl"
)

// for struct
type fieldsTarget struct {
	vdlType *vdl.Type
	block   bytesRef
}

func (fe fieldsTarget) StartField(name string) (key, field vdl.Target, _ error) {
	fieldType, fieldIndex := fe.vdlType.FieldByName(name)
	byteOffset, bitOffset := offsetInStruct(fieldIndex, fe.vdlType)
	numBits := baseTypeSizeBits(fieldType.Type)
	refSize := (numBits + 7) / 8
	newRef := fe.block.Slice(byteOffset, byteOffset+refSize)
	return nil, target{
		currentBitOffset: bitOffset,
		current:          newRef,
	}, nil
}
func (fieldsTarget) FinishField(key, field vdl.Target) error {
	return nil
}

type unionFieldsTarget struct {
	vdlType *vdl.Type
	block   bytesRef
}

func (ufe unionFieldsTarget) StartField(name string) (key, field vdl.Target, _ error) {
	fld, index := ufe.vdlType.FieldByName(name)
	binary.LittleEndian.PutUint32(ufe.block.Bytes(), 16)
	binary.LittleEndian.PutUint32(ufe.block.Bytes()[4:], uint32(index))

	valueSlice := ufe.block.Slice(8, 16)
	if fld.Type.Kind() == vdl.Union {
		// nested union, create a pointer to the body
		nestedUnionBlock := ufe.block.allocator.Allocate(8, 0)
		offset := nestedUnionBlock.AsPointer(valueSlice)
		binary.LittleEndian.PutUint64(valueSlice.Bytes(), uint64(offset))
		return nil, target{
			currentBitOffset: 0,
			current:          nestedUnionBlock.SignedSlice(-8, 8),
		}, nil
	}
	return nil, target{
		currentBitOffset: 0,
		current:          valueSlice,
	}, nil
}
func (unionFieldsTarget) FinishField(key, field vdl.Target) error {
	return nil
}

// doubles as set target
type listTarget struct {
	incrementSize uint32
	block         bytesRef
	nextPosition  uint32
}

func (lt *listTarget) StartElem(index int) (elem vdl.Target, _ error) {
	// TODO(bprosnitz) Index is ignored -- we should probably remove this from Target.
	sliceBlock := lt.block.Slice(lt.nextPosition, lt.nextPosition+lt.incrementSize)
	lt.nextPosition += lt.incrementSize
	return target{
		current: sliceBlock,
	}, nil
}
func (lt *listTarget) StartKey() (key vdl.Target, _ error) {
	return lt.StartElem(0)
}
func (listTarget) FinishElem(elem vdl.Target) error {
	return nil
}
func (listTarget) FinishKey(key vdl.Target) error {
	return nil
}

type bitListTarget struct {
	block           bytesRef
	nextBitPosition uint32
}

func (blt *bitListTarget) StartElem(index int) (elem vdl.Target, _ error) {
	bitPos := blt.nextBitPosition
	blt.nextBitPosition++
	byteIndex := bitPos / 8
	sliceBlock := blt.block.Slice(byteIndex, byteIndex+1)
	return target{
		currentBitOffset: uint8(bitPos % 8),
		current:          sliceBlock,
	}, nil
}
func (blt *bitListTarget) StartKey() (key vdl.Target, _ error) {
	return blt.StartElem(0)
}
func (bitListTarget) FinishElem(elem vdl.Target) error {
	return nil
}
func (bitListTarget) FinishKey(key vdl.Target) error {
	return nil
}

type mapTarget struct {
	listTarget vdl.ListTarget
	setTarget  vdl.SetTarget
}

func (mt *mapTarget) StartKey() (key vdl.Target, _ error) {
	return mt.setTarget.StartKey()
}
func (mt *mapTarget) FinishKeyStartField(key vdl.Target) (field vdl.Target, _ error) {
	return mt.listTarget.StartElem(0)
}
func (mapTarget) FinishField(key, field vdl.Target) error {
	return nil
}
