using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using System.Web.UI.WebControls.WebParts;
using ProductionControl.Utils;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Rebar;

namespace ProductionControl.Device
{
    internal class SmallAxis
    {
        #region 导入C函数
#if (!DEBUG)
        const string dllName = "PMSOpticalDll.dll";
#else
        const string dllName = "PMSOpticalDlld.dll";
#endif

        [DllImport(dllName, CharSet = CharSet.Ansi, EntryPoint = "PMSOptical_OpenSocket", CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr PMSOptical_OpenSocket(string ip, int nPort);

        [DllImport(dllName, CharSet = CharSet.Ansi, EntryPoint = "PMSOptical_OpenComm", CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr PMSOptical_OpenComm(string comname, int nBaud);

        [DllImport(dllName, CharSet = CharSet.Ansi, EntryPoint = "PMSOptical_IsOpened", CallingConvention = CallingConvention.Cdecl)]
        public static extern bool PMSOptical_IsOpened(IntPtr ptr, ref bool bIsOpened);

        [DllImport(dllName, CharSet = CharSet.Ansi, EntryPoint = "PMSOptical_Close", CallingConvention = CallingConvention.Cdecl)]
        public static extern bool PMSOptical_Close(ref IntPtr ptr);

        [DllImport(dllName, CharSet = CharSet.Ansi, EntryPoint = "PMSOptical_GoHome", CallingConvention = CallingConvention.Cdecl)]
        public static extern bool PMSOptical_GoHome(IntPtr ptr);

        [DllImport(dllName, CharSet = CharSet.Ansi, EntryPoint = "PMSOptical_IsHomed", CallingConvention = CallingConvention.Cdecl)]
        public static extern bool PMSOptical_IsHomed(IntPtr ptr, ref bool bIsHomed);

        [DllImport(dllName, CharSet = CharSet.Ansi, EntryPoint = "PMSOptical_MoveTo", CallingConvention = CallingConvention.Cdecl)]
        public static extern bool PMSOptical_MoveTo(IntPtr ptr, int nPulse);

        [DllImport(dllName, CharSet = CharSet.Ansi, EntryPoint = "PMSOptical_Stop", CallingConvention = CallingConvention.Cdecl)]
        public static extern bool PMSOptical_Stop(IntPtr ptr);

        [DllImport(dllName, CharSet = CharSet.Ansi, EntryPoint = "PMSOptical_JogStart", CallingConvention = CallingConvention.Cdecl)]
        public static extern bool PMSOptical_JogStart(IntPtr ptr, int nJogSpeed);

        [DllImport(dllName, CharSet = CharSet.Ansi, EntryPoint = "PMSOptical_JogStop", CallingConvention = CallingConvention.Cdecl)]
        public static extern bool PMSOptical_JogStop(IntPtr ptr);

        [DllImport(dllName, CharSet = CharSet.Ansi, EntryPoint = "PMSOptical_GetPos", CallingConvention = CallingConvention.Cdecl)]
        public static extern bool PMSOptical_GetPos(IntPtr ptr, ref int nCurPluse);

        [DllImport(dllName, CharSet = CharSet.Ansi, EntryPoint = "PMSOptical_GetMaxPos", CallingConvention = CallingConvention.Cdecl)]
        public static extern bool PMSOptical_GetMaxPos(IntPtr ptr, ref int nMaxPluse);

        [DllImport(dllName, CharSet = CharSet.Ansi, EntryPoint = "PMSOptical_GetStatus", CallingConvention = CallingConvention.Cdecl)]
        public static extern bool PMSOptical_GetStatus(IntPtr ptr, ref int nStatus);

        [DllImport(dllName, CharSet = CharSet.Ansi, EntryPoint = "PMSOptical_WaitForOpticalFinished", CallingConvention = CallingConvention.Cdecl)]
        public static extern void PMSOptical_WaitForOpticalFinished(IntPtr ptr, int nTimeOut);
        #endregion

        public Action<int, string> log;
        public Action<int, int> PPUChangeEvent;
        public Action<bool> StateChangeEvent;
        /// <summary>
        /// 最大倍数总的脉冲数
        /// </summary>
        public int MaxPPU { get; private set; }
        /// <summary>
        /// 是否打开设备成功
        /// </summary>
        public bool IsInit
        {
            get
            {
                if (pHandle == IntPtr.Zero)
                    return false;

                bool bIsOpened = false;
                PMSOptical_IsOpened(pHandle, ref bIsOpened);
                return bIsOpened;
            }
        }

        private System.Timers.Timer timer = new System.Timers.Timer();
        private IntPtr pHandle;

        private int prePPU;
        private bool preState;
        public SmallAxis(string comName,int baud)
        {
            pHandle = PMSOptical_OpenComm(comName, baud);
        }
        public void start()
        {
            //获取回零状态并状态栏显示
            bool bIsHomed = false;
            PMSOptical_IsHomed(pHandle, ref bIsHomed);
            if (!bIsHomed)
            {
                Thread.Sleep(100);
                PMSOptical_WaitForOpticalFinished(pHandle, 10000);
                PMSOptical_IsHomed(pHandle, ref bIsHomed);
                if (!bIsHomed)
                    throw new Exception("镜头电机复位失败！");
            }

            prePPU = 0;
            preState= false;
            this.getCurrPPU();
            this.isMoving();
            // 
            timer.Elapsed += Timer_Elapsed;
            timer.Interval = 1000;
            timer.Enabled = true;
        }
        public void stop()
        {
            if (IsInit) return;

            timer.Elapsed -= Timer_Elapsed;
            Thread.Sleep(200); 
            PMSOptical_Close(ref pHandle);
        }
        private void Timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            if (!IsInit) return;

            getCurrPPU();
            isMoving();
        }
        public bool home(bool await=false)
        {
            if (!IsInit) return false;

            PMSOptical_GoHome(pHandle);
            if (await)
            {
                PMSOptical_WaitForOpticalFinished(pHandle, 10000);
                //判断是否回零并设置按钮状态
                bool bIsHomed = false;
                PMSOptical_IsHomed(pHandle, ref bIsHomed);
                if (!bIsHomed)
                    return false;

                getCurrPPU();
            }

            return true;
        }
        public void gotoPos(int ppu,bool await=true)
        {
            if (!IsInit) return;
            PMSOptical_MoveTo(pHandle, ppu);
            if (await)
            {
                PMSOptical_WaitForOpticalFinished(pHandle, 10000); 
                getCurrPPU();
            }
        }

        public bool isMoving()
        {
            if (!IsInit)
                return false;

            int nStatus = 1;  //注意，这里建议nStatus初始化为1 //返回0为运动状态，1为停止状态，2为初始化失败    
            Thread.Sleep(20);
            //获取状态并刷新界面
            PMSOptical_GetStatus(pHandle, ref nStatus);
            bool state = 0 == nStatus;
            if (preState != state)
            {
                StateChangeEvent?.Invoke(state);
                preState = state;
            }
            return state;
        }
        //获取最大脉冲
        public int getMaxPPU()
        { 
            if (!IsInit)
                return -1; 
            
            int nMaxPos = 0;
            PMSOptical_GetMaxPos(pHandle, ref nMaxPos);
            return nMaxPos;
        }
        //获取当前脉冲
        public int getCurrPPU()
        {
            if (!IsInit)
                return -1;

            int nCurPos = 0;
            PMSOptical_GetPos(pHandle, ref nCurPos);
            if (prePPU != nCurPos)
            {
                PPUChangeEvent?.Invoke(prePPU, nCurPos); 
                prePPU = nCurPos;
            }
            return nCurPos;
        }
        private byte[] subBuff(byte[] buff, int start, int length)
        {
            byte[] res = new byte[length];
            for (int i = start; i < buff.Length && i < start + length; i++)
                res[i - start] = buff[i];
            return res;
        }
    }
}
