package modbus

import (
	"fmt"

	"golib/v2/gnet"
)

type Enum struct {
	No    uint16 `xml:"No,attr"`
	Label string `xml:"Label,attr"`
	Key   string `xml:"Key,attr"`
	Tag   string `xml:"Tag,attr"`
}

type Register struct {
	No    uint16 `xml:"No,attr"`     // No 起始位置, 请输入 10 进制的数字
	Label string `xml:"Label,attr"`  // Label 中文标签
	Len   uint16 `xml:"RetLen,attr"` // Len 数据长度, 即 No 包含的数据长度. 根据长度自动变换 8(1)/16(2)/32(4)/64(8) 位解析
	Type  string `xml:"Type,attr"`   // Type 数据类型, 见下方数据类型
	Key   string `xml:"Key,attr"`    // Key 字段, 用于转换成 map 时
	Bit   bool   `xml:"Bit,attr"`    // Bit 用于将读取的数据逐帧解析到 Key 当中, 当 Bit 为 true 时必须配置 Enums
	Tag   string `xml:"Tag,attr"`
	Enum  []Enum `xml:"Enums>Enum"`
}

type Page struct {
	Order    string     `xml:"Order,attr"`
	Code     uint8      `xml:"Code,attr"`          // Code 功能码
	Register []Register `xml:"Registers>Register"` // Register 已注册需要解析的数据列表
	codeMap  map[uint16]Register
	keyMap   map[string]Register
}

func (p *Page) HasNo(no uint16) (Register, bool) {
	reg, ok := p.codeMap[no]
	if !ok {
		return Register{}, false
	}
	return reg, true
}

func (p *Page) HasKey(key string) (Register, bool) {
	reg, ok := p.keyMap[key]
	if !ok {
		return Register{}, false
	}
	return reg, true
}

func (p *Page) Tag(tag string) []string {
	k := make([]string, 0)
	for _, reg := range p.Register {
		if reg.Tag == tag {
			k = append(k, reg.Tag)
		} else {
			if !reg.Bit {
				continue
			}
			for _, enum := range reg.Enum {
				if enum.Tag == tag {
					k = append(k, reg.Tag)
				}
			}
		}
	}
	return k
}

// Parse  使用当前 Page 解析数据到 valueMap. 其中 b 是数据包, no 是起始地址; len 寄存器数量
// 即从 no 开始解析 len 个寄存器, 并根据配置将其保存在 valueMap 内
func (p *Page) Parse(b []byte, no, len uint16, valueMap map[string]any) {
	for i := uint16(0); i < len; i++ {
		r := no + i
		if reg, ok := p.codeMap[r]; ok {
			bs := b[i*2 : i*2+reg.Len]
			var order gnet.BinaryOrder
			switch p.Order {
			case "big":
				order = gnet.BigEndian
			case "little":
				order = gnet.LittleEndian
			default:
				continue
			}
			if reg.Bit {
				parseBit(order, reg, bs, valueMap)
			} else {
				valueMap[reg.Key] = parseByteValue(order, reg, bs)
			}
		}
	}
}

type ItemInfo struct {
	Name  string // Name 页面名称
	Pages []Page `xml:"Pages>Page"`
}

func (i *ItemInfo) Page(funcCode uint8) *Page {
	for _, p := range i.Pages {
		if p.Code == funcCode {
			return &p
		}
	}
	return &Page{}
}

func (i *ItemInfo) Init() {
	for pi, page := range i.Pages {

		page.codeMap = make(map[uint16]Register)
		page.keyMap = make(map[string]Register)

		for _, reg := range page.Register {
			str := fmt.Sprintf("itemName: %s, Page: %d, No.: %d: ", i.Name, pi, reg.No)
			if reg.Bit && len(reg.Enum) == 0 {
				panic(str + "Bit == true but Enum == 0")
			}
			switch reg.Type {
			case TypeUInt, TypeInt, TypeFloat, TypeBool:
				break
			default:
				panic(str + "unknown Type: " + reg.Type)
			}
			if !reg.Bit && reg.Key == "" {
				panic(str + "Key == empty")
			}
			if _, ok := page.codeMap[reg.No]; ok {
				panic(str + "duplicate No.")
			}
			page.codeMap[reg.No] = reg
			if _, ok := page.keyMap[reg.Key]; ok {
				panic(str + "duplicate Key")
			}
			page.keyMap[reg.Key] = reg
		}

		i.Pages[pi] = page
	}
}

// 数据类型
const (
	TypeUInt  = "uint"  // TypeInt 数字类型.
	TypeInt   = "int"   // TypeInt 数字类型.
	TypeFloat = "float" // TypeFloat 小数类型
	TypeBool  = "bool"  // TypeBool 布尔类型
)
