func (a *AnnotationRegistry) GetInterfaceType(annotation string) (InterfaceAnnotationGenerator, error) {
	annotation = strings.TrimPrefix(annotation, "@")
	var annon InterfaceAnnotationGenerator
	var ok bool
	a.ml.RLock()
	{
		annon, ok = a.interfaceAnnotations[annotation]
	}
	a.ml.RUnlock()
	if !ok {
		return nil, fmt.Errorf("Interface Annotation @%s not found", annotation)
	}
	return annon, nil
}
GetInterfaceType returns the annotation generator associated with the giving annotation name.
package ast
import (
	"errors"
	"fmt"
	"strings"
	"sync"
	"github.com/influx6/faux/metrics"
	"github.com/influx6/moz/gen"
)
type TypeAnnotationGenerator func(string, AnnotationDeclaration, TypeDeclaration, PackageDeclaration, Package) ([]gen.WriteDirective, error)
type FunctionAnnotationGenerator func(string, AnnotationDeclaration, FuncDeclaration, PackageDeclaration, Package) ([]gen.WriteDirective, error)
type StructAnnotationGenerator func(string, AnnotationDeclaration, StructDeclaration, PackageDeclaration, Package) ([]gen.WriteDirective, error)
type InterfaceAnnotationGenerator func(string, AnnotationDeclaration, InterfaceDeclaration, PackageDeclaration, Package) ([]gen.WriteDirective, error)
type PackageAnnotationGenerator func(string, AnnotationDeclaration, PackageDeclaration, Package) ([]gen.WriteDirective, error)
type Annotations struct {
	Types      map[string]TypeAnnotationGenerator
	Structs    map[string]StructAnnotationGenerator
	Functions  map[string]FunctionAnnotationGenerator
	Packages   map[string]PackageAnnotationGenerator
	Interfaces map[string]InterfaceAnnotationGenerator
}
type AnnotationRegistry struct {
	metrics              metrics.Metrics
	ml                   sync.RWMutex
	typeAnnotations      map[string]TypeAnnotationGenerator
	structAnnotations    map[string]StructAnnotationGenerator
	pkgAnnotations       map[string]PackageAnnotationGenerator
	interfaceAnnotations map[string]InterfaceAnnotationGenerator
	functionAnnotations  map[string]FunctionAnnotationGenerator
}
func NewAnnotationRegistry() *AnnotationRegistry {
	return &AnnotationRegistry{
		metrics:              metrics.New(),
		typeAnnotations:      make(map[string]TypeAnnotationGenerator),
		structAnnotations:    make(map[string]StructAnnotationGenerator),
		pkgAnnotations:       make(map[string]PackageAnnotationGenerator),
		interfaceAnnotations: make(map[string]InterfaceAnnotationGenerator),
		functionAnnotations:  make(map[string]FunctionAnnotationGenerator),
	}
}
func NewAnnotationRegistryWith(log metrics.Metrics) *AnnotationRegistry {
	return &AnnotationRegistry{
		metrics:              log,
		typeAnnotations:      make(map[string]TypeAnnotationGenerator),
		structAnnotations:    make(map[string]StructAnnotationGenerator),
		pkgAnnotations:       make(map[string]PackageAnnotationGenerator),
		interfaceAnnotations: make(map[string]InterfaceAnnotationGenerator),
		functionAnnotations:  make(map[string]FunctionAnnotationGenerator),
	}
}
func (a *AnnotationRegistry) Clone() Annotations {
	a.ml.RLock()
	defer a.ml.RUnlock()
	var cloned Annotations
	cloned.Types = make(map[string]TypeAnnotationGenerator)
	cloned.Structs = make(map[string]StructAnnotationGenerator)
	cloned.Packages = make(map[string]PackageAnnotationGenerator)
	cloned.Interfaces = make(map[string]InterfaceAnnotationGenerator)
	cloned.Functions = make(map[string]FunctionAnnotationGenerator)
	for name, item := range a.pkgAnnotations {
		cloned.Packages[name] = item
	}
	for name, item := range a.functionAnnotations {
		cloned.Functions[name] = item
	}
	for name, item := range a.structAnnotations {
		cloned.Structs[name] = item
	}
	for name, item := range a.typeAnnotations {
		cloned.Types[name] = item
	}
	for name, item := range a.interfaceAnnotations {
		cloned.Interfaces[name] = item
	}
	return cloned
}
type CopyStrategy int
const (
	OursOverTheirs CopyStrategy = iota + 1
	TheirsOverOurs
)
func (a *AnnotationRegistry) Copy(registry *AnnotationRegistry, strategy CopyStrategy) {
	cloned := registry.Clone()
	a.ml.Lock()
	defer a.ml.Unlock()
	for name, item := range cloned.Packages {
		_, ok := a.pkgAnnotations[name]
		if !ok || (ok && strategy == TheirsOverOurs) {
			a.pkgAnnotations[name] = item
		}
	}
	for name, item := range cloned.Functions {
		_, ok := a.functionAnnotations[name]
		if !ok || (ok && strategy == TheirsOverOurs) {
			a.functionAnnotations[name] = item
		}
	}
	for name, item := range cloned.Types {
		_, ok := a.typeAnnotations[name]
		if !ok || (ok && strategy == TheirsOverOurs) {
			a.typeAnnotations[name] = item
		}
	}
	for name, item := range cloned.Structs {
		_, ok := a.structAnnotations[name]
		if !ok || (ok && strategy == TheirsOverOurs) {
			a.structAnnotations[name] = item
		}
	}
	for name, item := range cloned.Interfaces {
		_, ok := a.interfaceAnnotations[name]
		if !ok || (ok && strategy == TheirsOverOurs) {
			a.interfaceAnnotations[name] = item
		}
	}
}
func (a *AnnotationRegistry) MustPackage(annotation string) PackageAnnotationGenerator {
	annon, err := a.GetPackage(annotation)
	if err == nil {
		return annon
	}
	panic(err)
}
type AnnotationWriteDirective struct {
	gen.WriteDirective
	Annotation string
}
func (a *AnnotationRegistry) ParseDeclr(pkg Package, declr PackageDeclaration, toDir string) ([]AnnotationWriteDirective, error) {
	var directives []AnnotationWriteDirective
	for _, annotation := range declr.Annotations {
		a.metrics.Emit(metrics.Info("Directive Generation"),
			metrics.With("Level", "Package"), metrics.With("Annotaton", annotation.Name), metrics.With("Params", annotation.Params), metrics.With("Arguments", annotation.Arguments), metrics.With("Template", annotation.Template))
		generator, err := a.GetPackage(annotation.Name)
		if err != nil {
			continue
		}
		drs, err := generator(toDir, annotation, declr, pkg)
		if err != nil {
			a.metrics.Emit(metrics.Error(errors.New("Directive Generation")),
				metrics.With("error", err), metrics.With("Level", "Package"), metrics.With("Annotaton", annotation.Name), metrics.With("Params", annotation.Params), metrics.With("Arguments", annotation.Arguments), metrics.With("Template", annotation.Template))
			return nil, err
		}
		a.metrics.Emit(metrics.Info("Directive Generation: Success"),
			metrics.With("Level", "Package"),
			metrics.With("Directive", len(drs)),
			metrics.With("Annotaton", annotation.Name),
			metrics.With("Params", annotation.Params),
			metrics.With("Arguments", annotation.Arguments),
			metrics.With("Template", annotation.Template))
		for _, directive := range drs {
			directives = append(directives, AnnotationWriteDirective{
				WriteDirective: directive,
				Annotation:     annotation.Name,
			})
		}
	}
	for _, inter := range declr.Interfaces {
		for _, annotation := range inter.Annotations {
			a.metrics.Emit(metrics.Info("Directive Generation"),
				metrics.With("Level", "Interface"),
				metrics.With("Annotaton", annotation.Name),
				metrics.With("Interface", inter.Object.Name.Name),
				metrics.With("Params", annotation.Params),
				metrics.With("Arguments", annotation.Arguments),
				metrics.With("Template", annotation.Template))
			generator, err := a.GetInterfaceType(annotation.Name)
			if err != nil {
				a.metrics.Emit(metrics.Error(errors.New("Directive Generation")),
					metrics.With("error", err),
					metrics.With("Level", "Interface"),
					metrics.With("Annotaton", annotation.Name),
					metrics.With("Interface", inter.Object.Name.Name),
					metrics.With("Params", annotation.Params),
					metrics.With("Arguments", annotation.Arguments),
					metrics.With("Template", annotation.Template))
				continue
			}
			drs, err := generator(toDir, annotation, inter, declr, pkg)
			if err != nil {
				a.metrics.Emit(metrics.Error(errors.New("Directive Generation")),
					metrics.With("error", err),
					metrics.With("Level", "Interface"),
					metrics.With("Annotaton", annotation.Name),
					metrics.With("Interface", inter.Object.Name.Name),
					metrics.With("Params", annotation.Params),
					metrics.With("Arguments", annotation.Arguments),
					metrics.With("Template", annotation.Template))
				return nil, err
			}
			a.metrics.Emit(metrics.Info("Directive Generation: Success"),
				metrics.With("Level", "Interface"),
				metrics.With("Directive", len(drs)),
				metrics.With("Annotaton", annotation.Name),
				metrics.With("nterface", inter.Object.Name.Name),
				metrics.With("Params", annotation.Params),
				metrics.With("Arguments", annotation.Arguments),
				metrics.With("Template", annotation.Template))
			for _, directive := range drs {
				directives = append(directives, AnnotationWriteDirective{
					WriteDirective: directive,
					Annotation:     annotation.Name,
				})
			}
		}
	}
	for _, structs := range declr.Structs {
		for _, annotation := range structs.Annotations {
			a.metrics.Emit(metrics.Info("Directive Generation"),
				metrics.With("Level", "Struct"),
				metrics.With("Annotaton", annotation.Name),
				metrics.With("Struct", structs.Object.Name.Name),
				metrics.With("Params", annotation.Params),
				metrics.With("Arguments", annotation.Arguments),
				metrics.With("Template", annotation.Template))
			generator, err := a.GetStructType(annotation.Name)
			if err != nil {
				a.metrics.Emit(metrics.Error(errors.New("Directive Generation")),
					metrics.With("error", err),
					metrics.With("Level", "Struct"),
					metrics.With("Annotaton", annotation.Name),
					metrics.With("Struct", structs.Object.Name.Name),
					metrics.With("Params", annotation.Params),
					metrics.With("Arguments", annotation.Arguments),
					metrics.With("Template", annotation.Template))
				continue
			}
			drs, err := generator(toDir, annotation, structs, declr, pkg)
			if err != nil {
				a.metrics.Emit(metrics.Error(errors.New("Directive Generation")),
					metrics.With("error", err),
					metrics.With("Level", "Struct"),
					metrics.With("Annotaton", annotation.Name),
					metrics.With("Struct", structs.Object.Name.Name),
					metrics.With("Params", annotation.Params),
					metrics.With("Arguments", annotation.Arguments),
					metrics.With("Template", annotation.Template))
				return nil, err
			}
			a.metrics.Emit(metrics.Info("Directive Generation: Success"),
				metrics.With("Level", "Struct"),
				metrics.With("Directive", len(drs)),
				metrics.With("Annotaton", annotation.Name),
				metrics.With("Struct", structs.Object.Name.Name),
				metrics.With("Params", annotation.Params),
				metrics.With("Arguments", annotation.Arguments),
				metrics.With("Template", annotation.Template))
			for _, directive := range drs {
				directives = append(directives, AnnotationWriteDirective{
					WriteDirective: directive,
					Annotation:     annotation.Name,
				})
			}
		}
	}
	for _, typ := range declr.Functions {
		for _, annotation := range typ.Annotations {
			a.metrics.Emit(metrics.Info("Directive Generation"),
				metrics.With("Level", "Type"),
				metrics.With("Annotaton", annotation.Name),
				metrics.With("Function", typ.FuncDeclr.Name.Name),
				metrics.With("Params", annotation.Params),
				metrics.With("Arguments", annotation.Arguments),
				metrics.With("Template", annotation.Template))
			generator, err := a.GetFunctionType(annotation.Name)
			if err != nil {
				a.metrics.Emit(metrics.Error(errors.New("Directive Generation")),
					metrics.With("error", err),
					metrics.With("Level", "Type"),
					metrics.With("Annotaton", annotation.Name),
					metrics.With("Function", typ.FuncDeclr.Name.Name),
					metrics.With("Params", annotation.Params),
					metrics.With("Arguments", annotation.Arguments),
					metrics.With("Template", annotation.Template))
				continue
			}
			drs, err := generator(toDir, annotation, typ, declr, pkg)
			if err != nil {
				a.metrics.Emit(metrics.Error(errors.New("Directive Generation")),
					metrics.With("error", err),
					metrics.With("Level", "Type"),
					metrics.With("Annotaton", annotation.Name),
					metrics.With("Function", typ.FuncDeclr.Name.Name),
					metrics.With("Params", annotation.Params),
					metrics.With("Arguments", annotation.Arguments),
					metrics.With("Template", annotation.Template))
				return nil, err
			}
			a.metrics.Emit(metrics.Info("Directive Generation: Success"),
				metrics.With("Level", "Type"),
				metrics.With("Directive", len(drs)),
				metrics.With("Annotaton", annotation.Name),
				metrics.With("Function", typ.FuncDeclr.Name.Name),
				metrics.With("Params", annotation.Params),
				metrics.With("Arguments", annotation.Arguments),
				metrics.With("Template", annotation.Template))
			for _, directive := range drs {
				directives = append(directives, AnnotationWriteDirective{
					WriteDirective: directive,
					Annotation:     annotation.Name,
				})
			}
		}
	}
	for _, typ := range declr.Types {
		for _, annotation := range typ.Annotations {
			a.metrics.Emit(metrics.Info("Directive Generation"),
				metrics.With("Level", "Type"),
				metrics.With("Annotaton", annotation.Name),
				metrics.With("Type", typ.Object.Name.Name),
				metrics.With("Params", annotation.Params),
				metrics.With("Arguments", annotation.Arguments),
				metrics.With("Template", annotation.Template))
			generator, err := a.GetType(annotation.Name)
			if err != nil {
				a.metrics.Emit(metrics.Error(errors.New("Directive Generation")),
					metrics.With("error", err),
					metrics.With("Level", "Type"),
					metrics.With("Annotaton", annotation.Name),
					metrics.With("Type", typ.Object.Name.Name),
					metrics.With("Params", annotation.Params),
					metrics.With("Arguments", annotation.Arguments),
					metrics.With("Template", annotation.Template))
				continue
			}
			drs, err := generator(toDir, annotation, typ, declr, pkg)
			if err != nil {
				a.metrics.Emit(metrics.Error(errors.New("Directive Generation")),
					metrics.With("error", err),
					metrics.With("Level", "Type"),
					metrics.With("Annotaton", annotation.Name),
					metrics.With("Type", typ.Object.Name.Name),
					metrics.With("Params", annotation.Params),
					metrics.With("Arguments", annotation.Arguments),
					metrics.With("Template", annotation.Template))
				return nil, err
			}
			a.metrics.Emit(metrics.Info("Directive Generation: Success"),
				metrics.With("Level", "Type"),
				metrics.With("Directive", len(drs)),
				metrics.With("Annotaton", annotation.Name),
				metrics.With("Type", typ.Object.Name.Name),
				metrics.With("Params", annotation.Params),
				metrics.With("Arguments", annotation.Arguments),
				metrics.With("Template", annotation.Template))
			for _, directive := range drs {
				directives = append(directives, AnnotationWriteDirective{
					WriteDirective: directive,
					Annotation:     annotation.Name,
				})
			}
		}
	}
	return directives, nil
}
func (a *AnnotationRegistry) GetPackage(annotation string) (PackageAnnotationGenerator, error) {
	annotation = strings.TrimPrefix(annotation, "@")
	var annon PackageAnnotationGenerator
	var ok bool
	a.ml.RLock()
	{
		annon, ok = a.pkgAnnotations[annotation]
	}
	a.ml.RUnlock()
	if !ok {
		return nil, fmt.Errorf("Package Annotation @%s not found", annotation)
	}
	return annon, nil
}
func (a *AnnotationRegistry) MustInterfaceType(annotation string) InterfaceAnnotationGenerator {
	annon, err := a.GetInterfaceType(annotation)
	if err == nil {
		return annon
	}
	panic(err)
}
func (a *AnnotationRegistry) MustFunctionType(annotation string) FunctionAnnotationGenerator {
	annon, err := a.GetFunctionType(annotation)
	if err == nil {
		return annon
	}
	panic(err)
}
func (a *AnnotationRegistry) GetFunctionType(annotation string) (FunctionAnnotationGenerator, error) {
	annotation = strings.TrimPrefix(annotation, "@")
	var annon FunctionAnnotationGenerator
	var ok bool
	a.ml.RLock()
	{
		annon, ok = a.functionAnnotations[annotation]
	}
	a.ml.RUnlock()
	if !ok {
		return nil, fmt.Errorf("Function/Method Annotation @%s not found", annotation)
	}
	return annon, nil
}