using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.OleDb;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using GWSocketClient.db;
using GWSocketClient.model;
using GWSocketClient.util;
using GWSocketClient.xml;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using XuanJiSocket;


namespace GWSocketClient
{
    delegate void ThreadFormDelegate(object msg);

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private string ip;
        private string port;
        private SocketHelper.TcpClients sockeTcpClients;
        private VcarecityPD vcarecityProtocolBean = null;
        private volatile bool hbRunFlag = false; //心跳线程标志
        private ThreadFormDelegate uiDelegate;


        private void Form1_Load(object sender, EventArgs e)
        {
            XmlLoader xmlLoader = new XmlLoader();
            vcarecityProtocolBean = xmlLoader.loadXml();
            if (vcarecityProtocolBean != null)
            {
                this.Text = vcarecityProtocolBean.ProtocolName + " - " + vcarecityProtocolBean.ProtocolNo + " - " +
                            vcarecityProtocolBean.ProtocolStartSymbol;
            }

            SocketHelper.pushSockets = new SocketHelper.PushSockets(receiveData); //注册推送器
            sockeTcpClients = new SocketHelper.TcpClients();
            ip = tbIpaddress.Text.Trim();
            port = tbPort.Text.Trim();

            uiDelegate = addToListboxItem;
        }


        #region 处理心跳相关的

        //开启心跳连接
        private void startHeartBeatThread()
        {
            Thread thread = new Thread(heartBeatThread);
            thread.Start(this);
        }

