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
    {
        #region 属性定义

        private string ip;
        private string port;
        private SocketHelper.TcpClients sockeTcpClients;

        private VcarecityPD vcarecityProtocolBean = null;

        private ThreadFormDelegate uiDelegate;


        //这个发送时间,不处理心跳时间
        private bool sendCmd = false;

        private DateTime sendCmdTime;

        #endregion


        #region Form 事件

        public Form1()
        {
            InitializeComponent();
        }

        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;

            timerHeartBeat.Enabled = ToolStripMenuItemHbStart.Checked;
        }

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

            AccessDbLoader.getInstance().closeConnection();
        }

        #endregion


        #region 点击事件

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


                SocketHelper.pushSockets = new SocketHelper.PushSockets(receiveData); //注册推送器
                sockeTcpClients = new SocketHelper.TcpClients();
                sendCmdTime = DateTime.Now;

                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 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("-", "");

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

                    AccessDbLoader.getInstance().addToHistory(AccessDbLoader.SEND_HIS, trim);
                    addToListboxItem(string.Format("发送到服务端:[{0}]", trim));
                    //记录发送时间
                    sendCmdTime = DateTime.Now;
                    sendCmd = true;

                    sockeTcpClients.SendData(ts);
                }
            }
            catch (Exception exception)
            {
                MessageBox.Show(exception.Message);
            }
        }

        /// <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 buttonCmdManager_Click(object sender, EventArgs e)
        {
            InfoEditor ie = new InfoEditor();
            ie.ShowDialog();
        }


        private void btnTextCmd_Click(object sender, EventArgs e)
        {
            //beta test tool
            if (tfTmpSendData.Text.Trim().ToLower().Equals("pre"))
            {
                btnPressureTest.Visible = !btnPressureTest.Visible;
                tbPresureTestCount.Visible = !tbPresureTestCount.Visible;
                label4.Visible = !label4.Visible;
            }
            else
            {
                AccessDbLoader.getInstance().addToHistory(AccessDbLoader.SEND_HIS, "1234567890");
            }
        }

        private void toolStripMenuItemHBtime_Click(object sender, EventArgs e)
        {
            InputDialog id = new InputDialog();
            id.InputResult += (string topmost) =>
            {
                timerHeartBeat.Interval = int.Parse(topmost) * 1000;
                //5秒
                toolStripStatusLabelHbShow.Text = "心跳时间: " + topmost + "秒";
            };
            id.ShowDialog();
        }

        private void Id_InputResult(string topmost)
        {
            throw new NotImplementedException();
        }

        private void labelHis_Click(object sender, EventArgs e)
        {
            Label lab = sender as Label;
            HistoryDialog hd = new HistoryDialog(lab.Name);
            hd.HistoryHandler += Hd_HistoryHandler;
            hd.ShowDialog();
        }

        private void Hd_HistoryHandler(string type, string result)
        {
            if ("labelCCIDHIS".Equals(type))
            {
                tbCCID.Text = result;
            }
            else if ("labelAddHis".Equals(type))
            {
                tbEquipmentAddress.Text = result;
            }
            else if ("labelIPHIS".Equals(type))
            {
                tbIpaddress.Text = result;
            }
            else if ("labelSendHIS".Equals(type))
            {
                tfTmpSendData.Text = result;
            }
        }

        private void IPToolStripMenuItem_Click(object sender, EventArgs e)
        {
            HistoryDialog hd = new HistoryDialog("labelIPHIS");
            hd.HistoryHandler += Hd_HistoryHandler;
            hd.ShowDialog();
        }

        private void AddrToolStripMenuItem_Click(object sender, EventArgs e)
        {
            HistoryDialog hd = new HistoryDialog("labelAddHis");
            hd.HistoryHandler += Hd_HistoryHandler;
            hd.ShowDialog();
        }

        private void CCIDToolStripMenuItem_Click(object sender, EventArgs e)
        {
            HistoryDialog hd = new HistoryDialog("labelCCIDHIS");
            hd.HistoryHandler += Hd_HistoryHandler;
            hd.ShowDialog();
        }

        private void SendToolStripMenuItem_Click(object sender, EventArgs e)
        {
            HistoryDialog hd = new HistoryDialog("labelSendHIS");
            hd.HistoryHandler += Hd_HistoryHandler;
            hd.ShowDialog();
        }

        #endregion


        #region 处理心跳相关的

        private void timerHeartBeat_Tick(object sender, EventArgs e)
        {
            Thread thread = new Thread(heartBeatThread);
            thread.Start(this);
        }
