using HeidenhainDNCLib;
using IMCS.HeidenHain;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using HEIDENHAIN.body;
using System.Net.NetworkInformation;

namespace HEIDENHAIN
{
    public partial class Form1 : Form
    {
        private int iChannel = 0;
        //private string RemotePath = "TNC:\\nc_prog\\ATUO";//ConfigurationManager.AppSettings["RemotePath"]; 
        private string RemotePath = "TNC:\\SMG80SKCX";//ConfigurationManager.AppSettings["RemotePath"]; 

        //连接设备列表
        public Dictionary<string, DNC_STATE> deviceList { get; set; } = new Dictionary<string, DNC_STATE>();
        private DNC_STATE m_ControlState;
        public Dictionary<string, JHMachineInProcess> machineList { get; set; } = new Dictionary<string, JHMachineInProcess>();
        //private JHMachineInProcess Machine = new JHMachineInProcess();
        // private JHAutomatic m_Automatic = null;
        // private JHFileSystem m_FileSystem = null;
        //private JHProcessData m_ProcessData = null;
        //private JHError m_Error = null; 
       

        string Http_Request_Url = "http://127.0.0.1:8011/heidenhain/";
        bool _contine = true;//用于线程循环
        private AutoResetEvent autoConnectEvent = new AutoResetEvent(false);//此处需要调用System.Threading;用于触发等待的线程已发生的事件(连接)
        public delegate void RecvAndSendHandler(HttpListenerContext s);//此处需要调用System.Net用于请求和响应HttpListener类
        public event RecvAndSendHandler RecvAndSend;

        AsyncCallback callback;
        HttpListenerContext context = null;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        { 
            this.RecvAndSend += new RecvAndSendHandler(HttpListen_RecvAndSend);
            #region 添加监听的信息线程添加到线程池
            WaitCallback wc = new WaitCallback(http_Listen);
            ThreadPool.QueueUserWorkItem(wc);
            label1.Text = "HttpServer已开启：" + Http_Request_Url;
 
            #endregion 

        }
        /// <summary>
        /// 监听的线程
        /// </summary>
        /// <param name="ob"></param>
        private void http_Listen(object ob)
        {
            callback = new AsyncCallback(acceptCallback);

            HttpListener httpListenner;
            httpListenner = new HttpListener();
            httpListenner.AuthenticationSchemes = AuthenticationSchemes.Anonymous;
            httpListenner.Prefixes.Add(Http_Request_Url);
            httpListenner.Start();

            while (_contine)
            {
                try
                {
                    httpListenner.BeginGetContext(callback, httpListenner);
                    autoConnectEvent.WaitOne();
                }
                catch (Exception)
                {

                }
                Thread.Sleep(10);
            }
        }
        /// <summary>
        /// 回调函数
        /// </summary>
        /// <param name="ar"></param>
        private void acceptCallback(IAsyncResult ar)
        {
            try
            {
                context = ((HttpListener)ar.AsyncState).EndGetContext(ar);
            }
            catch (Exception)
            {
                autoConnectEvent.Set();
            }
            if (context != null)
            {
                RecvAndSend(context);//触发我们一开始声明的事件
                autoConnectEvent.Set();
            }
        }

