package gff

import "fmt"

type FieldType uint32

const (
	TypeByte FieldType = iota
	TypeChar
	TypeWord
	TypeShort
	TypeDWord
	TypeInt
	TypeDWord64
	TypeInt64
	TypeFloat
	TypeDouble
	TypeCExoString
	TypeResRef
	TypeCExoLocString
	TypeVoid
	TypeStruct
	TypeList
	TypeOrientation
	TypeVector
)

var fieldTypeNames = map[FieldType]string{
	TypeByte:          "Byte",
	TypeChar:          "Char",
	TypeWord:          "Word",
	TypeShort:         "Short",
	TypeDWord:         "DWord",
	TypeInt:           "Int",
	TypeDWord64:       "DWord64",
	TypeInt64:         "Int64",
	TypeFloat:         "Float",
	TypeDouble:        "Double",
	TypeCExoString:    "CExoString",
	TypeResRef:        "ResRef",
	TypeCExoLocString: "CExoLocString",
	TypeVoid:          "Void",
	TypeStruct:        "Struct",
	TypeList:          "List",
	TypeOrientation:   "Orientation",
	TypeVector:        "Vector",
}

type Document struct {
	FileType    string `json:"file_type"`
	FileVersion string `json:"file_version"`
	Root        Struct `json:"root"`
}

type Struct struct {
	Type   uint32  `json:"struct_type"`
	Fields []Field `json:"fields"`
}

type Field struct {
	Label string    `json:"label"`
	Type  FieldType `json:"-"`
	Value Value     `json:"-"`
}

type Value interface {
	fieldType() FieldType
}

type LocString struct {
	StringRef uint32           `json:"string_ref"`
	Entries   []LocStringEntry `json:"entries"`
}

type LocStringEntry struct {
	ID    uint32 `json:"id"`
	Value string `json:"value"`
}

type Vector struct {
	X float32 `json:"x"`
	Y float32 `json:"y"`
	Z float32 `json:"z"`
}

type Orientation struct {
	X float32 `json:"x"`
	Y float32 `json:"y"`
	Z float32 `json:"z"`
	W float32 `json:"w"`
}

type ByteValue uint8
type CharValue int8
type WordValue uint16
type ShortValue int16
type DWordValue uint32
type IntValue int32
type DWord64Value uint64
type Int64Value int64
type FloatValue float32
type DoubleValue float64
type StringValue string
type ResRefValue string
type VoidValue []byte
type ListValue []Struct

func (ByteValue) fieldType() FieldType    { return TypeByte }
func (CharValue) fieldType() FieldType    { return TypeChar }
func (WordValue) fieldType() FieldType    { return TypeWord }
func (ShortValue) fieldType() FieldType   { return TypeShort }
func (DWordValue) fieldType() FieldType   { return TypeDWord }
func (IntValue) fieldType() FieldType     { return TypeInt }
func (DWord64Value) fieldType() FieldType { return TypeDWord64 }
func (Int64Value) fieldType() FieldType   { return TypeInt64 }
func (FloatValue) fieldType() FieldType   { return TypeFloat }
func (DoubleValue) fieldType() FieldType  { return TypeDouble }
func (StringValue) fieldType() FieldType  { return TypeCExoString }
func (ResRefValue) fieldType() FieldType  { return TypeResRef }
func (LocString) fieldType() FieldType    { return TypeCExoLocString }
func (VoidValue) fieldType() FieldType    { return TypeVoid }
func (Struct) fieldType() FieldType       { return TypeStruct }
func (ListValue) fieldType() FieldType    { return TypeList }
func (Orientation) fieldType() FieldType  { return TypeOrientation }
func (Vector) fieldType() FieldType       { return TypeVector }

func (t FieldType) String() string {
	if name, ok := fieldTypeNames[t]; ok {
		return name
	}
	return fmt.Sprintf("FieldType(%d)", t)
}

func NewField(label string, value Value) Field {
	return Field{
		Label: label,
		Type:  value.fieldType(),
		Value: value,
	}
}
