using HslCommunication;
using HslCommunication.Profinet.Siemens;
using MvCamCtrl.NET;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using System.Windows.Forms;

namespace WaferAlignment
{
    public class Camera
    {
        private bool _isConnected = false;

        public bool IsConnected
        {
            get { return _isConnected; }
            set { _isConnected = value; }
        }

        private bool _isStarted = false;

        public bool IsStarted
        {
            get { return _isStarted; }
            set { _isStarted = value; }
        }
        public event Action<Bitmap> OutputImageEvent;
        private float expo = 12;
        private uint imgHeight = 4000;
        private MyCamera _dev;
        private CancellationTokenSource _startAcqToken;
        private CancellationTokenSource _stopAcqToken;
        private Task _imageAcquisitionTask;
        private static Object BufForDriverLock = new Object();
        private IntPtr m_BufForDriver = IntPtr.Zero;
        private UInt32 m_nBufSizeForDriver = 0;
        private MyCamera.MV_FRAME_OUT_INFO_EX m_stFrameInfo = new MyCamera.MV_FRAME_OUT_INFO_EX();
        [DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
        public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);
        public void Connect()
        {
            IntPtr devIPtr;
            try
            {
                MyCamera.MV_CC_DEVICE_INFO_LIST m_stDeviceList = new MyCamera.MV_CC_DEVICE_INFO_LIST();
                MyCamera.MV_CC_EnumDevices_NET(MyCamera.MV_GIGE_DEVICE, ref m_stDeviceList);
                if (m_stDeviceList.nDeviceNum > 0)
                {
                    devIPtr = m_stDeviceList.pDeviceInfo[0];
                }
                else
                {
                    throw new Exception("未找到相机连接！");
                }
            }
            catch (Exception ex)
            {
                throw new Exception("相机查找失败！");
            }

            MyCamera.MV_CC_DEVICE_INFO devInfo = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(devIPtr, typeof(MyCamera.MV_CC_DEVICE_INFO));
            if (_dev != null)
            {
                throw new Exception("相机连接失败，原因:该设备实例已存在");
            }
            _dev = new MyCamera();
            if (_dev == null)
            {
                throw new Exception("相机连接失败，原因:该设备实例化失败");
            }
            int status = _dev.MV_CC_CreateDevice_NET(ref devInfo);
            if (status != MyCamera.MV_OK)
            {
                throw new Exception(String.Format("相机连接失败，原因:设备创建失败"));
            }
            status = _dev.MV_CC_OpenDevice_NET();
            if (status != MyCamera.MV_OK)
            {
                throw new Exception(String.Format("相机连接失败，原因:设备启动失败"));
            }
            int nPacketSize = _dev.MV_CC_GetOptimalPacketSize_NET();
            if (nPacketSize > 0)
            {
                status = _dev.MV_CC_SetIntValue_NET("GevSCPSPacketSize", (uint)nPacketSize);
                if (status != MyCamera.MV_OK)
                {
                    throw new Exception(String.Format("相机连接失败，原因:获取本地包大小失败"));
                }
            }
            else
            {
                throw new Exception(String.Format("相机连接失败，原因:获取本地包大小失败"));
            }

            // 连续采集
            int nRet;
            nRet = _dev.MV_CC_SetEnumValue_NET("AcquisitionMode", (uint)MyCamera.MV_CAM_ACQUISITION_MODE.MV_ACQ_MODE_CONTINUOUS);
            // 手动曝光
            nRet = _dev.MV_CC_SetEnumValue_NET("ExposureAuto", (uint)MyCamera.MV_CAM_EXPOSURE_AUTO_MODE.MV_EXPOSURE_AUTO_MODE_OFF);
            // 行触发关闭
            //nRet = _dev.MV_CC_SetEnumValue_NET("TriggerSelector", 9);
            //nRet = _dev.MV_CC_SetEnumValue_NET("TriggerMode", (uint)MyCamera.MV_CAM_TRIGGER_MODE.MV_TRIGGER_MODE_OFF);
            // 帧触发打开,软件触发
            nRet = _dev.MV_CC_SetEnumValue_NET("TriggerSelector", 6);
            nRet = _dev.MV_CC_SetEnumValue_NET("TriggerMode", (uint)MyCamera.MV_CAM_TRIGGER_MODE.MV_TRIGGER_MODE_ON);
            nRet = _dev.MV_CC_SetEnumValue_NET("TriggerSource", (uint)MyCamera.MV_CAM_TRIGGER_SOURCE.MV_TRIGGER_SOURCE_COUNTER0);
            nRet = _dev.MV_CC_SetFloatValue_NET("ExposureTime", expo);
            //nRet = _dev.MV_CC_SetIntValue_NET("Width", 1600);
            //nRet = _dev.MV_CC_SetIntValue_NET("Height", 1200);
            //nRet = _dev.MV_CC_SetIntValue_NET("OffsetX", 1760);
            //nRet = _dev.MV_CC_SetIntValue_NET("OffsetY", 1448);

            _isConnected = true;
        }

