using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace ZLGCANFD
{
    public class ZLG_Msg
    {
        public int msg_type { get; set; }
        public uint msg_id { get; set; }
        public double msg_cyclic { get; set; }
        public byte msg_dlc { get; set; }
        public string msg_name { get; set; }
        public List<ZDBC.DBCSignal> signals { get; set; } = new List<ZDBC.DBCSignal>();
        public string[] signal_Name { get; set; }

        // 适配 ZLG 的 CANFD 帧结构 (来自 2.txt)
        public CAN.ZCAN_CANFD_FRAME ACANFD;
    }

    public class DBCParse
    {
        // 存储多通道的消息数据库
        public static List<List<ZLG_Msg>> MsgDatabase { get; set; } =
            Enumerable.Range(0, 12).Select(_ => new List<ZLG_Msg>()).ToList();

        /// <summary>
        /// ZLG 专用解析逻辑：遍历 ZDBC 内部的消息链表并填充到 MsgDatabase
        /// </summary>
        /// <param name="hDBC">ZDBC_Init 返回的句柄</param>
        /// <param name="channel">目标通道索引</param>
        public static void Parse(uint hDBC, int channel)
        {
            if (hDBC == ZDBC.INVALID_DBC_HANDLE) return;

            // 1. 初始化指针空间
            int msgSize = Marshal.SizeOf(typeof(ZDBC.DBCMessage));
            nint pMsg = Marshal.AllocHGlobal(msgSize);

            try
            {
                // 清空当前通道旧数据
                MsgDatabase[channel].Clear();

                // 2. 迭代获取所有消息
                bool hasMessage = ZDBC.ZDBC_GetFirstMessage(hDBC, pMsg);
                while (hasMessage)
                {
                    ZDBC.DBCMessage dbMsg = Marshal.PtrToStructure<ZDBC.DBCMessage>(pMsg);

                    ZLG_Msg temp = new ZLG_Msg();
                    temp.msg_id = dbMsg.nID;
                    temp.msg_name = Encoding.Default.GetString(dbMsg.strName).TrimEnd('\0');
                    temp.msg_dlc = (byte)dbMsg.nSize;
                    temp.msg_cyclic = dbMsg.nCycleTime;
                    temp.msg_type = dbMsg.nExtend; // 0-标准帧, 1-扩展帧

                    // 3. 处理信号
                    int sigCount = (int)dbMsg.nSignalCount;
                    temp.signal_Name = new string[sigCount];
                    for (int i = 0; i < sigCount; i++)
                    {
                        var sig = dbMsg.vSignals[i];
                        temp.signals.Add(sig);
                        temp.signal_Name[i] = Encoding.Default.GetString(sig.strName).TrimEnd('\0');
                    }

                    // 4. 初始化对应的 ZLG 发送帧结构 (预设好 ID 和 DLC)
                    temp.ACANFD = new CAN.ZCAN_CANFD_FRAME();
                    temp.ACANFD.can_id = dbMsg.nID;
                    temp.ACANFD.len = (byte)dbMsg.nSize;
                    temp.ACANFD.eff = dbMsg.nExtend;
                    temp.ACANFD.data = new byte[64];

                    MsgDatabase[channel].Add(temp);

                    // 获取下一条
                    hasMessage = ZDBC.ZDBC_GetNextMessage(hDBC, pMsg);
                }

                // 按 ID 排序
                MsgDatabase[channel].Sort((a, b) => a.msg_id.CompareTo(b.msg_id));
            }
            finally
            {
                // 释放内存
                Marshal.FreeHGlobal(pMsg);
            }
        }

        /// <summary>
        /// 加载 DBC 的入口函数
        /// </summary>
        public static int LoadDBC(string filePath, int[] channels, out uint databaseID)
        {
            // 初始化
            databaseID = ZDBC.ZDBC_Init(0, 1);
            if (databaseID == ZDBC.INVALID_DBC_HANDLE) return -1;

            // 准备文件信息
            ZDBC.FileInfo fileInfo = new ZDBC.FileInfo();
            fileInfo.strFilePath = new byte[ZDBC._MAX_FILE_PATH_ + 1];
            byte[] pathBytes = Encoding.Default.GetBytes(filePath);
            Array.Copy(pathBytes, fileInfo.strFilePath, Math.Min(pathBytes.Length, ZDBC._MAX_FILE_PATH_));
            fileInfo.type = ZDBC.PROTOCOL_OTHER;
            fileInfo.merge = 0;

            // 加载文件
            nint pFileInfo = Marshal.AllocHGlobal(Marshal.SizeOf(fileInfo));
            Marshal.StructureToPtr(fileInfo, pFileInfo, false);
            bool success = ZDBC.ZDBC_LoadFile(databaseID, pFileInfo);
            Marshal.FreeHGlobal(pFileInfo);

            if (!success)
            {
                ZDBC.ZDBC_Release(databaseID);
                return -2;
            }

            // 解析到各通道
            foreach (var ch in channels)
            {
                Parse(databaseID, ch);
            }

            return 0;
        }

        /// <summary>
        /// 卸载 DBC 并释放 ZDBC 句柄
        /// </summary>
        public static int UnLoadDBC(uint? databaseID = null)
        {
            if (databaseID.HasValue && databaseID.Value != ZDBC.INVALID_DBC_HANDLE)
            {
                ZDBC.ZDBC_Release(databaseID.Value);
            }

            foreach (var list in MsgDatabase)
            {
                list.Clear();
            }
            return 0;
        }
    }
}