using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Linq;

public static class SymbolParser
{
    public static List<TypeBase> ParseTypeList(string filePath)
    {
        XmlDocument doc = new XmlDocument();
        doc.Load(filePath);
        // 1. 动态获取命名空间
        string namespaceUri = doc.DocumentElement?.NamespaceURI ?? "";
        // 2. 创建命名空间管理器
        XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
        nsmgr.AddNamespace("ns", namespaceUri);

        var typeList = doc.SelectNodes("//ns:TypeList/*", nsmgr);
        if (typeList == null)
        {
            throw new Exception("无法找到 TypeList 节点，请检查XML结构或命名空间。");
        }
        List<TypeBase> types = new List<TypeBase>();

        // 解析类型定义
        foreach (XmlNode typeNode in typeList)
        {
           var type= ParseTypeDefinition(typeNode, nsmgr);
            if(type!=null) 
            { types.Add(type); }
        }
        return types;
    }
    private static TypeBase ParseTypeDefinition(XmlNode node, XmlNamespaceManager nsmgr)
    {
        string typeName = GetAttribute(node, "name");
        if (typeName == null)
            return null;

        switch (node.Name)
        {
            case "TypeSimple":
                var typeSimple = new TypeSimple()
                {
                    Name = GetAttribute(node, "name"),
                    Size = int.Parse(GetAttribute(node, "size")),
                    SwapSize = int.Parse(GetAttribute(node, "swapsize")),
                    TypeClass = GetAttribute(node, "typeclass"),
                    IecName = GetAttribute(node, "iecname"),
                    BitOffset = int.Parse(string.IsNullOrEmpty(GetAttribute(node, "bitoffset")) ? "0" : GetAttribute(node, "bitoffset"))
                };
                return typeSimple;
            case "TypeArray":
                var typeArray = new TypeArray()
                {
                    Name = GetAttribute(node, "name"),
                    Size = int.Parse(GetAttribute(node, "size")),
                    NativeSize = int.Parse(GetAttribute(node, "nativesize")),
                    TypeClass = GetAttribute(node, "typeclass"),
                    IecName = GetAttribute(node, "iecname"),
                    BaseType = GetAttribute(node, "basetype")
                };
                var dimensions = GetArrayDimensions(node, nsmgr);
                typeArray.Rank = dimensions.Count;
                if (typeArray.Rank > 0)
                {
                    typeArray.MinRange = new int[typeArray.Rank];
                    typeArray.MaxRange = new int[typeArray.Rank];
                    for (int i = 0; i < typeArray.Rank; i++)
                    {
                        typeArray.MinRange[i] = dimensions[i].Min;
                        typeArray.MaxRange[i] = dimensions[i].Max;
                    }
                }
                return typeArray;
            case "TypeUserDef":
                var typeUserDef = new TypeUserDef()
                {
                    Name = GetAttribute(node, "name"),
                    Size = int.Parse(GetAttribute(node, "size")),
                    NativeSize = int.Parse(GetAttribute(node, "nativesize")),
                    TypeClass = GetAttribute(node, "typeclass"),
                    PouClass = GetAttribute(node, "pouclass"),
                    IecName = GetAttribute(node, "iecname"),
                };

                typeUserDef.UserDefElements = GetUserDefElement(node, nsmgr);
                return typeUserDef;
            default:
                return null;
        }
    }
    public static List<(int Min, int Max)> GetArrayDimensions(XmlNode arrayNode, XmlNamespaceManager nsmgr)
    {
        var result = new List<(int Min, int Max)>();

        XmlNodeList dimNodes = arrayNode.SelectNodes("ns:ArrayDim", nsmgr);
        if (dimNodes == null) return result;

        foreach (XmlNode dim in dimNodes)
        {
            if (int.TryParse(dim.Attributes["minrange"]?.Value, out int min) &&
                int.TryParse(dim.Attributes["maxrange"]?.Value, out int max))
            {
                result.Add((min, max));
            }
        }
        return result;
    }
    public static List<UserDefElement> GetUserDefElement(XmlNode arrayNode, XmlNamespaceManager nsmgr)
    {
        var result = new List<UserDefElement>();
        XmlNodeList dimNodes = arrayNode.SelectNodes("ns:UserDefElement", nsmgr);
        if (dimNodes == null) return result;

        foreach (XmlNode dim in dimNodes)
        {
            var element = new UserDefElement
            {
                IecName = dim.Attributes["iecname"]?.Value,
                Type = dim.Attributes["type"].Value,
                //ByteOffset = uint.Parse(dim.Attributes["byteoffset"]?.Value),
                VarType = dim.Attributes["vartype"]?.Value,
                Access = dim.Attributes["access"]?.Value
            };
            //if(element.Type!=GetAttribute(arrayNode, "name"))//如果一个类型的name和子类型的type相同，则不能添加进去，否则在添加Node时会出现一直递归，堆栈溢出
                result.Add(element);
        }
        return result;
    }