        public void Disconnect()
        {
            if (_dev != null)
            {
                // 关闭设备
                _dev.MV_CC_CloseDevice_NET();
                _dev.MV_CC_DestroyDevice_NET();
                _dev = null;
                _isConnected = false;
            }
        }

        public void Start()
        {
            if (_dev == null)
            {
                _isStarted = false;
                MessageBox.Show("相机启动失败，相机未连接");
                return;
            }
            ImageAcquisitionStart();
            m_stFrameInfo.nFrameLen = 0;//取流之前先清除帧长度
            m_stFrameInfo.enPixelType = MyCamera.MvGvspPixelType.PixelType_Gvsp_Undefined;
            _dev.MV_CC_SetEnumValue_NET("TriggerSource", (uint)MyCamera.MV_CAM_TRIGGER_SOURCE.MV_TRIGGER_SOURCE_COUNTER0);
            int nRet = _dev.MV_CC_StartGrabbing_NET();
            if (MyCamera.MV_OK != nRet)
            {
                ImageAcquisitionStop();
                _isStarted = false;
                MessageBox.Show("相机启动失败，清除缓存区失败");
                return;
            }
            _isStarted = true;
        }
        public void SoftwareGrab()
        {
            _dev.MV_CC_StopGrabbing_NET();
            _dev.MV_CC_SetEnumValue_NET("TriggerSource", (uint)MyCamera.MV_CAM_TRIGGER_SOURCE.MV_TRIGGER_SOURCE_SOFTWARE);
            _dev.MV_CC_StartGrabbing_NET();
            _dev.MV_CC_TriggerSoftwareExecute_NET();
        }

        public void Stop()
        {
            if (_dev == null)
            {
                _isStarted = false;
                MessageBox.Show("相机停止失败，相机未连接");
                return;
            }
            ImageAcquisitionStop();
            int nRet = _dev.MV_CC_StopGrabbing_NET();
            if (nRet != MyCamera.MV_OK)
            {
                _isStarted = false;
                MessageBox.Show("相机停止失败");
                return;
            }
            _isStarted = false;

        }