        private void heartBeatThread(object o)
        {
            while (hbRunFlag)
            {
                int interval = 5;
                if (!toolStripTextBoxHbtime.Text.Trim().Equals(""))
                {
                    interval = int.Parse(toolStripTextBoxHbtime.Text.Trim());
                }
                Thread.Sleep(interval * 1000);


                if (hbRunFlag)
                {
                    string hbCmd = vcarecityProtocolBean.ProtocolStartSymbol;
                    hbCmd += tbEquipmentAddress.Text.Trim() + "840000";
                    hbCmd = Utils.calcCrcCode(hbCmd);
                    byte[] ts = HexUtil.hexToBytes(hbCmd);

                    sockeTcpClients.SendData(ts);

                    if (ToolStripMenuItemLogHb.Checked)
                    {
                        this.Invoke(this.uiDelegate, new object[] {string.Format("发送到服务端-心跳:[{0}]", hbCmd)});
                    }
                }
            }
            try
            {
                this.Invoke(this.uiDelegate, new object[] { "心跳线程结束!" });
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }

        #endregion

        private bool showTopForNoLoadXML()
        {
            if (vcarecityProtocolBean == null)
            {
                MessageBox.Show("请先加载XML协议文件");
                return false;
            }
            return true;
        }

        private void receiveData(SocketHelper.Sockets sks)
        {
            this.Invoke(new ThreadStart(delegate
            {
                if (sks.ex != null)
                {
                    switch (sks.ErrorCode)
                    {
                        case SocketHelper.Sockets.ErrorCodes.objectNull:
                            addToListboxItem("状态信息:服务器连接已断开");
                            hbRunFlag = false;
                            checkLogin(false);
                            break;
                        case SocketHelper.Sockets.ErrorCodes.ConnectError:
                            //连接不成功
                            addToListboxItem("状态信息:连接服务器失败,可能是服务器未开启!");
                            break;
                        case SocketHelper.Sockets.ErrorCodes.ConnectSuccess:
                            //连接成功
                            addToListboxItem("状态信息:与服务器连接成功");
                            addToListboxItem(string.Format("客户端信息{0}", sks.ex));
                            checkLogin(true);
                            sendLoginCmd();
                            hbRunFlag = true;
                            startHeartBeatThread();
                            break;
                        case SocketHelper.Sockets.ErrorCodes.TrySendData:
                            addToListboxItem("状态信息:ErrorCodes");
                            break;
                        default:
                            addToListboxItem(string.Format("客户端信息{0}", sks.ex));
                            break;
                    }
                }
                else
                {
                    byte[] buffer = new byte[sks.Offset];
                    Array.Copy(sks.RecBuffer, buffer, sks.Offset);
                    string byteToHexStr = HexUtil.byteToHexStr(buffer);

                    if (!byteToHexStr.Equals(""))
                    {
                        handleResponse(sks, byteToHexStr);
                    }
                    else
                    {
                        addToListboxItem("状态信息:服务端主动关闭! position");
                        sockeTcpClients.Stop();
                    }
                    //                    listBoxShow.Text += "\r\n";
                    //                    listBoxShow.Text += string.Format("服务端{0}发来消息：{1}", sks.Ip, byteToHexStr);
                }
            }));
        }

        /// <summary>
        /// 处理回复信息
        /// </summary>
        /// <param name="sks">Socket对象</param>
        /// <param name="reqData">服务器发过来的信息</param>
        private void handleResponse(SocketHelper.Sockets sks, string reqData)
        {
            //取出原数据功能码
            string functionWord = reqData.Substring(18, 2);
            int funcode = Utils.hexToTen(functionWord);


            //处理心跳的回复
            if (funcode == 4)
            {
                string hbLen = reqData.Substring(20, 4);

                if (ToolStripMenuItemLogHb.Checked && hbLen.Equals("0000"))
                {
                    addToListboxItem(string.Format("收到服务端{0}发来心跳：[{1}]", sks.Ip, reqData));
                }
            }
            else
            {
                addToListboxItem(string.Format("收到服务端{0}发来消息：[{1}]", sks.Ip, reqData));
            }

            if (!(funcode == 16 || funcode == 32))
            {
                Console.WriteLine("功能码10进制=" + funcode + ",所以不用回复!");
                return;
            }


            //16 表示要读数据,返回数据库中的数据
            //32 表示返回结果 成功:00 失败:01 

            //数据长度
            int dataLen = Utils.hexToTen(reqData.Substring(20, 4)) * 2;

            string readlData = "";
            try
            {
                readlData = reqData.Substring(24, dataLen);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                addToListboxItem("数据长度与帧长度对不上!! 帧数据长度=" + (dataLen / 2) + " ,Error=" + e.Message);
                return;
            }

            //消息流水&测量点
            string flowPoint = readlData.Substring(0, 6);
            //ID
            string myId = readlData.Substring(6, 4);
            //对应信息
            string idInfo = readlData.Substring(10);

            //回复功能码
            int responceFunCode = funcode + 128;

            string cmd = reqData.Substring(0, 18); //前面的

            cmd += Utils.stringWith0(Utils.tenToHex(responceFunCode), 2); //回复功能码
            string body = flowPoint + myId;

            if (funcode == 32)
            {
                //设置数据
                int res = AccsessDbLoader.getInstance().setReceiveData(myId, idInfo);

                //成功回复00 失败回复01
                if (res > 0)
                {
                    addToListboxItem("设置成功,功能码(10)=" + funcode + " ; ID=" + myId + " ; Value=" + idInfo);
                    body += "00";
                    AccsessDbLoader.getInstance().reloadAccessDb();
                }
                else
                {
                    addToListboxItem("设置失败,功能码(10)=" + funcode + " ; ID=" + myId + " ; Value=" + idInfo);
                    body += "01";
                }
            }
            else
            {
                //返回数据库的数据 OR 临时数据,如果临时数据有数据的话
                try
                {
                    string responce = AccsessDbLoader.getInstance().getUserIdInfo()[myId];

                    if (!tfTmpResponse.Text.Trim().Equals(""))
                    {
                        string inputRespocse = tfTmpResponse.Text.Trim();
                        responce = Utils.stringWith0(inputRespocse, responce.Length);
                    }
                    addToListboxItem("读取数据,功能码(10)=" + funcode + " ; ID=" + myId + " ; 回 复=" + responce);
                    body += responce;
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    addToListboxItem("异常,没有这个ID=(" + myId + "),ERROR=" + e.Message);
                    return;
                }
            }
            cmd += Utils.stringWith0(Utils.tenToHex(body.Length / 2), 4); //长度
            cmd += body; //消息体 
            cmd = Utils.calcCrcCode(cmd); //计算检验码

            addToListboxItem(string.Format("回复服务端{0}回应消息：[{1}]", sks.Ip, cmd));

            byte[] ts = HexUtil.hexToBytes(cmd);
            sockeTcpClients.SendData(ts);
        }


        private void tbEquipmentAddress_TextChanged(object sender, EventArgs e)
        {
            string equipmentAddress = tbEquipmentAddress.Text.Trim();

            tsslEquipmentAddress.Text = equipmentAddress.Length / 2.0 + "";
        }


        private void sendLoginCmd()
        {
            //                string loginCmd = "7e7e7e4442832e833c8200143839383630324231313931353530343739383737f7";
            string loginCmd = vcarecityProtocolBean.ProtocolStartSymbol;
            loginCmd += tbEquipmentAddress.Text.Trim() + "82" +
                        Utils.stringWith0(Utils.tenToHex(tbCCID.Text.Trim().Length / 2), 4);
            loginCmd += tbCCID.Text.Trim();
            loginCmd = Utils.calcCrcCode(loginCmd);
            //发送登录命令
            byte[] ts = HexUtil.hexToBytes(loginCmd);

            addToListboxItem(string.Format("发送到服务端:[{0}]", loginCmd));

            sockeTcpClients.SendData(ts);
        }

        private void btnLogin_Click(object sender, EventArgs e)
        {
            try
            {
                if (!showTopForNoLoadXML())
                    return;

                ip = tbIpaddress.Text.Trim();
                port = tbPort.Text.Trim();

                sockeTcpClients.InitSocket(ip, int.Parse(port));
                sockeTcpClients.Start();
            }
            catch (Exception ex)
            {
//                statuslist.Items.Add(string.Format("连接失败!原因：{0}", ex.Message
                Console.WriteLine(ex.Message);
            }
        }


        private void tbCCID_TextChanged(object sender, EventArgs e)
        {
            string ccid = tbCCID.Text.Trim();

            tsslCCIDLEN.Text = ccid.Length / 2.0 + "";
        }

        private void btnQuickLogout_Click(object sender, EventArgs e)
        {
            try
            {
                sockeTcpClients.Stop();
            }
            catch (Exception exception)
            {
                addToListboxItem("你还没有登录!!" + exception.Message);
            }
        }

        private void tsmiLoadXml_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "XML文件|*.xml|所有文件|*.*";
            ofd.InitialDirectory = Application.StartupPath;

            if (ofd.ShowDialog() == DialogResult.OK)
            {
                string xmlFilepath = ofd.FileName;

                vcarecityProtocolBean = new XmlLoader().load(xmlFilepath).getVcarecityPD();
                this.Text = vcarecityProtocolBean.ProtocolName + " - " + vcarecityProtocolBean.ProtocolNo + " - " +
                            vcarecityProtocolBean.ProtocolStartSymbol;
            }
        }

