package jdr
import (
//"html/template"
"encoding/xml"
"errors"
"os"
)
type Page struct {
Items []SheetItem
}
type SheetItem interface{
}
type Block struct {
Name string
Items []SheetItem
}
type Variable struct {
Type VariableType
Name string
}
type CharacterSheet struct {
types map[string]VariableType
Pages []*Page
}
func (self *CharacterSheet) AddType(t VariableType) {
if self.types == nil {
self.types = make(map[string]VariableType)
}
name := t.Name()
self.types[name] = t
}
func (self *CharacterSheet) AddDefaultTypes() {
self.AddType(&VariableType_bool{})
self.AddType(&VariableType_int{})
self.AddType(&VariableType_float{})
self.AddType(&VariableType_string{})
self.AddType(&VariableType_d{})
}
func (self *CharacterSheet) getType(typename string) (VariableType, error) {
t, ok := self.types[typename]
if !ok {
return &VariableType_badType{}, errors.New("unknown type \"" + typename + "\"")
}
return t, nil
}
type xmlNode struct {
XMLName xml.Name
Attrs []xml.Attr `xml:"-"`
Content []byte `xml:",innerxml"`
Nodes []xmlNode `xml:",any"`
}
func (n *xmlNode) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
n.Attrs = start.Attr
type node xmlNode
return d.DecodeElement((*node)(n), &start)
}
func parseVariable(root xmlNode, sheet *CharacterSheet) (*Variable, error) {
ret := &Variable{}
typeOk := false
nameOk := false
for i := 0; i < len(root.Attrs); i++ {
attrName := root.Attrs[i].Name.Local
attrVal := root.Attrs[i].Value
switch attrName {
case "type":
t, err := sheet.getType(attrVal)
if err != nil {
return nil, err
}
ret.Type = t
typeOk = true
case "name":
ret.Name = attrVal
nameOk = true
}
}
if !nameOk {
return nil, errors.New("Unnamed variable")
}
if !typeOk {
return nil, errors.New("No type provided for variable \"" + ret.Name + "\"")
}
return ret, nil
}
func parseBlock(root xmlNode, sheet *CharacterSheet) (*Block, error) {
ret := &Block{}
for i := 0; i < len(root.Attrs); i++ {
attrName := root.Attrs[i].Name.Local
attrVal := root.Attrs[i].Value
switch attrName {
case "name":
ret.Name = attrVal
}
}
for i := 0; i < len(root.Nodes); i++ {
item, err := parseItem(root.Nodes[i], sheet)
if err != nil {
return nil, err
}
ret.Items = append(ret.Items, item)
}
return ret, nil
}
func parseItem(root xmlNode, sheet *CharacterSheet) (SheetItem, error) {
switch root.XMLName.Local {
case "block":
return parseBlock(root, sheet)
case "variable":
return parseVariable(root, sheet)
default:
return nil, errors.New("Unknown item: " + root.XMLName.Local)
}
}
func parsePage(root xmlNode, sheet *CharacterSheet) (*Page, error) {
ret := &Page{}
for i := 0; i < len(root.Nodes); i++ {
item, err := parseItem(root.Nodes[i], sheet)
if err != nil {
return nil, err
}
ret.Items = append(ret.Items, item)
}
return ret, nil
}
func parseSheet(root xmlNode) (*CharacterSheet, error) {
if root.XMLName.Local != "jdr-desc" {
return nil, errors.New("Wrong root node")
}
sheet := &CharacterSheet{}
sheet.AddDefaultTypes()
for i := 0; i < len(root.Nodes); i++ {
node := root.Nodes[i]
switch node.XMLName.Local {
case "custom-types":
types, err := parseCustomTypes(node)
if err != nil {
return nil, err
}
for j := 0; j < len(types); j++ {
sheet.AddType(types[j])
}
case "page":
page, err := parsePage(node, sheet)
if err != nil {
return nil, err
}
sheet.Pages = append(sheet.Pages, page)
default:
return nil, errors.New("Wrong format")
}
}
return sheet, nil
}
func ReadCharacterSheet(filename string) (*CharacterSheet, error) {
file, err := os.Open(filename)
if err != nil {
return nil, err
}
defer file.Close()
decoder := xml.NewDecoder(file)
var n xmlNode
err = decoder.Decode(&n)
if err != nil {
return nil, err
}
sheet, err := parseSheet(n)
if err != nil {
return nil, err
}
return sheet, nil
}