        private void ImageAcquisitionStart()
        {
            _startAcqToken = new CancellationTokenSource();
            _imageAcquisitionTask = new Task(() => ImageAcquisitionProcess(), _startAcqToken.Token);
            _imageAcquisitionTask.Start();
        }
        private void ImageAcquisitionStop()
        {
            try
            {
                _startAcqToken.Cancel();
                Thread.Sleep(200);
                _imageAcquisitionTask.Wait(_stopAcqToken.Token);
                _imageAcquisitionTask.Dispose();
            }
            catch (OperationCanceledException ex)
            {
                _imageAcquisitionTask.Dispose();
            }
        }
        private void ImageAcquisitionProcess()
        {
            _stopAcqToken = new CancellationTokenSource();
            MyCamera.MV_FRAME_OUT stFrameInfo = new MyCamera.MV_FRAME_OUT();
            while (true)
            {
                if (_startAcqToken.IsCancellationRequested)
                    break;
                int nRet = _dev.MV_CC_GetImageBuffer_NET(ref stFrameInfo, 1000);
                Console.WriteLine("-----------------------Get Image Buffer:" + "Width[" + Convert.ToString(stFrameInfo.stFrameInfo.nWidth) + "] , Height[" + Convert.ToString(stFrameInfo.stFrameInfo.nHeight)
           + "] ,Trigger[" + Convert.ToString(stFrameInfo.stFrameInfo.nTriggerIndex) + "], FrameNum[" + Convert.ToString(stFrameInfo.stFrameInfo.nFrameNum) + "]");
                      
                if (nRet == MyCamera.MV_OK)
                {
                    lock (BufForDriverLock)
                    {
                        if (m_BufForDriver == IntPtr.Zero || stFrameInfo.stFrameInfo.nFrameLen > m_nBufSizeForDriver)
                        {
                            if (m_BufForDriver != IntPtr.Zero)
                            {
                                Marshal.Release(m_BufForDriver);
                                m_BufForDriver = IntPtr.Zero;
                            }

                            m_BufForDriver = Marshal.AllocHGlobal((Int32)stFrameInfo.stFrameInfo.nFrameLen);
                            if (m_BufForDriver == IntPtr.Zero)
                            {
                                return;
                            }
                            m_nBufSizeForDriver = stFrameInfo.stFrameInfo.nFrameLen;
                        }

                        m_stFrameInfo = stFrameInfo.stFrameInfo;
                        CopyMemory(m_BufForDriver, stFrameInfo.pBufAddr, stFrameInfo.stFrameInfo.nFrameLen);
                    }

                    if (RemoveCustomPixelFormats(stFrameInfo.stFrameInfo.enPixelType))
                    {
                        _dev.MV_CC_FreeImageBuffer_NET(ref stFrameInfo);
                        continue;
                    }
                    //从缓存区获取图片
                    IntPtr pTemp = IntPtr.Zero;
                    MyCamera.MvGvspPixelType enDstPixelType = MyCamera.MvGvspPixelType.PixelType_Gvsp_Undefined;
                    if (m_stFrameInfo.enPixelType == MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8)
                    {
                        pTemp = m_BufForDriver;
                        enDstPixelType = m_stFrameInfo.enPixelType;
                    }
                    else
                    {
                        //ErrorMsgEvent(DeviceName + " -> 图像格式错误");
                    }

                    _dev.MV_CC_FreeImageBuffer_NET(ref stFrameInfo);

                    //************************Mono8 转 Bitmap*******************************
                    Bitmap bmp = new Bitmap(m_stFrameInfo.nWidth, m_stFrameInfo.nHeight, m_stFrameInfo.nWidth * 1, PixelFormat.Format8bppIndexed, pTemp);
                    ColorPalette cp = bmp.Palette;

                    for (int i = 0; i < 256; i++)
                    {
                        cp.Entries[i] = Color.FromArgb(i, i, i);
                    }
                    bmp.Palette = cp;
                    OutputImageEvent(bmp);
                }
                else
                {
                    Thread.Sleep(10);
                }
            }
            _stopAcqToken.Cancel();
        }
        private bool RemoveCustomPixelFormats(MyCamera.MvGvspPixelType enPixelFormat)
        {
            Int32 nResult = ((int)enPixelFormat) & (unchecked((Int32)0x80000000));
            if (0x80000000 == nResult)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        //public Bitmap Trigger()
        //{
        //    if (_dev == null)
        //    {
        //        throw new Exception(String.Format("相机触发失败，原因:该设备未连接"));
        //    }
        //    _dev.MV_CC_SetEnumValue_NET("TriggerSelector", 6);
        //    int nRet = _dev.MV_CC_SetCommandValue_NET("TriggerSoftware");
        //    if (MyCamera.MV_OK != nRet)
        //    {
        //        throw new Exception(String.Format("相机触发失败"));
        //    }

        //    MyCamera.MV_FRAME_OUT stFrameInfo = new MyCamera.MV_FRAME_OUT();
        //    nRet = _dev.MV_CC_GetImageBuffer_NET(ref stFrameInfo, 1000);
        //    if (nRet == MyCamera.MV_OK)
        //    {
        //        lock (BufForDriverLock)
        //        {
        //            if (m_BufForDriver == IntPtr.Zero || stFrameInfo.stFrameInfo.nFrameLen > m_nBufSizeForDriver)
        //            {
        //                if (m_BufForDriver != IntPtr.Zero)
        //                {
        //                    Marshal.Release(m_BufForDriver);
        //                    m_BufForDriver = IntPtr.Zero;
        //                }

        //                m_BufForDriver = Marshal.AllocHGlobal((Int32)stFrameInfo.stFrameInfo.nFrameLen);
        //                if (m_BufForDriver == IntPtr.Zero)
        //                {
        //                    return null;
        //                }
        //                m_nBufSizeForDriver = stFrameInfo.stFrameInfo.nFrameLen;
        //            }

        //            m_stFrameInfo = stFrameInfo.stFrameInfo;
        //            CopyMemory(m_BufForDriver, stFrameInfo.pBufAddr, stFrameInfo.stFrameInfo.nFrameLen);
        //        }

        //        if (RemoveCustomPixelFormats(stFrameInfo.stFrameInfo.enPixelType))
        //        {
        //            _dev.MV_CC_FreeImageBuffer_NET(ref stFrameInfo);
        //            return null;
        //        }
        //        //从缓存区获取图片
        //        IntPtr pTemp = IntPtr.Zero;
        //        MyCamera.MvGvspPixelType enDstPixelType = MyCamera.MvGvspPixelType.PixelType_Gvsp_Undefined;
        //        if (m_stFrameInfo.enPixelType == MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8)
        //        {
        //            pTemp = m_BufForDriver;
        //            enDstPixelType = m_stFrameInfo.enPixelType;
        //        }

        //        _dev.MV_CC_FreeImageBuffer_NET(ref stFrameInfo);

        //        //************************Mono8 转 Bitmap*******************************
        //        Bitmap bmp = new Bitmap(m_stFrameInfo.nWidth, m_stFrameInfo.nHeight, m_stFrameInfo.nWidth * 1, PixelFormat.Format8bppIndexed, pTemp);
        //        ColorPalette cp = bmp.Palette;
        //        for (int i = 0; i < 256; i++)
        //        {
        //            cp.Entries[i] = Color.FromArgb(i, i, i);
        //        }
        //        bmp.Palette = cp;
        //        return bmp;
        //    }
        //    else
        //    {
        //        return null;
        //    }

        //}

        //private bool RemoveCustomPixelFormats(MyCamera.MvGvspPixelType enPixelFormat)
        //{
        //    Int32 nResult = ((int)enPixelFormat) & (unchecked((Int32)0x80000000));
        //    if (0x80000000 == nResult)
        //    {
        //        return true;
        //    }
        //    else
        //    {
        //        return false;
        //    }
        //}
    }