        /// <summary>
        /// 接听到消息的方法
        /// </summary>
        /// <param name="cont"></param>
        private void HttpListen_RecvAndSend(HttpListenerContext cont)
        {
            HttpListenerRequest request = cont.Request;
            HttpListenerResponse response = context.Response;
            Servlet servlet = new MyServlet();
            servlet.onCreate();

            if (request.HttpMethod == "POST")
            {
                if (!request.Url.ToString().Contains("favicon"))
                {
                    ResponseBody responseBody = new ResponseBody();
                    string body = null;
                    RequestBody hdhBody =null;
                    try
                    {
                        Stream stream = context.Request.InputStream;
                        StreamReader reader = new StreamReader(stream, Encoding.UTF8);
                        body = reader.ReadToEnd();

                        //YG.Log.Instance.WriteLogAdd(">>>===收到POST数据 : >>>>===" + body);

                        hdhBody = JsonConvert.DeserializeObject<RequestBody>(body);

                        AddList(DateTime.Now.ToString(), "POST", hdhBody.ServerUrl + ":设备:" + hdhBody.MachineName, "OK：数据接受");

                        if (hdhBody.Type == ActionTypeEnum.Connect.ToString())
                        {
                            Ping pingSender = new Ping();
                            PingReply reply = pingSender.Send(hdhBody.ServerUrl);
                            if (reply.Status != IPStatus.Success)
                            {
                                responseBody.result = false;
                            }
                        }
                        else
                        {
                            //第一次连接加入数组,以支持多台设备
                            if (deviceList == null || (deviceList.Where(m => m.Key == hdhBody.MachineName).Count() == 0))
                            {
                                m_ControlState = connect(hdhBody.MachineName);

                                //DNC连接正常,加入数组
                                if (m_ControlState.ToString() == "DNC_STATE_MACHINE_IS_AVAILABLE")
                                {
                                    deviceList.Add(hdhBody.MachineName, m_ControlState);
                                }
                                Thread.Sleep(500);
                            }
                            else
                            {
                                //取设备对应的状态
                                m_ControlState = deviceList.Where(m => m.Key == hdhBody.MachineName).FirstOrDefault().Value;
                            }
                           

                            if (m_ControlState != null && m_ControlState.ToString() == "DNC_STATE_MACHINE_IS_AVAILABLE")
                            {
                                JHMachineInProcess Machine = machineList.Where(m => m.Key == hdhBody.MachineName).FirstOrDefault().Value;
                                JHError m_Error = Machine.GetInterface(HeidenhainDNCLib.DNC_INTERFACE_OBJECT.DNC_INTERFACE_JHERROR);
                                JHErrorEntry2List errorsList = m_Error.GetErrorList();
                                IJHErrorEntry2 pErrorEntry = null;
                                for (int i = 0; i < errorsList.Count; i++)
                                {
                                    pErrorEntry = errorsList[i];
                                    if (pErrorEntry != null && pErrorEntry.Text != null)
                                    {
                                        //Console.WriteLine("===" + pErrorEntry.Text.ToString());
                                        responseBody.errorsInfo += pErrorEntry.Text.ToString() + " ";
                                    }
                                }


                                if (hdhBody.Type == ActionTypeEnum.Collect.ToString())
                                {

                                    JHAutomatic m_Automatic = Machine.GetInterface(DNC_INTERFACE_OBJECT.DNC_INTERFACE_JHAUTOMATIC);

                                    JHProcessData m_ProcessData = Machine.GetInterface(HeidenhainDNCLib.DNC_INTERFACE_OBJECT.DNC_INTERFACE_JHPROCESSDATA);


                                    object pFeed = new object();
                                    object pSpeed = new object();
                                    object pRapid = new object();
                                    object proStatus = new object();
                                    //进出倍率 主轴倍率 
                                    m_Automatic.GetOverrideInfo(ref pFeed, ref pSpeed, ref pRapid);
                                    m_Automatic.GetExecutionMode();
                                    DNC_STS_PROGRAM dncProgram = m_Automatic.GetProgramStatus();

                                    RunDatasInfo runDatasInfo = new RunDatasInfo();
                                    runDatasInfo.feedRate = pFeed.ToString();
                                    runDatasInfo.spindleMagnification = pSpeed.ToString();
                                    runDatasInfo.spindleSpeed = pRapid.ToString();

                                    responseBody.runDatasInfo = JsonConvert.SerializeObject(runDatasInfo);

                                    object oHours = new object();
                                    object oMinutes = new object();
                                    // --- NC uptime --------------------------------------------------------------------------
                                    m_ProcessData.GetNcUpTime(ref oHours, ref oMinutes);
                                    string ncUpTime = oHours.ToString() + ":" + (Convert.ToInt32(oMinutes) > 9 ? oMinutes.ToString() : ("0" + oMinutes.ToString()));

                                    // --- Machine uptime ---------------------------------------------------------------------
                                    m_ProcessData.GetMachineUpTime(ref oHours, ref oMinutes);
                                    string machineUpTime = oHours.ToString() + ":" + (Convert.ToInt32(oMinutes) > 9 ? oMinutes.ToString() : ("0" + oMinutes.ToString()));
                                    // --- Machine running time ---------------------------------------------------------------
                                    m_ProcessData.GetMachineRunningTime(ref oHours, ref oMinutes);
                                    string runningTimes = oHours.ToString() + ":" + (Convert.ToInt32(oMinutes) > 9 ? oMinutes.ToString() : ("0" + oMinutes.ToString()));


                                }
                                else if (hdhBody.Type == ActionTypeEnum.Upload.ToString())
                                {

                                    JHFileSystem m_FileSystem = Machine.GetInterface(DNC_INTERFACE_OBJECT.DNC_INTERFACE_JHFILESYSTEM);

                                    JHAutomatic m_Automatic = Machine.GetInterface(DNC_INTERFACE_OBJECT.DNC_INTERFACE_JHAUTOMATIC);

                                    string sSelectedFile = Path.GetFileName(hdhBody.Path);
                                    string dncPath = null;
                                    string tempDncPath = RemotePath + "\\2.h";
                                    if (hdhBody.Address != "")
                                    {
                                        RemotePath = RemotePath + "\\" + hdhBody.Address;
                                    }
                                    //上传
                                    dncPath = GenPath(RemotePath, sSelectedFile);
                                    //设置临时程序为主程序
                                    m_Automatic.SelectProgram(iChannel, tempDncPath);
                                    try
                                    { //删除上传文件，try异常防止文件不存在
                                      //m_FileSystem.DeleteFile(dncPath);
                                    }
                                    catch (Exception edel)
                                    {
                                    }
                                    //上传
                                    m_FileSystem.TransmitFile(hdhBody.Path, dncPath);
                                    //设当前上传程序为主程序
                                    m_Automatic.SelectProgram(iChannel, dncPath);
                                }
                                else if (hdhBody.Type == ActionTypeEnum.DeleteNc.ToString())
                                {

                                    JHFileSystem m_FileSystem = Machine.GetInterface(DNC_INTERFACE_OBJECT.DNC_INTERFACE_JHFILESYSTEM);

                                    string dncPath = GenPath(RemotePath, hdhBody.Path);
                                    m_FileSystem.DeleteFile(dncPath);
                                }
                                else if (hdhBody.Type == ActionTypeEnum.SelectNcProgram.ToString())//选中程序
                                {

                                    JHAutomatic m_Automatic = Machine.GetInterface(DNC_INTERFACE_OBJECT.DNC_INTERFACE_JHAUTOMATIC);

                                    string dncPath = GenPath(RemotePath, hdhBody.Path);
                                    m_Automatic.SelectProgram(iChannel, dncPath);
                                }
                                else if (hdhBody.Type == ActionTypeEnum.StartNcProgram.ToString())//启动程序备用
                                {

                                    JHAutomatic m_Automatic = Machine.GetInterface(DNC_INTERFACE_OBJECT.DNC_INTERFACE_JHAUTOMATIC);

                                    //m_Automatic.SelectProgram(iChannel, GenPath(RemotePath, hdhBody.Path));
                                    //Thread.Sleep(1000);
                                    m_Automatic.StartProgram(GenPath(RemotePath, hdhBody.Path));
                                }
                                else if (hdhBody.Type == ActionTypeEnum.Read.ToString())
                                {

                                }
                                else if (hdhBody.Type == ActionTypeEnum.Write.ToString())
                                {

                                }
                                else if (hdhBody.Type == ActionTypeEnum.ToolList.ToString())
                                {
                                    IJHDataEntry2 ToolLine = null;
                                    IJHDataEntry2List ToolCells = null;
                                    //IJHDataEntry2 ToolCell = null;                                    
                                    List<ToolsInfo> toolsList = new List<ToolsInfo>();
                                    JHDataAccess dataAccess = Machine.GetInterface(HeidenhainDNCLib.DNC_INTERFACE_OBJECT.DNC_INTERFACE_JHDATAACCESS);
                                    dataAccess.SetAccessMode(DNC_ACCESS_MODE.DNC_ACCESS_MODE_TABLEDATAACCESS, "");
                                    //string ToolColumnNamesAccessor = @"\TABLE\TOOL\T\('1'-'50')";   // see Init()
                                    string ToolColumnNamesAccessor = @"\TABLE\TOOL_P\T\('1'-'50')";
                                    IJHDataEntry2 ToolTable = dataAccess.GetDataEntry2(ToolColumnNamesAccessor, DNC_DATA_UNIT_SELECT.DNC_DATA_UNIT_SELECT_METRIC, false);
                                    IJHDataEntry2List ToolLines = ToolTable.GetChildList();
                                    int ToolLinesCount = ToolLines.Count >= 50 ? 50 : ToolLines.Count;
                                    //int ToolLinesCount = ToolLines.Count;                                    
                                    for (int i = 0; i < ToolLinesCount; i++)
                                    {
                                        ToolLine = ToolLines[i];
                                        ToolCells = ToolLine.GetChildList();
                                        // get child list from server                                       
                                        ToolsInfo toolsInfo = new ToolsInfo();

                                        //刀位编码
                                        int[] pCode = ToolCells[0].GetPropertyValue(DNC_DATAENTRY_PROPKIND.DNC_DATAENTRY_PROPKIND_DATA);
                                        toolsInfo.position = string.Join(".", pCode);
                                        toolsInfo.number = ToolCells[1].GetPropertyValue(DNC_DATAENTRY_PROPKIND.DNC_DATAENTRY_PROPKIND_DATA).ToString();
                                        toolsInfo.name = ToolCells[2].GetPropertyValue(DNC_DATAENTRY_PROPKIND.DNC_DATAENTRY_PROPKIND_DATA).ToString();


                                        if (!String.IsNullOrEmpty(toolsInfo.name) && !String.IsNullOrEmpty(toolsInfo.number) && pCode.Length > 0 && pCode[1] > 0)
                                        {
                                            string ToolNumberAccessor = @"\TABLE\TOOL\T\" + toolsInfo.number.ToString();
                                            IJHDataEntry2List ToolList = dataAccess.GetDataEntry2(ToolNumberAccessor, DNC_DATA_UNIT_SELECT.DNC_DATA_UNIT_SELECT_METRIC, false).GetChildList();

                                            //报警期限
                                            toolsInfo.warnLife = ToolList[10].GetPropertyValue(DNC_DATAENTRY_PROPKIND.DNC_DATAENTRY_PROPKIND_DATA).ToString();
                                            //刀具寿命目标值
                                            toolsInfo.targetLife = ToolList[11].GetPropertyValue(DNC_DATAENTRY_PROPKIND.DNC_DATAENTRY_PROPKIND_DATA).ToString();
                                            //Cur_Time使用时间
                                            toolsInfo.curTime = ToolList[12].GetPropertyValue(DNC_DATAENTRY_PROPKIND.DNC_DATAENTRY_PROPKIND_DATA).ToString();

                                            toolsList.Add(toolsInfo);
                                        }
                                    }
                                    //获取海德汉的刀具寿命信息
                                    responseBody.toolsInfo = JsonConvert.SerializeObject(toolsList.Distinct().ToList());
                                }
                            }
                            else
                            {
                                responseBody.msg = m_ControlState.ToString();
                                responseBody.result = false;
                                deviceList.Remove(hdhBody.MachineName);
                                machineList.Remove(hdhBody.MachineName);
                            }
                        }


                    }
                    catch (Exception opcex)
                    {
                        YG.Log.Instance.WriteLogAdd($"海德汉响应异常--->>" + opcex.Message);
                        AddList(DateTime.Now.ToString(), "POST", request.Url.ToString(), opcex.Message);
                        //发生异常,清空数组,重新连接
                        deviceList = new Dictionary<string, DNC_STATE>();
                        machineList = new Dictionary<string, JHMachineInProcess>();
                    }
                    finally {

                        AddList(DateTime.Now.ToString(), "POST", hdhBody.ServerUrl + ":响应数据:" + responseBody.toolsInfo, responseBody.result ? "OK" : "失败:" + m_ControlState != null ? m_ControlState.ToString() : "");

                        response.ContentType = "application/json;charset=UTF-8";
                        response.ContentEncoding = Encoding.UTF8;
                        response.AppendHeader("Content-Type", "application/json;charset=UTF-8");
                        string retJsonData = JsonConvert.SerializeObject(responseBody);

                        using (StreamWriter writer = new StreamWriter(response.OutputStream, Encoding.UTF8))
                        {
                            YG.Log.Instance.WriteLogAdd($"海德汉响应结果--->>{JsonConvert.SerializeObject(JsonConvert.SerializeObject(responseBody))}--->>{body}\r\n");
                            
                            writer.Write(JsonConvert.SerializeObject(responseBody));
                            writer.Close();
                            response.Close();
                        }
                    }


                }
            }
            else if (request.HttpMethod == "GET")
            {
                if (!request.Url.ToString().Contains("favicon"))
                {
                    string ip = request.QueryString["ip"];
                    string port = request.QueryString["port"];
                    string fun = request.QueryString["fun"];

                    AddList(DateTime.Now.ToString(), "GET", ip + port + fun, "OK");

                }
                response.Close();
            }
            
         
    }
 