    public static XmlVariable ParseNode(string filePath, List<TypeBase> types)
    {
        XmlDocument doc = new XmlDocument();
        doc.Load(filePath);
        // 1. 动态获取命名空间
        string namespaceUri = doc.DocumentElement?.NamespaceURI ?? "";
        // 2. 创建命名空间管理器
        XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
        //nsmgr.AddNamespace("ns", "http://www.3s-software.com/schemas/Symbolconfiguration.xsd");
        nsmgr.AddNamespace("ns", namespaceUri);
        // 使用命名空间前缀进行查询
        XmlNode rootNode = doc.SelectSingleNode("//ns:NodeList/ns:Node", nsmgr);
        if (rootNode == null)
        {
            throw new Exception("无法找到 NodeList/Node 节点，请检查XML结构或命名空间。");
        }
        //var varNode= ParseNode(rootNode);
        var varNode= ParseAllElementNode(rootNode, nsmgr, types);
        return varNode;
    }
    private static XmlVariable ParseAllElementNode(XmlNode xmlNode, XmlNamespaceManager nsmgr, List<TypeBase> types)
    {
        var varNode = GetNodeValue(xmlNode, nsmgr);
        if (!varNode.IsLeaf)
        {
            foreach (XmlNode xmlChild in xmlNode.ChildNodes)
            {
                if (xmlChild.Name == "Node")
                {
                    string strXmlChildNodeType = GetAttribute(xmlChild, "type");

                    if (string.IsNullOrEmpty(strXmlChildNodeType))//不是具体的数据，有子Node
                        varNode.Children.Add(ParseAllElementNode(xmlChild, nsmgr, types));

                    else
                    {
                        var xmlChildNodeType = types.First(t => t.Name == strXmlChildNodeType);//找到具体是之前搜索到的具体哪个类型

                        if (xmlChildNodeType is TypeSimple)//简单数据类型，直接添加
                        {
                            var subNode = GetNodeValue(xmlChild, nsmgr);
                            varNode.Children.Add(subNode);
                        }
                        else if (xmlChildNodeType is TypeArray typeArray)//数组类型
                        {
                            var subNode = GetNodeValue(xmlChild, nsmgr);
                            subNode.IsLeaf = false;

                            varNode.Children.Add(subNode);//添加数组名本身，然后再添加其下面的元素


                            int count = 1;
                            for (int i = 0; i < typeArray.Rank; i++)
                            {
                                count *= (typeArray.MaxRange[i] + 1 - typeArray.MinRange[i]);
                            }
                            int[] cIndex = new int[typeArray.Rank];

                            for (int i = 0; i < count; i++)
                            {
                                string name = IndicesToString(GetNDElement(typeArray.Rank, typeArray.MinRange, typeArray.MaxRange, i));
                                subNode.Children.Add(ParseArrayAndUserDefElement(name, typeArray.BaseType, types));
                            }
                        }
                        else if (xmlChildNodeType is TypeUserDef typeUserDef)//结构体类型
                        {
                            var subNode = GetNodeValue(xmlChild, nsmgr);
                            subNode.IsLeaf = false;
                            varNode.Children.Add(subNode);//添加结构体名本身，然后再添加其下面的元素

                            foreach (var userDefElement in typeUserDef.UserDefElements)
                            {
                                subNode.Children.Add(ParseArrayAndUserDefElement(userDefElement.IecName, userDefElement.Type, types));
                            }
                        }
                    }
                }
            }
        }
        return varNode;
    }
    private static int[] GetNDElement(int N, int[] MinRange, int[] MaxRange, int linearIndex)
    {
        // 1. 计算每个维度的长度
        int[] lengths = new int[N];
        for (int i = 0; i < N; i++)
        {
            lengths[i] = MaxRange[i] - MinRange[i] + 1;
        }

        int totalElements = 1;
        for (int i = 0; i < N; i++)
        {
            totalElements *= lengths[i];
        }

        if (linearIndex < 0 || linearIndex >= totalElements)
        {
            throw new IndexOutOfRangeException("线性索引超出数组范围");
        }

        // 2. 计算每个维度的步长（Stride）
        int[] strides = new int[N];
        strides[N - 1] = 1;
        for (int i = N - 2; i >= 0; i--)
        {
            strides[i] = strides[i + 1] * lengths[i + 1];
        }

        // 3. 还原每个维度的索引（加上偏移 MinRange[i]）
        int[] result = new int[N];
        for (int i = 0; i < N; i++)
        {
            int index = (linearIndex / strides[i]) % lengths[i];
            result[i] = MinRange[i] + index;
        }

        return result;
    }