    public class SiemensS7
    {
        private SiemensS7Net _s7;
        private string _ip;
        public bool OK { get; private set; }
        private System.Timers.Timer _reconnectTimer;

        public SiemensS7(string ip)
        {
            OK = false;
            _ip = ip;

            _reconnectTimer = new System.Timers.Timer(5000); // 设置定时器为5秒
            _reconnectTimer.Elapsed += ReconnectTimerElapsed;
            _reconnectTimer.AutoReset = true;
        }
        //public void Connect()
        //{
        //    _s7 = new SiemensS7Net(SiemensPLCS.S1200);
        //    _s7.IpAddress = _ip;
        //    _s7.Port = 102;
        //    OperateResult operateResult = _s7.ConnectServer();
        //    if (!operateResult.IsSuccess)
        //    {
        //        throw new Exception(string.Format("Siemens S7 S1200客户端连接失败"));
        //    }
        //}


        public void Connect()
        {
            _s7 = new SiemensS7Net(SiemensPLCS.S1200);
            _s7.IpAddress = _ip;
            _s7.Port = 102;
            TryConnect();
        }

        private void TryConnect()
        {

            OperateResult operateResult = _s7.ConnectServer();
            if (!operateResult.IsSuccess)
            {
                OK = false;
                Console.WriteLine("Siemens S7 S1200客户端连接失败，5秒后重试...");
                _reconnectTimer.Start(); // 启动定时器
            }
            else
            {
                OK = true;
                Console.WriteLine("Siemens S7 S1200客户端连接成功");
                _reconnectTimer.Stop(); // 停止定时器
            }
        }