        private DNC_STATE connect(string connectName)
        { 
            DNC_CNC_TYPE CncType ;

            IJHConnectionList connectionList = null;
            IJHConnection connection = null;
            try
            {
                JHMachineInProcess Machine = null;
                //第一次连接加入数组,以支持多台设备
                if (machineList == null || (machineList.Where(m => m.Key == connectName).Count() == 0))
                {
                    Machine = new JHMachineInProcess(); 
                    //DNC连接正常,加入数组 
                    machineList.Add(connectName, Machine); 
                    Thread.Sleep(20);
                }
                else
                {
                    //取对应设备 
                    Machine = machineList.Where(m => m.Key == connectName).FirstOrDefault().Value;
                }
                Machine.ConnectRequest(connectName);
                string sCurrentMachine = Machine.currentMachine;

                // Find out control type
                connectionList = Machine.ListConnections();
                for (int i = 0; i < connectionList.Count; i++)
                {
                    connection = connectionList[i];

                    if (connection.name == sCurrentMachine)
                    {
                        CncType = connection.cncType; 
                    }

                    if (connection != null)
                        Marshal.ReleaseComObject(connection);
                }
                return Machine.GetState();
            }
            catch (COMException cex)
            {
                return DNC_STATE.DNC_STATE_NOT_INITIALIZED;
            }
            catch (Exception ex)
            {
                return DNC_STATE.DNC_STATE_NOT_INITIALIZED;
            }
            finally
            {
                if (connectionList != null)
                    Marshal.ReleaseComObject(connectionList);
                if (connection != null)
                    Marshal.ReleaseComObject(connection);
            } 
        }
        private string GenPath(string part1, string part2)
        {
            string sFullPath = part1;
            switch (part2)
            {
                case ".":
                    break;
                case "..":
                    if (part1.EndsWith(@"\") && part1.Length > 5)
                        part1 = part1.Substring(0, part1.Length - 3);
                    int iLastFolderPos = part1.LastIndexOf(@"\");
                    if (iLastFolderPos >= 0)
                        sFullPath = part1.Substring(0, iLastFolderPos + 1);
                    break;
                default:
                    if (part1.EndsWith(@"\"))
                        sFullPath = part1 + part2;
                    else
                        sFullPath = part1 + @"\" + part2;
                    break;
            }
            return sFullPath;
        }

        public class Servlet
        {
            public virtual void onGet(System.Net.HttpListenerRequest request, System.Net.HttpListenerResponse response, string info) { }
            public virtual void onPost(System.Net.HttpListenerRequest request, System.Net.HttpListenerResponse response) { }

            public virtual void onCreate()
            {

            }
        }


        public void AddList(string dtime, string type, string url, string res)
        {
            this.Invoke(new Action(delegate ()
            {
                listView1.BeginUpdate();   //数据更新，UI暂时挂起，直到EndUpdate绘制控件，可以有效避免闪烁并大大提高加载速度
                ListViewItem lvi = new ListViewItem();
                lvi.Text = dtime;
                lvi.SubItems.Add(type);
                lvi.SubItems.Add(url);
                lvi.SubItems.Add(res);
                this.listView1.Items.Insert(0, lvi);
                if (this.listView1.Items.Count > 100)
                {
                    this.listView1.Items.Clear();
                }

                this.listView1.EndUpdate();  //结束数据处理，UI界面一次性绘制。}

            }));

        }


        public class MyServlet : Servlet
        {
            public override void onCreate()
            {
                base.onCreate();
            }

            public override void onGet(HttpListenerRequest request, HttpListenerResponse response, string info)
            {
                Console.WriteLine("GET:" + request.Url);


                byte[] buffer = Encoding.UTF8.GetBytes(info);
                //string sss = request.QueryString["ty"];
                System.IO.Stream output = response.OutputStream;
                output.Write(buffer, 0, buffer.Length);
                // You must close the output stream.
                output.Close();
                //listener.Stop();
            }

            public override void onPost(HttpListenerRequest request, HttpListenerResponse response)
            {
                Console.WriteLine("POST:" + request.Url);
                byte[] res = Encoding.UTF8.GetBytes("OK");
                response.OutputStream.Write(res, 0, res.Length);
            }
        }

    }
}
