package xvdoc import ( "fmt" "strings" ) func constructorFormula(m JSONMap) (res Cell, err error) { if method := m.StringVal("method", ""); len(method) > 0 { var args []CellArg if ai := m.Array("args"); len(ai) > 0 { var arg CellArg args = make([]CellArg, len(ai)) for i, v := range ai { if arg, err = argFromIface(v); err == nil { args[i] = arg } else { return } } } res = &CellFormula{ method: method, args: args, style: m.StringVal("style", ""), styles: m.StringArray("styles"), } } else { err = fmt.Errorf("Formula constructor error: empty method") } return } // CellFormula is cell of formula for excel or other types with formula support type CellFormula struct { method string args []CellArg styles []string style string } // Val is method of getter formula string (Cell interface) func (s *CellFormula) Val() interface{} { return s.method } // Type method is value type getter (formula) func (s *CellFormula) Type() string { return "formula" } func (s *CellFormula) String() string { return fmt.Sprintf("{ formula :: %v, args: [ %v ]}", s.method, s.args) } // ReplaceArgs is replace variable templates ($1, $2, etc) to valus from incoming array func (s *CellFormula) ReplaceArgs(args []string) (res string) { res = s.method for i, arg := range args { res = strings.ReplaceAll(res, fmt.Sprintf("$%v", i+1), arg) } return res } // Style is getter of cell style func (s *CellFormula) Styles() (res []string) { if len(s.styles) > 0 { res = s.styles } else if len(s.style) > 0 { res = []string{s.style} } return } //////////////////////////////////////////// type argType uint8 const ( argTypeValue argType = iota argTypeRow argTypeCell ) func (s argType) String() string { switch s { case argTypeRow: return "row" case argTypeCell: return "cell" default: return "value" } } func argFromIface(i interface{}) (arg CellArg, err error) { if _, check := i.(map[string]interface{}); !check { err = fmt.Errorf("Cell argument parse Error :: object expected") } else { m := JSONMap(i.(map[string]interface{})) switch m.StringVal("type", "") { case "cell": arg.aType = argTypeCell case "row": arg.aType = argTypeRow default: if m.KeyExists("value") { arg.aType = argTypeValue } else { err = fmt.Errorf("Unexpected argument type (type or value field expected)") } } delete(m, "type") arg.data = m } return } // CellArg is argument object of cell type CellArg struct { aType argType data JSONMap } func (s CellArg) String() string { return fmt.Sprintf("{ %v, data: %v }", s.aType, s.data) } // Value is getter of argument value func (s CellArg) Value() interface{} { return s.data["value"] } // Coords calculate real argument coords by current args func (s CellArg) Coords(x, y int) (dx, dy int) { dx, dy = x, y if s.data.KeyExists("x") { dx = int(s.data.Int("x", 0)) } else if s.data.KeyExists("ox") { dx += int(s.data.Int("ox", 0)) } if s.data.KeyExists("y") { dy = int(s.data.Int("y", 0)) } else if s.data.KeyExists("oy") { dy += int(s.data.Int("oy", 0)) } return }