        private void btnSendData_Click(object sender, EventArgs e)
        {
            string trim = tfTmpSendData.Text.Trim();
            trim = trim.Replace("\n", "").Replace("\r", "").Replace("\t", "").Replace(" ", "").Replace("-", "");

            if (!trim.Equals(""))
            {
                byte[] ts = HexUtil.hexToBytes(trim);

                addToListboxItem(string.Format("发送到服务端:[{0}]", trim));

                sockeTcpClients.SendData(ts);
            }
        }

        private void rightMenuCopyCmd_Click(object sender, EventArgs e)
        {
            int index = listBoxShow.SelectedIndex;
            if (index >= 0 && index < listBoxShow.Items.Count)
            {
                string info = listBoxShow.SelectedItem.ToString();
                if (!info.Equals(""))
                {
                    if (info.Contains("[") || info.Contains("]"))
                    {
                        Regex reg = new Regex(@"\[\w+\]"); //注意里面的引号 要用双引号表示，而不是用反斜
                        Match match = reg.Match(info);
                        string ifs = match.ToString();
                        ifs = ifs.Replace("[", "").Replace("]", "");
                        if (!info.Equals(""))
                        {
                            Clipboard.SetDataObject(ifs);
                        }
                        else
                        {
                            Clipboard.SetDataObject(info);
                        }
                    }
                    else
                    {
                        Clipboard.SetDataObject(info);
                    }
                }
            }
        }


        private void addToListboxItem(object info)
        {
            if (listBoxShow.Items.Count > 1000)
            {
                listBoxShow.Items.Remove(0);
//                listBoxShow.Items.Clear();
            }

            Console.WriteLine(info);
            listBoxShow.Items.Add(info);
            listBoxShow.TopIndex = listBoxShow.Items.Count - 1;
        }


        private void rightMenuClearInfo_Click(object sender, EventArgs e)
        {
            listBoxShow.Items.Clear();
        }

