using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;

namespace PCie_PN_TEST
{
    public partial class Form1 : Form
    {
        public int devIndex = -1;
        #region === 结构体定义 ===
        [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
        public struct DEVICE_NET_INFO_T
        {
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
            public byte[] name;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
            public byte[] mac;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
            public byte[] ip;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
            public byte[] mask;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
            public byte[] gw;

            /// <summary>一次性分配并清零</summary>
            public static DEVICE_NET_INFO_T Create()
            {
                var n = new DEVICE_NET_INFO_T
                {
                    name = new byte[16],
                    mac = new byte[32],
                    ip = new byte[16],
                    mask = new byte[16],
                    gw = new byte[16]
                };
                return n;
            }

            public override string ToString()
            {
                return $"name={BytesToStr(name)} mac={BytesToStr(mac)} ip={BytesToStr(ip)}";
            }
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
        public struct DEVICE_MODULE_INFO_T
        {
            public int status;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
            public byte[] name;
            public int type;
            public int recLen;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
            public byte[] record;
            public int in_size;
            public int out_size;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
            public byte[] in_buff;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
            public byte[] out_buff;

            public static DEVICE_MODULE_INFO_T Create()
            {
                return new DEVICE_MODULE_INFO_T
                {
                    name = new byte[32],
                    record = new byte[4],
                    in_buff = new byte[128],
                    out_buff = new byte[128]
                };
            }
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
        public struct DEVICE_INFO_T
        {
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
            public byte[] app_ver;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
            public byte[] fw_ver;
            public int max_slot_num;
            public int cur_slot_num;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
            public DEVICE_NET_INFO_T[] net;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
            public DEVICE_MODULE_INFO_T[] module;

            /// <summary>一次性把整个结构体（含定长数组）创建并清零</summary>
            public static DEVICE_INFO_T Create()
            {
                var dev = new DEVICE_INFO_T
                {
                    app_ver = new byte[16],
                    fw_ver = new byte[16],
                    net = new DEVICE_NET_INFO_T[2],
                    module = new DEVICE_MODULE_INFO_T[64]
                };
                for (int i = 0; i < 2; i++) dev.net[i] = DEVICE_NET_INFO_T.Create();
                for (int i = 0; i < 64; i++) dev.module[i] = DEVICE_MODULE_INFO_T.Create();
                return dev;
            }
        }
        #endregion

        #region === 小工具 ===
        /// <summary>把以 \0 结尾的 byte[] 转成 string，去掉尾部 0</summary>
        public static string BytesToStr(byte[] buf)
        {
            if (buf == null) return "";
            int len = Array.IndexOf(buf, (byte)0);
            if (len < 0) len = buf.Length;
            return Encoding.ASCII.GetString(buf, 0, len);
        }
        #endregion

        [DllImport("PN-DEV.dll", EntryPoint = "test_func", CallingConvention = CallingConvention.Cdecl)]
        public static extern int test_func(int a, int b);
        [DllImport("PN-DEV.dll", EntryPoint = "pn_dev_init", CallingConvention = CallingConvention.Cdecl)]
        public static extern int pn_dev_init();
        [DllImport("PN-DEV.dll", EntryPoint = "pn_dev_deinit", CallingConvention = CallingConvention.Cdecl)]
        public static extern bool pn_dev_deinit();
        [DllImport("PN-DEV.dll", EntryPoint = "pn_dev_open", CallingConvention = CallingConvention.Cdecl)]
        public static extern bool pn_dev_open(int index);
        [DllImport("PN-DEV.dll", EntryPoint = "pn_dev_close", CallingConvention = CallingConvention.Cdecl)]
        public static extern bool pn_dev_close(int index);
        [DllImport("PN-DEV.dll", EntryPoint = "pn_dev_info_get", CallingConvention = CallingConvention.Cdecl)]
        public static extern bool pn_dev_info_get(int index, ref DEVICE_INFO_T pDevInfo);
        [DllImport("PN-DEV.dll", EntryPoint = "pn_dev_net_get", CallingConvention = CallingConvention.Cdecl)]
        public static extern bool pn_dev_net_get(int index, ref DEVICE_NET_INFO_T pDevNet);
        [DllImport("PN-DEV.dll", EntryPoint = "pn_dev_net_set", CallingConvention = CallingConvention.Cdecl)]
        public static extern bool pn_dev_net_set(int index, ref DEVICE_NET_INFO_T pDevNet);
        [DllImport("PN-DEV.dll", EntryPoint = "pn_dev_module_info_get", CallingConvention = CallingConvention.Cdecl)]
        public static extern bool pn_dev_module_info_get(int index, int slot, ref DEVICE_MODULE_INFO_T pDevModuleInfo);
        [DllImport("PN-DEV.dll", EntryPoint = "pn_dev_module_data_get", CallingConvention = CallingConvention.Cdecl)]
        public static extern bool pn_dev_module_data_get(int Index, int Slot, int Type, int Offset, int Size, [Out] byte[] pData);
        [DllImport("PN-DEV.dll", EntryPoint = "pn_dev_module_data_set", CallingConvention = CallingConvention.Cdecl)]
        public static extern bool pn_dev_module_data_set(int Index, int Slot, int Type, int Offset, int Size, [Out] byte[] pData);
        public Form1()
        {
            InitializeComponent();
            comboBox2.SelectedIndex = 0;
            listBox1.MouseDoubleClick += listBox1_MouseDoubleClick;

        }
        
        private void button1_Click(object sender, EventArgs e)
        {
            bool ret = pn_dev_open(devIndex);
            if (ret == false)
            {
                MessageBox.Show($"连接板卡失败！\n设备索引 = {devIndex}");
                return;
            }
            
            //MessageBox.Show("连接板卡成功"); 

        }

        private void textBox14_TextChanged(object sender, EventArgs e)
        {

        }

        private void listBox1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            // 获取点击位置的索引
            int index = listBox1.IndexFromPoint(e.Location);

            if (index == ListBox.NoMatches)
            {
                MessageBox.Show("无效双击");
                return;
            }
            string selectedItem = listBox1.Items[index].ToString();
            Console.WriteLine($"鼠标双击 - 索引: {index}, 内容: {selectedItem}");
            DEVICE_MODULE_INFO_T Module = DEVICE_MODULE_INFO_T.Create();
            int slot = index + 1;
            bool ret = pn_dev_module_info_get(devIndex, slot, ref Module);
            if (ret == false)
            {
                MessageBox.Show($"获取 {slot} 号插槽信息失败");
                return;
            }
            label17.Text = Module.in_size.ToString() + " Byte";
            label18.Text = Module.out_size.ToString() + " Byte";
            textBox11.Text = slot.ToString();
            textBox12.Text = "0";
            int buff_size = 0;
            if ((Module.type & 0x01) != 0)
                buff_size = Module.out_size;
            else if ((Module.type & 0x02) != 0)
                buff_size = Module.in_size;
            else
                buff_size = Module.in_size;
            textBox13.Text = buff_size.ToString();
            string In = "", Out = "";
            for (int i = 0; i < buff_size; i++)
            {
                if ((Module.type & 0x01) != 0)
                {
                    Out += Module.out_buff[i].ToString("X2") + " ";
                }
                if ((Module.type & 0x02) != 0)
                {
                    In += Module.in_buff[i].ToString("X2") + " ";
                }
            }
            textBox14.Text = In;
            textBox15.Text = Out;
        }

        private void button3_Click(object sender, EventArgs e)
        {
            int type = comboBox2.SelectedIndex == 0 ? 2 : 1;
            int slot = Convert.ToInt32(textBox11.Text);
            int offset = Convert.ToInt32(textBox12.Text);
            int size = Convert.ToInt32(textBox13.Text);
            byte[] data = new byte[128];

            Stopwatch sw = Stopwatch.StartNew();
            bool ret = pn_dev_module_data_get(devIndex, slot, type, offset, size, data);
            if (ret == false)
            {
                MessageBox.Show("读取错误");
                return;
            }
            sw.Stop();

            Console.WriteLine($"返回码 : {ret}");
            Console.WriteLine($"耗时   : {sw.Elapsed.TotalMilliseconds:F3} ms");
            Console.WriteLine($"时钟数 : {sw.ElapsedTicks} ticks");

            string Out = "";
            for (int i = 0; i < size; i++)
            {
                Out += data[i].ToString("X2") + " ";
            }
            if (type == 2)
            {
                textBox14.Text = Out;
                textBox15.Text = "";
            }
            else
            {
                textBox14.Text = "";
                textBox15.Text = Out;
            }
        }

        private void button4_Click(object sender, EventArgs e)
        {
            int type = comboBox2.SelectedIndex == 0 ? 2 : 1;
            int slot = Convert.ToInt32(textBox11.Text);
            int offset = Convert.ToInt32(textBox12.Text);
            int size = Convert.ToInt32(textBox13.Text);
            byte[] data = new byte[128];
            String[] In = textBox14.Text.Split(' ');
            for (int i = 0; i < size; i++)
            {
                data[i] = Convert.ToByte(In[i], 16);
            }
            bool ret = pn_dev_module_data_set(devIndex, slot, type, offset, size, data);
            if (ret == false)
            {
                MessageBox.Show("写入错误");
                return;
            }
        }

        private void button5_Click(object sender, EventArgs e)
        {
            DEVICE_INFO_T devInfo = DEVICE_INFO_T.Create();
            bool ret = pn_dev_info_get(devIndex, ref devInfo);
            if (!ret)
            {
                MessageBox.Show("获取板卡信息失败");
                return;
            }
            Console.WriteLine("fw ver" + BytesToStr(devInfo.fw_ver));
            textBox1.Text = BytesToStr(devInfo.net[0].name);
            textBox2.Text = BytesToStr(devInfo.net[0].mac);
            textBox3.Text = BytesToStr(devInfo.net[0].ip);
            textBox4.Text = BytesToStr(devInfo.net[0].mask);
            textBox5.Text = BytesToStr(devInfo.net[0].gw);
            textBox6.Text = BytesToStr(devInfo.net[1].name);
            textBox7.Text = BytesToStr(devInfo.net[1].mac);
            textBox8.Text = BytesToStr(devInfo.net[1].ip);
            textBox9.Text = BytesToStr(devInfo.net[1].mask);
            textBox10.Text = BytesToStr(devInfo.net[1].gw);
            label19.Text = BytesToStr(devInfo.app_ver);
            label20.Text = BytesToStr(devInfo.fw_ver);
            label25.Text = devInfo.cur_slot_num.ToString();
            label26.Text = devInfo.max_slot_num.ToString();
            listBox1.Items.Clear();
            for (int i = 1; i < devInfo.max_slot_num; i++)
            {
                string lines;
                if (devInfo.module[i].status == 1)
                {
                    lines = $"{i,-2}" + "  " + BytesToStr(devInfo.module[i].name);
                    listBox1.Items.Add(lines);
                }
                else
                {
                    lines = $"{i,-2}" + "  " + "- - - ";
                    listBox1.Items.Add(lines);
                }
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            bool ret = pn_dev_close(devIndex);
            if (ret == false)
                MessageBox.Show("关闭失败");
            devIndex = -1;
        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            devIndex = comboBox1.SelectedIndex;
        }

        private void comboBox1_DropDown(object sender, EventArgs e)
        {
            if (comboBox1.Items.Count > 0)
            {
                comboBox1.Items.Clear();
                pn_dev_deinit();
            }
            int ret = pn_dev_init();
            if (ret <= 0)
                MessageBox.Show("未检查到可用设备。");
            for (int i = 0; i < ret; i++)
            {
                comboBox1.Items.Add(i);
            }
        }
    }
}
