package jdr import( "html/template" "log" "errors" "strings" "strconv" "regexp" "encoding/json" ) var regexp_d = regexp.MustCompile(`^[1-9][0-9]*d([468]|1[02]|20|100)$`) type VariableType interface { Name() string Validate(value string) bool ToHTML(value string) (template.HTML, error) DefaultValue() string } type VariableType_badType struct {} func (*VariableType_badType) Name() string { return "unknown type" } func (*VariableType_badType) Validate(s string) bool { return false } func (*VariableType_badType) ToHTML(value string) (template.HTML, error) { return template.HTML(""), errors.New("unknown type") } func (*VariableType_badType) DefaultValue() string { return "" } type VariableType_bool struct {} func (*VariableType_bool) Name() string { return "bool" } func (*VariableType_bool) ToBool(value string) (bool, error) { switch strings.ToLower(value) { case "true": return true, nil case "false": return false, nil default: return false, errors.New("unknown bool value") } } func (self *VariableType_bool) Validate(value string) bool { _, err := self.ToBool(value) return err == nil } func (self *VariableType_bool) ToHTML(value string) (template.HTML, error) { val, err := self.ToBool(value) if err != nil { return template.HTML(""), err } ret := `` return template.HTML(ret), nil } func (self *VariableType_bool) DefaultValue() string { return "false" } type VariableType_int struct {} func (*VariableType_int) Name() string { return "int" } func (self *VariableType_int) ToInt(value string) (int64, error) { return strconv.ParseInt(value, 10, 64) } func (self *VariableType_int) Validate(value string) bool { _, err := self.ToInt(value) return err == nil } func (self *VariableType_int) ToHTML(value string) (template.HTML, error) { val, err := self.ToInt(value) if err != nil { return template.HTML(""), err } ret := `` return template.HTML(ret), nil } func (self *VariableType_int) DefaultValue() string { return "0" } type VariableType_float struct {} func (*VariableType_float) Name() string { return "float" } func (*VariableType_float) ToFloat(value string) (float64, error) { return strconv.ParseFloat(value, 64) } func (self *VariableType_float) Validate(value string) bool { _, err := self.ToFloat(value) return err == nil } func (self *VariableType_float) ToHTML(value string) (template.HTML, error) { val, err := self.ToFloat(value) if err != nil { return template.HTML(""), err } ret := `` return template.HTML(ret), nil } func (self *VariableType_float) DefaultValue() string { return "0.0" } type VariableType_string struct {} func (*VariableType_string) Name() string { return "string" } func (*VariableType_string) Validate(s string) bool { return true } func (self *VariableType_string) ToHTML(value string) (template.HTML, error) { ret := `` return template.HTML(ret), nil } func (self *VariableType_string) DefaultValue() string { return "" } type VariableType_d struct {} func (*VariableType_d) Name() string { return "d" } func (*VariableType_d) Validate(s string) bool { return regexp_d.MatchString(s) } func (self *VariableType_d) ToHTML(value string) (template.HTML, error) { //FIXME: non-generic version ret := `` return template.HTML(ret), nil } func (self *VariableType_d) DefaultValue() string { //FIXME: non-generic version return "" } func makeVariableType(s string) VariableType { switch(strings.ToLower(s)) { case "bool": return &VariableType_bool{} case "int": return &VariableType_int{} case "float": return &VariableType_float{} case "string": return &VariableType_string{} case "d": return &VariableType_d{} default: log.Println("Unknown type:", s) return &VariableType_badType{} } } type CustomEnum struct { name string BaseType VariableType Values []string } func (self *CustomEnum) Name() string { return self.name } func (self *CustomEnum) ToId(value string) (int, error) { if !self.BaseType.Validate(value) { return 0, errors.New("Invalid value") } for i := 0; i < len(self.Values); i++ { if self.Values[i] == value { return i, nil } } return 0, errors.New("No such element") } func (self *CustomEnum) Validate(value string) bool { _, err := self.ToId(value) return err == nil } func (self *CustomEnum) ToHTML(value string) (template.HTML, error) { selectItem := value != "" value_id := 0 if selectItem { var err error value_id, err = self.ToId(value) if err != nil { return template.HTML(""), err } } ret := `` return template.HTML(ret), nil } func (self *CustomEnum) DefaultValue() string { return "" } type CustomStruct struct { name string Variables []*Variable } func (self *CustomStruct) Name() string { return self.name } func (self *CustomStruct) Validate(s string) bool { var jsonValue map[string]interface{} err := json.Unmarshal([]byte(s), &jsonValue) if err != nil { log.Fatal(err) return false } for _, v := range self.Variables { jsonVal, isString := jsonValue[v.Name()].(string) if !isString || ! v.Type.Validate(jsonVal) { return false } } return true } func (self *CustomStruct) ToHTML(value string) (template.HTML, error) { var jsonValue map[string]interface{} err := json.Unmarshal([]byte(value), &jsonValue) if err != nil { log.Fatal(err) return template.HTML(""), errors.New("Cannot unmarshal JSON") } ret := template.HTML("") ret += `