func (f Function) RootAttribute() string {
	if f.FnAttributeList != "" {
		if f.IsAttributeListSlice() {
			return strings.Split(f.FnAttributeList, "#")[0]
		}
		return strings.Split(f.FnAttributeList, ".")[0]
	}
	return f.Entity
}
RootAttribute returns the first attribute of the
FnAttributeList even if it is a List (#) or a
method call (.)
package main
import (
	"fmt"
	"html/template"
	"io"
	"strings"
	"github.com/jinzhu/inflection"
	"github.com/pkg/errors"
)
const (
	packageTmpl = `
	package reader
	`
	arTmpl = `
	type Reader interface {
		GetAccountID() string
		GetRegion() string
		{{ range . }}
			{{ .Documentation -}}
			{{ .Signature }}
		{{ end }}
	}
	`
	functionTmpl = `
		func (c *connector) {{ .Signature }} {
			{{ if ne .FilterByOwner ""}}
				if input == nil {
					input = &{{.Input}}{}
				}
				input.{{.FilterByOwner}} = append(input.{{.FilterByOwner}}, c.accountID)
			{{ end -}}
			if c.svc.{{.Service}} == nil {
				c.svc.{{.Service}} = {{.Service}}.New(c.svc.session)
			}
			{{ if .HasNoSlice }}
				var opt {{ .Output }}
			{{ else }}
				opt := make({{ .Output }}, 0)
			{{ end }}
			hasNextToken := true
			for hasNextToken {
				o, err := c.svc.{{.Service}}.{{.ServiceEntityFn}}WithContext(ctx, input)
				if err != nil {
					return nil, err
				}
				if o.{{ .RootAttribute }} == nil {
					hasNextToken = false
					continue
				}
				{{ if .HasNotPagination }}
					hasNextToken = false
				{{ else }}
					if input == nil {
						input = &{{.Input}}{}
					}
					input.{{.InputPaginationAttributeFn}} = o.{{.PaginationAttributeFn}}
					hasNextToken = o.{{.PaginationAttributeFn}} != nil
				{{ end }}
				{{ if .IsAttributeListSlice }}
					for _,v := range o.{{ index .AttributeList 0 }} {
						opt = append(opt, v.{{ index .AttributeList 1 }}...)
					}
				{{ else if .HasNoSlice }}
					opt = o.{{ index .AttributeList 0 }}
				{{ else if .IsMap }}
					opt = o.{{ index .AttributeList 0 }}
				{{ else }}
					opt = append(opt, o.{{ index .AttributeList 0 }}...)
				{{ end }}
			}
			return opt, nil
		}
	`
)
var (
	fnTmpl        *template.Template
	pkgTmpl       *template.Template
	awsReaderTmpl *template.Template
)
func init() {
	var err error
	fnTmpl, err = template.New("test").Parse(functionTmpl)
	if err != nil {
		panic(err)
	}
	pkgTmpl, err = template.New("test").Parse(packageTmpl)
	if err != nil {
		panic(err)
	}
	awsReaderTmpl, err = template.New("test").Parse(arTmpl)
	if err != nil {
		panic(err)
	}
}
type Function struct {
	FnName string
	Entity string
	FnAttributeList string
	Prefix string
	Service string
	FnServiceEntity string
	Documentation string
	FnOutput string
	FnSignature string
	NoGenerateFn bool
	FilterByOwner string
	HasNotPagination bool
	HasNoSlice bool
	FnPaginationAttribute string
	FnInputPaginationAttribute string
	SingularEntity string
	IsMap bool
}
func (f Function) Name() string {
	if f.FnName != "" {
		return f.FnName
	}
	prefix := "Get"
	if f.FilterByOwner != "" {
		prefix += "Own"
	}
	return fmt.Sprintf("%s%s", prefix, f.Entity)
}
func (f Function) Output() string {
	var typePrefix = "[]*"
	if f.IsMap {
		typePrefix = "map[string]*"
	}
	if f.HasNoSlice {
		typePrefix = "*"
	}
	if f.FnOutput != "" {
		return fmt.Sprintf("%s%s", typePrefix, f.FnOutput)
	}
	if f.SingularEntity != "" {
		return fmt.Sprintf("%s%s.%s", typePrefix, f.Service, f.SingularEntity)
	}
	return fmt.Sprintf("%s%s.%s", typePrefix, f.Service, inflection.Singular(f.Entity))
}
func (f Function) Input() string {
	return fmt.Sprintf("%s.%sInput", f.Service, f.ServiceEntityFn())
}
func (f Function) Signature() string {
	if f.FnSignature != "" {
		return f.FnSignature
	}
	return fmt.Sprintf("%s (ctx context.Context, input *%s) (%s, error)", f.Name(), f.Input(), f.Output())
}
func (f Function) AttributeList() []string {
	if f.FnAttributeList != "" {
		if f.IsAttributeListSlice() {
			return strings.Split(f.FnAttributeList, "#")
		}
		return []string{f.FnAttributeList}
	}
	return []string{f.Entity}
}