func (f *Form) GenChoices(lenType interface{}, fnType interface{}) interface{} {
	return GenChoices(lenType, fnType)
}
GenChoices generate choices
type Data struct{
ID string
Name string
}
data:=[]*Data{
&Data{ID:"a",Name:"One"},
&Data{ID:"b",Name:"Two"},
}
GenChoices(len(data), func(index int) (string, string, bool){
return data[index].ID,data[index].Name,false
})
or
GenChoices(map[string]int{
"":len(data),
}, func(group string,index int) (string, string, bool){
return data[index].ID,data[index].Name,false
})
package forms
import (
	"bytes"
	"fmt"
	"html/template"
	"net/url"
	"reflect"
	"strconv"
	"strings"
	"github.com/coscms/forms/common"
	"github.com/coscms/forms/config"
	"github.com/coscms/forms/fields"
	"github.com/webx-top/validation"
)
const (
	POST = "POST"
	GET  = "GET"
)
func NewWithConfig(c *config.Config, args ...interface{}) *Form {
	form := New()
	form.Init(c, args...)
	return form
}
func NewWithConfigFile(m interface{}, configJSONFile string) *Form {
	config, err := UnmarshalFile(configJSONFile)
	if err != nil {
		panic(err)
	}
	return NewWithModelConfig(m, config)
}
func New() *Form {
	return &Form{
		FieldList:             []config.FormElement{},
		fieldMap:              make(map[string]int),
		containerMap:          make(map[string]string),
		Theme:                 common.BASE,
		Class:                 common.HTMLAttrValues{},
		ID:                    "",
		Params:                map[string]string{},
		CSS:                   map[string]string{},
		Method:                POST,
		AppendData:            map[string]interface{}{},
		labelFn:               func(s string) string { return s },
		validTagFn:            Html5Validate,
		beforeRender:          []func(){},
		omitOrMustFieldsValue: map[string]bool{},
	}
}
func NewFromModel(m interface{}, c *config.Config) *Form {
	form := NewWithConfig(c, m)
	form.SetModel(m)
	form.ParseModel(m)
	return form
}
type Form struct {
	AppendData map[string]interface{} `json:"appendData,omitempty" xml:"appendData,omitempty"`
	Model      interface{}            `json:"model" xml:"model"`
	FieldList  []config.FormElement   `json:"fieldList" xml:"fieldList"`
	Theme      string                 `json:"theme" xml:"theme"`
	Class      common.HTMLAttrValues  `json:"class" xml:"class"`
	ID         string                 `json:"id" xml:"id"`
	Params     map[string]string      `json:"params" xml:"params"`
	CSS        map[string]string      `json:"css" xml:"css"`
	Method     string                 `json:"method" xml:"method"`
	Action     template.HTML          `json:"action" xml:"action"`
	omitOrMustFieldsValue map[string]bool  
	omitAllFieldsValue    bool
	fieldMap              map[string]int
	containerMap          map[string]string
	ignoreValid           []string
	valid                 *validation.Validation
	labelFn               func(string) string
	validTagFn            func(string, fields.FieldInterface)
	config                *config.Config
	beforeRender          []func()
	debug                 bool
	data                  map[string]interface{}
}
func (f *Form) Debug(args ...bool) *Form {
	if len(args) > 0 {
		f.debug = args[0]
	} else {
		f.debug = true
	}
	return f
}
func (f *Form) Config() *config.Config {
	return f.config
}
func (f *Form) IsDebug() bool {
	return f.debug
}
func (f *Form) Must(fields ...string) *Form {
	for _, field := range fields {
		f.omitOrMustFieldsValue[field] = true
	}
	return f
}
func (f *Form) ResetOmitOrMust() *Form {
	f.omitOrMustFieldsValue = map[string]bool{}
	return f
}
func (f *Form) Omit(fields ...string) *Form {
	for _, field := range fields {
		f.omitOrMustFieldsValue[field] = false
	}
	return f
}
func (f *Form) OmitAll(on ...bool) *Form {
	if len(on) > 0 {
		f.omitAllFieldsValue = on[0]
	} else {
		f.omitAllFieldsValue = true
	}
	return f
}
func (f *Form) IsOmit(fieldName string) (omitFieldValue bool) {
	if f.omitAllFieldsValue {
		omit, ok := f.omitOrMustFieldsValue[fieldName]
		if !ok || omit {
			omitFieldValue = true
		}
	} else {
		omit, ok := f.omitOrMustFieldsValue[fieldName]
		if ok && omit {
			omitFieldValue = true
		}
	}
	return
}
func (f *Form) SetLabelFunc(fn func(string) string) *Form {
	f.labelFn = fn
	return f
}
func (f *Form) SetValidTagFunc(fn func(string, fields.FieldInterface)) *Form {
	f.validTagFn = fn
	return f
}
func (f *Form) LabelFunc() func(string) string {
	return f.labelFn
}
func (f *Form) ValidTagFunc() func(string, fields.FieldInterface) {
	return f.validTagFn
}
func (f *Form) Init(c *config.Config, model ...interface{}) *Form {
	if c == nil {
		c = &config.Config{}
	}
	f.config = c
	if len(c.Theme) == 0 {
		c.Theme = common.BASE
	}
	f.Theme = c.Theme
	f.Method = c.Method
	f.Action = template.HTML(c.Action)
	if len(model) > 0 {
		f.Model = model[0]
	}
	return f
}
func (f *Form) HTMLTemplate() (*template.Template, error) {
	var tmpl string
	if f.config != nil {
		tmpl = f.config.Template
	}
	if len(tmpl) == 0 {
		tmpl = common.TmplDir(f.Theme) + `/baseform.html`
	}
	return common.GetOrSetCachedTemplate(tmpl, func() (*template.Template, error) {
		return common.ParseFiles(common.LookupPath(tmpl))
	})
}
func (f *Form) Valid(onlyCheckFields ...string) error {
	if f.Model == nil {
		return nil
	}
	passed, err := f.Validate().Valid(f.Model, onlyCheckFields...)
	if err != nil {
		return err
	}
	if !passed {  
		for index, validErr := range f.Validate().Errors {
			if index == 0 {
				err = validErr
			}
			f.Field(validErr.Field).AddError(f.labelFn(validErr.Message))
		}
	}
	return err
}
func (f *Form) InsertErrors() *Form {
	if f.valid != nil && f.valid.HasError() {
		for _, err := range f.valid.Errors {
			f.Field(err.Field).AddError(f.labelFn(err.Message))
		}
	}
	return f
}
func (f *Form) Error() (err *validation.ValidationError) {
	if f.valid != nil && f.valid.HasError() {
		err = f.valid.Errors[0]
	}
	return
}
func (f *Form) Errors() (errs []*validation.ValidationError) {
	if f.valid != nil && f.valid.HasError() {
		errs = f.valid.Errors
	}
	return
}
func (f *Form) HasError() bool {
	return f.valid != nil && f.valid.HasError()
}
func (f *Form) HasErrors() bool {
	return f.valid != nil && f.valid.HasErrors()
}
func (f *Form) AddBeforeRender(fn func()) *Form {
	if fn == nil {
		return f
	}
	f.beforeRender = append(f.beforeRender, fn)
	return f
}
func (f *Form) Validate() *validation.Validation {
	if f.valid == nil {
		f.valid = &validation.Validation{}
	}
	return f.valid
}
func (f *Form) SetModel(m interface{}) *Form {
	f.Model = m
	return f
}
func (f *Form) ParseModel(model ...interface{}) *Form {
	var m interface{}
	if len(model) > 0 {
		m = model[0]
	}
	if m == nil {
		m = f.Model
	}
	flist, fsort := f.unWindStructure(m, ``)
	for _, v := range flist {
		f.Elements(v.(config.FormElement))
	}
	if len(fsort) > 0 {
		f.Sort(fsort)
	}
	return f
}
func (f *Form) AddButton(tmpl string, args ...string) *Form {
	btnFields := make([]fields.FieldInterface, 0)
	if len(args) < 1 {
		btnFields = append(btnFields, fields.SubmitButton("submit", f.labelFn("Submit")))
		btnFields = append(btnFields, fields.ResetButton("reset", f.labelFn("Reset")))
	} else {
		for _, field := range args {
			switch field {
			case `submit`:
				btnFields = append(btnFields, fields.SubmitButton("submit", f.labelFn("Submit")))
			case `reset`:
				btnFields = append(btnFields, fields.ResetButton("reset", f.labelFn("Reset")))
			default:
				btnFields = append(btnFields, fields.Button(field, f.labelFn(strings.Title(field))))
			}
		}
	}
	if len(tmpl) == 0 {
		tmpl = `fieldset_buttons`
	}
	f.Elements(f.NewFieldSet("_button_group", "", btnFields...).SetTemplate(tmpl))
	return f
}
func (f *Form) GenChoicesForField(name string, lenType interface{}, fnType interface{}) *Form {
	f.Field(name).SetChoices(f.GenChoices(lenType, fnType))
	return f
}