func hyphenDelimToCamel(s string) string {
	parts := strings.Split(s, "-")
	for i, part := range parts {
		parts[i] = strings.ToUpper(string(part[0])) + part[1:]
	}
	return strings.Join(parts, "")
}
hyphenDelimToCamel will convert names like
list-zones to ListZones, where the hyphen
is removed and the first letter of each word
is properly camel cased. Be aware that abbrvs
like 'ttl' will be transformmed to 'Ttl'.
package definitions
import (
	"bytes"
	"fmt"
	"io/ioutil"
	"strings"
	"text/template"
	"github.com/BurntSushi/toml"
)
const (
	goTemplate = `
package cmd
var (
{{ .Variables }}
)
func init() {
{{ .Commands }}
}
func Run(cmd *cobra.Command, args []string, name string, api *cloudflare.API) (resp interface{}, err error) {
  {{ .SwitchList }}
  return
}
`
	switchTemplate = `switch name {
  {{ range . }}
  case "{{.Name}}":
    resp, err = {{.Name}}(api, {{.ArgList}}){{ end }}
  default:
    break
}`
	varTemplate = `{{ range .}}{{ .Name }} {{ .Type }}
{{ end }}`
	cmdTemplate = `var {{.VariableName}} = &cobra.Command{
  Use:   "{{- .Name -}}",
  Short: "{{- .ShortDescription -}}",
  Long: ` + "`" + `{{- .Description -}}` + "`" + `,
{{ if .V4APIName}}Run: func(cmd *cobra.Command, args []string) {
    Main(cmd, args, "{{- .V4APIName}}")
  },{{ end}}
}
{{- $varName := .VariableName }}
{{range .Subcommands}}{{$varName}}.AddCommand({{.}})
{{end}}
{{ if .TopLevel }}RootCmd.AddCommand({{.VariableName}})
{{ end }}
{{range .Option}}
  {{$varName}}.Flags().{{.TypeCap}}Var(&{{.ArgName}}, "{{.Name}}", {{.Default}}, "{{.Description}}")
  {{if .Required}}{{$varName}}.MarkFlagRequired("{{.Name}}")
{{end}}
{{end}}
`
)
var (
	declaredVariables = make(map[string]bool)
)
type Option struct {
	Name        string
	Type        string
	Description string
	Required    bool
}
type OptionTemplateValue struct {
	TypeCap     string
	ArgName     string
	Name        string
	Default     string
	Description string
	Required    bool
}
type SwitchTemplateEntry struct {
	Name    string
	ArgList string
}
type Command struct {
	Name             string
	Description      string
	ShortDescription string
	V4APIName        string
	Option           []Option
	Subcommands      []string
	TopLevel         bool
}
type CommandTemplateValues struct {
	Name             string
	VariableName     string
	V4APIName        string
	Description      string
	ShortDescription string
	Option           []OptionTemplateValue
	Subcommands []string
	TopLevel    bool
}
type FileTemplateValues struct {
	Commands   string
	Variables  string
	SwitchList string
}
func fileText(commands, variables, switchList string) (string, error) {
	var (
		buff bytes.Buffer
	)
	tmpl, err := template.New("gofile").Parse(goTemplate)
	if err != nil {
		return "", err
	}
	err = tmpl.Execute(&buff, &FileTemplateValues{
		Commands:   commands,
		Variables:  variables,
		SwitchList: switchList,
	})
	if err != nil {
		return "", err
	}
	return buff.String(), nil
}
func (o Option) ToOptionTemplateValue() OptionTemplateValue {
	defaultType := "\"\""
	if o.Type == "int" {
		defaultType = "0"
	} else if o.Type == "bool" {
		defaultType = "false"
	}
	return OptionTemplateValue{
		TypeCap:     hyphenDelimToCamel(o.Type),
		ArgName:     hyphenDelimToCamel(o.Name),
		Name:        o.Name,
		Default:     defaultType,
		Description: o.Description,
		Required:    o.Required,
	}
}
func ToSwitch(cmds []*Command) (string, error) {
	var (
		switchList []SwitchTemplateEntry
		buff       bytes.Buffer
	)
	for _, cmd := range cmds {
		if cmd.V4APIName == "" {
			continue
		}
		argList := cmd.ToArgList()
		switchList = append(switchList, SwitchTemplateEntry{
			Name:    cmd.V4APIName,
			ArgList: argList,
		})
	}
	tmpl, err := template.New("switch").Parse(switchTemplate)
	if err != nil {
		return "", err
	}
	err = tmpl.Execute(&buff, switchList)
	if err != nil {
		return "", err
	}
	return buff.String(), nil
}
func (c *Command) ToVariables() (string, error) {
	var (
		buff    bytes.Buffer
		options []Option
	)
	for _, opt := range c.Option {
		if _, ok := declaredVariables[opt.Name]; ok {
			continue
		}
		options = append(options, Option{
			Name: hyphenDelimToCamel(opt.Name),
			Type: opt.Type,
		})
		declaredVariables[opt.Name] = true
	}
	tmpl, err := template.New("option").Parse(varTemplate)
	if err != nil {
		return "", err
	}
	err = tmpl.Execute(&buff, options)
	if err != nil {
		return "", err
	}
	return buff.String(), nil
}
func (c *Command) ToGo() (string, error) {
	var (
		buff               bytes.Buffer
		subcommandVarNames []string
	)
	for _, subcmd := range c.Subcommands {
		subcommandVarNames = append(subcommandVarNames, hyphenDelimToCamel(subcmd))
	}
	var optionTemplateValueList []OptionTemplateValue
	for _, opt := range c.Option {
		optionTemplateValueList = append(optionTemplateValueList, opt.ToOptionTemplateValue())
	}
	tmpl, err := template.New("command").Parse(cmdTemplate)
	if err != nil {
		return "", err
	}
	err = tmpl.Execute(&buff, &CommandTemplateValues{
		Name:             c.Name,
		TopLevel:         c.TopLevel,
		Subcommands:      subcommandVarNames,
		VariableName:     hyphenDelimToCamel(c.Name),
		V4APIName:        c.V4APIName,
		ShortDescription: c.ShortDescription,
		Description:      c.Description,
		Option:           optionTemplateValueList,
	})
	if err != nil {
		return "", err
	}
	return buff.String(), nil
}
func LoadDefinitions(fname string) ([]*Command, error) {
	c := map[string][]*Command{}
	_, err := toml.DecodeFile(fname, &c)
	if err != nil {
		return nil, err
	}
	return c["command"], nil
}