/*
        //开启心跳连接
        private void startHeartBeatThread()
        {
        }*/

        private void heartBeatThread(object o)
        {
            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)});
            }
        }

        private void ToolStripMenuItemHbStart_CheckStateChanged(object sender, EventArgs e)
        {
            timerHeartBeat.Enabled = ToolStripMenuItemHbStart.Checked;
        }

        #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("状态信息:服务器连接已断开");
                            checkLogin(false);
                            break;
                        case SocketHelper.Sockets.ErrorCodes.ConnectError:
                            //连接不成功
                            addToListboxItem("状态信息:连接服务器失败,可能是服务器未开启!");
                            checkLogin(false);
                            break;
                        case SocketHelper.Sockets.ErrorCodes.ConnectSuccess:
                            //连接成功
                            addToListboxItem("状态信息:与服务器连接成功");
                            addToListboxItem(string.Format("客户端信息{0}", sks.ex));
                            sendLoginCmd();
                            checkLogin(true);

                            if (StripMenuItemLoSucHb.Checked)
                            {
                                ToolStripMenuItemHbStart.Checked = true;
                            }
                            break;
                        case SocketHelper.Sockets.ErrorCodes.TrySendData:
                            addToListboxItem("状态信息:ErrorCodes");
                            checkLogin(false);
                            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 (sendCmd)
            {
                sendCmd = false;
                long time = (long)(DateTime.Now - sendCmdTime).TotalMilliseconds;
                toolStripStatusLabelSendTime.Text = "发送-回复时间: " + time + "/ms";
            }
            
            //处理心跳的回复
            if (funcode == 4)
            {
                string hbLen = reqData.Substring(20, 4);

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

            if (!(funcode == 16 || funcode == 32))
            {
                Console.WriteLine("功能码10进制=" + funcode + ",所以不用回复! data=" + reqData);
                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 = AccessDbLoader.getInstance().setReceiveData(myId, idInfo);

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


            loginCmd += 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("发送到服务端,funCode={0} : [{1}]", loginCmd.Substring(18, 2), loginCmd));

            sockeTcpClients.SendData(ts);
        }


        private void tbCCID_TextChanged(object sender, EventArgs e)
        {
            string ccid = tbCCID.Text.Trim();
            tsslCCIDLEN.Text = ccid.Length / 2.0 + "";
        }


        #region ListBox相关

        /// <summary>
        /// ListBox右键菜单-点击复制
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        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();
            }
        }

        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();
                        }
                    }
                }
            }
        }

        #endregion


        #region 检验工具类

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


        private void checkLogin(bool isLogin)
        {
            if (isLogin)
            {
                btnLogin.Enabled = false;
                btnQuickLogout.Enabled = true;
                btnSendData.Enabled = true;
                ToolStripMenuItemHbStart.Enabled = true; //开启心中的点击选项
                if (StripMenuItemLoSucHb.Checked)
                {
                    //如果勾选了登录成功并心跳
                    timerHeartBeat.Enabled = true;
                }

                //ADD To History
                AccessDbLoader.getInstance().addToHistory(AccessDbLoader.IP_HIS, tbIpaddress.Text.Trim());
                AccessDbLoader.getInstance().addToHistory(AccessDbLoader.CCID_HIS, tbCCID.Text.Trim());
                AccessDbLoader.getInstance().addToHistory(AccessDbLoader.ADDR_HIS, tbEquipmentAddress.Text.Trim());
            }
            else
            {
                btnLogin.Enabled = true;
                btnQuickLogout.Enabled = false;
                btnSendData.Enabled = false;
                ToolStripMenuItemHbStart.Checked = false;
                ToolStripMenuItemHbStart.Enabled = false;
                timerHeartBeat.Enabled = false;
            }
        }

        #endregion

        private void ClearAllAllToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AccessDbLoader.getInstance().deleteAllData(AccessDbLoader.IP_HIS);
            AccessDbLoader.getInstance().deleteAllData(AccessDbLoader.ADDR_HIS);
            AccessDbLoader.getInstance().deleteAllData(AccessDbLoader.SEND_HIS);
            AccessDbLoader.getInstance().deleteAllData(AccessDbLoader.CCID_HIS);
        }
    }
}