        private void listBoxShow_DrawItem(object sender, DrawItemEventArgs e)
        {
            if (e.Index >= 0 && e.Index < listBoxShow.Items.Count)
            {
                e.DrawBackground();
                //
                string res = listBoxShow.Items[e.Index].ToString().ToLower();
                if (res.Contains("收到服务端"))
                {
                    Font f = new Font("微软雅黑", e.Font.Size, FontStyle.Bold);

                    e.Graphics.DrawString(((ListBox) sender).Items[e.Index].ToString(), f, new SolidBrush(Color.Blue),
                        e.Bounds);
                }
                else if (res.Contains("发送到服务端") || res.Contains("回复"))
                {
                    Font f = new Font("微软雅黑", e.Font.Size, FontStyle.Italic);
                    e.Graphics.DrawString(((ListBox) sender).Items[e.Index].ToString(), f,
                        new SolidBrush(Color.BlueViolet),
                        e.Bounds);
                }
                else if (res.Contains("读取数据,") || res.Contains("设置失败,") || res.Contains("设置成功,"))
                {
                    e.Graphics.DrawString(((ListBox) sender).Items[e.Index].ToString(), e.Font,
                        new SolidBrush(Color.Red),
                        e.Bounds);
                }
                else
                {
                    e.Graphics.DrawString(((ListBox) sender).Items[e.Index].ToString(), e.Font,
                        new SolidBrush(e.ForeColor),
                        e.Bounds);
                }
                e.DrawFocusRectangle();
            }
        }

        /// <summary>
        /// 压力测试
        /// </summary>
        private void btnPressureTest_Click(object sender, EventArgs e)
        {
            ip = tbIpaddress.Text.Trim();
            port = tbPort.Text.Trim();

            int count = int.Parse(tbPresureTestCount.Text);

            ThreadPool.QueueUserWorkItem(o =>
            {
                for (int i = 1024; i < 1024 + count; i++)
                {
                    SocketHelper.TcpClients clientx = new SocketHelper.TcpClients(); //初始化类库  
                    clientx.InitSocket(ip, int.Parse(port));
                    clientx.Start();

                    string loginCmd = "7e7e7e";
                    loginCmd += "4442832e" + i;
                    loginCmd += "820014383938363032423131393135353034373938" + i;
                    loginCmd = Utils.calcCrcCode(loginCmd);
                    sockeTcpClients.SendData(HexUtil.hexToBytes(loginCmd));
                    Thread.Sleep(200);
                }
            });
        }

        private void listBoxShow_DoubleClick(object sender, EventArgs e)
        {
            int index = listBoxShow.SelectedIndex;
            if (index >= 0 && index < listBoxShow.Items.Count)
            {
                string info = listBoxShow.SelectedItem.ToString();
                if (!info.Equals(""))
                {
                    if (info.Contains("[") || info.Contains("]"))
                    {
                        Regex reg = new Regex(@"\[\w+\]"); //注意里面的引号 要用双引号表示，而不是用反斜
                        Match match = reg.Match(info);
                        string ifs = match.ToString();
                        ifs = ifs.Replace("[", "").Replace("]", "");
                        if (!info.Equals(""))
                        {
//                            MessageBox.Show(ifs);
                            AnaProtocol ap = new AnaProtocol(ifs);
                            ap.ShowDialog();
                        }
                    }
                }
            }
        }

        private void buttonCmdManager_Click(object sender, EventArgs e)
        {
            InfoEditor ie = new InfoEditor();
            ie.ShowDialog();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            try
            {
                sockeTcpClients.Stop();
            }
            catch (Exception exception)
            {
            }
            finally
            {
                sockeTcpClients = null;
            }

            AccsessDbLoader.getInstance().closeConnection();
        }

        private void btnTextCmd_Click(object sender, EventArgs e)
        {
//            string code = Utils.calcCrcCode("7e7e7e123456789abc20000701010107030001");
//            code = Utils.calcCrcCode("7e7e7e123456789abc10000501010107023f");
//            Console.WriteLine(code);

//            handleResponse(null, code);


            /*try
            {
                Dictionary<string, string> abc = AccsessDbLoader.getInstance().getUserIdInfo();
                MessageBox.Show(abc.Count + "");
                string ac = abc["0400"];
                MessageBox.Show(ac);
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception);
            }*/
        }

        private void toolStripTextBoxHbtime_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar != 8 && !Char.IsDigit(e.KeyChar))
            {
                e.Handled = true;
            }
        }

        private void ToolStripMenuItemLogHb_Click(object sender, EventArgs e)
        {
            ToolStripMenuItemLogHb.Checked = !ToolStripMenuItemLogHb.Checked;
        }


        private void checkLogin(bool isLogin)
        {
            if (isLogin)
            {
                btnLogin.Enabled = false;
                btnQuickLogout.Enabled = true;
                btnSendData.Enabled = true;
            }
            else
            {
                btnLogin.Enabled = true;
                btnQuickLogout.Enabled = false;
                btnSendData.Enabled = false;
            }
        }
    }
}