    private static string IndicesToString(int[] indices)
    {
        if (indices == null || indices.Length == 0)
            return "[]";

        return "[" + string.Join(",", indices) + "]";
    }

    private static XmlVariable ParseArrayAndUserDefElement(string name, string baseType, List<TypeBase> types)
    {
        var type = types.First(t => t.Name == baseType);//找到数组的基本类型是哪种类型（也即素组的元素是什么类型）

        if (type is TypeSimple typeSimple)//简单数据类型，直接添加
        {
            var subNode = new XmlVariable()
            {
                Name = name,
                Type = typeSimple.Name,
                IsLeaf = true,
            };
            return subNode;
        }
        else if (type is TypeArray typeArray)
        {
            var subNode = new XmlVariable();
            subNode.Name = name;

            int count = 1;
            for (int i = 0; i < typeArray.Rank; i++)
            {
                count *= (typeArray.MaxRange[i] + 1 - typeArray.MinRange[i]);
            }
            int[] cIndex = new int[typeArray.Rank];

            for (int i = 0; i < count; i++)
            {
                string n = IndicesToString(GetNDElement(typeArray.Rank, typeArray.MinRange, typeArray.MaxRange, i));
                subNode.Children.Add(ParseArrayAndUserDefElement(n, typeArray.BaseType, types));
            }
            return subNode;//添加数组名本身
        }
        else if (type is TypeUserDef typeUserDef)//结构体类型
        {
            
            var subNode = new XmlVariable();
            subNode.Name = name;

            foreach (var userDefElement in typeUserDef.UserDefElements)
            {
                subNode.Children.Add(ParseArrayAndUserDefElement(userDefElement.IecName, userDefElement.Type, types));
            }
            return subNode;
        }
        return null;
    }
    static XmlVariable GetNodeValue(XmlNode xmlNode, XmlNamespaceManager nsmgr)
    {
        var node = new XmlVariable
        {
            Name = GetAttribute(xmlNode, "name"),
            Type = GetAttribute(xmlNode, "type"),
            Access = GetAttribute(xmlNode, "access"),
            Comment= xmlNode.SelectSingleNode("ns:Comment", nsmgr)?.InnerText.Trim() ?? null,
            IsLeaf = xmlNode.SelectNodes("ns:Node", nsmgr).Count == 0
        };
        return node;
    }

    private static string GetAttribute(XmlNode node, string attrName)
    {
        XmlAttribute attr = node.Attributes?[attrName];
        return attr?.Value ?? string.Empty;
    }


}