        private void ReconnectTimerElapsed(object sender, ElapsedEventArgs e)
        {
            Console.WriteLine("尝试重新连接...");
            TryConnect();
        }
        public void Disconnect()
        {
            if (_s7 == null)
            {
                throw new Exception(string.Format("Siemens S7 S1200通信未连接"));
            }
            OperateResult operateResult = _s7.ConnectClose();
            if (!operateResult.IsSuccess)
            {
                throw new Exception(string.Format("Siemens S7 S1200客户端断开失败"));
            }
        }
        public bool GetValue(string address, out bool value)
        {
            if (_s7 == null)
            {
                throw new Exception(string.Format("Siemens S7 S1200通信未连接"));
            }
            OperateResult<bool> boolResult = _s7.ReadBool(address);
            if (boolResult.IsSuccess)
            {
                value = boolResult.Content;
                return true;
            }
            else
            {
                value = false;
                return false;
            }
        }
        public void SetValue(string address, bool value)
        {
            if (_s7 == null)
            {
                throw new Exception(string.Format("Siemens S7 S1200通信未连接"));
            }
            if (!_s7.Write(address, value).IsSuccess)
            {
                throw new Exception(string.Format("Siemens S7 S1500客户端发送数据失败"));
            }
        }

        public void SetValue(string address, int value)
        {
            if (_s7 == null)
            {
                throw new Exception(string.Format("Siemens S7 S1200通信未连接"));
            }
            if (!_s7.Write(address, value).IsSuccess)
            {
                throw new Exception(string.Format("Siemens S7 S1500客户端发送数据失败"));
            }
        }

        public void SetValue(string address, uint value)
        {
            if (_s7 == null)
            {
                throw new Exception(string.Format("Siemens S7 S1200通信未连接"));
            }
            if (!_s7.Write(address, value).IsSuccess)
            {
                throw new Exception(string.Format("Siemens S7 S1500客户端发送数据失败"));
            }
        }

        public void SetValue(string address, short value)
        {
            if (_s7 == null)
            {
                throw new Exception(string.Format("Siemens S7 S1200通信未连接"));
            }
            if (!_s7.Write(address, value).IsSuccess)
            {
                throw new Exception(string.Format("Siemens S7 S1500客户端发送数据失败"));
            }
        }
        public void SetValue(string address, ushort value)
        {
            if (_s7 == null)
            {
                throw new Exception(string.Format("Siemens S7 S1200通信未连接"));
            }
            if (!_s7.Write(address, value).IsSuccess)
            {
                throw new Exception(string.Format("Siemens S7 S1500客户端发送数据失败"));
            }
        }
        public void SetValue(string address, float value)
        {
            if (_s7 == null)
            {
                throw new Exception(string.Format("Siemens S7 S1200通信未连接"));
            }
            if (!_s7.Write(address, value).IsSuccess)
            {
                throw new Exception(string.Format("Siemens S7 S1500客户端发送数据失败"));
            }
        }
    }
}
