package yu_proto_old

import (
	"encoding"
)

var generators = newInterfaceRegistry()

// InterfaceMarshaler is used to differentiate implementations of an
// interface when encoding/decoding
type InterfaceMarshaler interface {
	encoding.BinaryMarshaler
	MarshalID() [8]byte
}

// InterfaceGeneratorFunc generates an instance of the implementation
// of an interface
type InterfaceGeneratorFunc func() interface{}

// GeneratorID is the key used to map the generator functions
type GeneratorID [8]byte

type generatorRegistry struct {
	generators map[GeneratorID]InterfaceGeneratorFunc
}

func newInterfaceRegistry() *generatorRegistry {
	return &generatorRegistry{
		generators: make(map[GeneratorID]InterfaceGeneratorFunc),
	}
}

// register gets the type tag and map it to the generator function
func (ir *generatorRegistry) register(g InterfaceGeneratorFunc) {
	val, ok := g().(InterfaceMarshaler)
	if !ok {
		panic("Implementation of the interface must fulfilled InterfaceMarshaler")
	}
	key := val.MarshalID()

	ir.generators[key] = g
}

// get returns the generator associated with the tag
func (ir *generatorRegistry) get(key GeneratorID) InterfaceGeneratorFunc {
	g, _ := ir.generators[key]
	return g
}

// RegisterInterface registers the generator to be used to decode
// the type generated by the function
func RegisterInterface(f InterfaceGeneratorFunc) {
	generators.register(f)
}
