using System;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Aitex.Core.UI.Control;
using MECF.Framework.Simulator.Core.Driver;
using Aitex.Core.Util;
using CyberX8_Core;
using Aitex.Core.RT.DataCenter;
using System.Linq;
using MECF.Framework.Common.DataCenter;
using Aitex.Core.RT.ConfigCenter;
using CyberX8_Simulator.Instances;
using System.Collections.Generic;

namespace CyberX8_Simulator.Devices
{
    public class SunWayEfemSimulator : SocketDeviceSimulator
    {
        private const string SCMD        = @"(?<=\:)(.*?)(?=\/)";
        private const string SFOUP       = @"(?<=P)(\d{1})(?=[\;\/])";
        private const string ACK         = "ACK";
        private readonly char[] delimiters = { ':', '/', '>', '|', ';' };
        private string[] _slotMap = new string[25];
        private string[] _slotDummy = new string[25];
        private PeriodicJob _HwThread;
        private bool _bCommReady;

        private bool _isDoorOpen;
        private bool _isLp1Placed;
        private bool _isLp2Placed;
        private bool _isLp3Placed;
        private bool _isLp1Clamped;
        private bool _isLp2Clamped;
        private bool _isLp3Clamped;
        private bool _isLP1Docked;
        private bool _isLP2Docked;
        private bool _isLP3Docked;
        public int WaferSize = 200;
        private int _speed = 20;
        private string _carrier1ID = "12345678";
        private string _carrier2ID = "12345678";
        private string _carrier3ID = "12345678";
        private List<int> _lpStationNumber; 
        private List<int> _dummyStationNumber; 
        public string SlotMap
        {
            get { return string.Join("", _slotMap); }
        }

        public bool _isVacuumError { get;  set; }
        public bool _isAirError { get;  set; }
        public bool _isFlowError { get;  set; }
        public bool _isLeak { get;  set; }
        public bool _isMaintain { get;  set; }
        public bool _isWaferPresent { get;  set; }
        public bool _isMaintainDoorOpen { get; private set; }


        public bool _isProtrude1 { get; set; }
        public bool _isProtrude2 { get; set; }
        public bool _isVAC { get; set; }
        public bool _isAIR { get; set; }

        private bool _isDoorOpen1;
        public bool IsDoorOpen1 { get { return _isDoorOpen1; } set { _isDoorOpen1 = value; SendLP1Data(); } }

        private bool _isDoorOpen2;
        public bool IsDoorOpen2 { get { return _isDoorOpen2; } set { _isDoorOpen2 = value;SendLP2Data(); } }

        private bool _isDoorOpen3;
        public bool IsDoorOpen3
        {
            get { return _isDoorOpen3; }
            set { _isDoorOpen3 = value; SendLP3Data(); }
        }
        public SunWayEfemSimulator() : base(1102, -1, "\r", ' ')
        {
            for (int i = 0; i < _slotMap.Length; i++)
                _slotMap[i] = "0";

            for(int i=0; i < _slotDummy.Length; i++)
            {
                _slotDummy[i]="0";
            }
            _HwThread = new PeriodicJob(5000, OnSendEvent, "EfemHardware", true);
            GetStationNumber();
        }

        private bool OnSendEvent()
        {
            if (IsConnected)
            {
                
            }
            return true;
        }
        private void GetStationNumber()
        {
            _lpStationNumber = new List<int>();
            _lpStationNumber.Add(SystemConfig.Instance.GetValue<int>("EFEM.LP1.Cassete200Station"));
            _lpStationNumber.Add(SystemConfig.Instance.GetValue<int>("EFEM.LP1.Cassete150Station"));
            _lpStationNumber.Add(SystemConfig.Instance.GetValue<int>("EFEM.LP1.Cassete100Station"));
            _lpStationNumber.Add(SystemConfig.Instance.GetValue<int>("EFEM.LP2.Cassete200Station"));
            _lpStationNumber.Add(SystemConfig.Instance.GetValue<int>("EFEM.LP2.Cassete150Station"));
            _lpStationNumber.Add(SystemConfig.Instance.GetValue<int>("EFEM.LP2.Cassete100Station"));
            _lpStationNumber.Add(SystemConfig.Instance.GetValue<int>("EFEM.LP3.Cassete200Station"));
            _lpStationNumber.Add(SystemConfig.Instance.GetValue<int>("EFEM.LP3.Cassete150Station"));
            _lpStationNumber.Add(SystemConfig.Instance.GetValue<int>("EFEM.LP3.Cassete100Station"));
            _dummyStationNumber = new List<int>();
            _dummyStationNumber.Add(SystemConfig.Instance.GetValue<int>("EFEM.Dummy1.Cassete200Station"));
            _dummyStationNumber.Add(SystemConfig.Instance.GetValue<int>("EFEM.Dummy1.Cassete150Station"));
            _dummyStationNumber.Add(SystemConfig.Instance.GetValue<int>("EFEM.Dummy1.Cassete100Station"));
            _dummyStationNumber.Add(SystemConfig.Instance.GetValue<int>("EFEM.Dummy2.Cassete200Station"));
            _dummyStationNumber.Add(SystemConfig.Instance.GetValue<int>("EFEM.Dummy2.Cassete150Station"));
            _dummyStationNumber.Add(SystemConfig.Instance.GetValue<int>("EFEM.Dummy2.Cassete100Station"));

        }
        protected override void ProcessUnsplitMessage(string str)
        {
            //OnWriteMessage(ack);

            // 处理INF
            OnWork(str);
        }
        internal void SetCassetteDoor(bool doorOpen)
        {
            _isMaintainDoorOpen = doorOpen;
            uint data = doorOpen ? (uint)0b0111111111000001110 : (uint)0b0111111111000001111;
            string msg = $"EVT:SIGSTAT/System/{data:X8}/00000000;";
            OnWriteMessage(msg);
        }

        internal void SetMaintain(bool maintain)
        {
            _isMaintain = maintain;
            uint data = maintain ? (uint)0b0111111111000011111 : (uint)0b0111111111000001111;
            string msg = $"EVT:SIGSTAT/System/{data:X8}/00000000;";
            OnWriteMessage(msg);
        }

        internal void SetProtrude1(bool protrude)
        {
            _isProtrude1 = protrude;
            uint data = protrude? (uint)0b0111111111000101111: (uint)0b0111111111000001111;
            string msg = $"EVT:SIGSTAT/System/{data:X8}/00000000;";
            OnWriteMessage(msg);
        }

        internal void SetProtrude2(bool protrude)
        {
            _isProtrude2 = protrude;
            uint data = protrude ? (uint)0b0111111111001001111 : (uint)0b0111111111000001111;
            string msg = $"EVT:SIGSTAT/System/{data:X8}/00000000;";
            OnWriteMessage(msg);
        }

        internal void SetVAC(bool VAC)
        {
            _isVAC = VAC;
            uint data = VAC ? (uint)0b0111111111000001101 : (uint)0b0111111111000001111;
            string msg = $"EVT:SIGSTAT/System/{data:X8}/00000000;";
            OnWriteMessage(msg);
        }

        internal void SetAIR(bool AIR)
        {
            _isAIR = AIR;
            uint data = AIR ? (uint)0b0111111111000001011 : (uint)0b0111111111000001111;
            string msg = $"EVT:SIGSTAT/System/{data:X8}/00000000;";
            OnWriteMessage(msg);
        }
        private void OnWork(string str)
        {
            string ack = "";
            if (str.StartsWith("RQ LOAD")) //查询手指是否带片
            {
                ack = "LOAD A OFF\n_RDY";
            }
            else if (str.StartsWith("RSR"))  //返回扫片结果
            {
                string[] strings = str.Split(' ').ToArray();
                int stationNumber = int.Parse(strings[1]);
                if (_lpStationNumber.Contains(stationNumber)) //LP
                {
                    string lpwafer = "";
                    foreach (var item in _slotMap)
                    {
                        lpwafer += $" {item}";
                    }
                    ack = "MAP" + lpwafer;
                }
                else if (_dummyStationNumber.Contains(stationNumber)) //dummy
                {
                    string dummywafer = "";
                    foreach (var item in _slotDummy)
                    {
                        dummywafer += $" {item}";
                    }
                    ack = "MAP" + dummywafer;
                }
            }
            else //默认回复
            {
                if (str.StartsWith("PICK") || str.StartsWith("PLACE") || str.StartsWith("MAP") || str.StartsWith("ALIGNER ALGN") || str.StartsWith("ALIGNER HOME"))
                {
                    Thread.Sleep((ushort)2200);
                }
                ack = "_RDY";
            }
            OnWriteMessage(ack);
            //// match basic
            //Match m1 = Regex.Match(strACK, SCMD);

            //// get mock delay time
            //string sBasic = m1.Groups[1].Value;

            //if (string.IsNullOrEmpty(sBasic))
            //    return;



            //EfemOperation op = EfemConstant.ToOperation(sBasic);
            //ushort millionSec = this.SimuOperationTime(op);

            //// delay
            ////await Task.Delay(millionSec);
            //Thread.Sleep(millionSec);

            //// build the INF string
            //string strINF = string.Empty;

            //switch (EfemConstant.ToOperation(strACK))
            //{
            //    case EfemOperation.GetWaferInfo:
            //        strINF = strACK.Replace(ACK, "INF");
            //        strINF = strINF.TrimEnd(';');
            //        string map1 = string.Join("", _slotMap);
            //        strINF += $"/{map1};";
            //        break;
            //    case EfemOperation.Home:
            //        int data1 = 0b011111111010100000;
            //        string s1 = $"EVT:SIGSTAT/LP1/00000000/00000003;\rEVT:SIGSTAT/LP2/0000000/00000003;\rEVT:SIGSTAT/LP3/000000/00000003;\rEVT:SIGSTAT/System/{data1}/00000;\r";

            //        strINF = s1 + strACK.Replace(ACK, "INF");
            //        SendSystemData();
            //        SendLP1Data();
            //        SendLP2Data();
            //        SendLP3Data();
            //        SendAlignData();
            //        OnWriteMessage(strACK.Replace(ACK, "INF"));
            //        return;
            //    case EfemOperation.Map:
            //        if(strACK.Contains("BF"))
            //        {
            //            string map = string.Join("", _slotDummy);
            //            string strEVT = strACK.Replace(ACK,"EVT");
            //            strEVT = strEVT.Replace("WAFSH","MAPDT");
            //            strEVT = strEVT.TrimEnd(';');
            //            string str = $"{strEVT}/{map};";
            //            OnWriteMessage(str);
            //        }
            //        else if (strACK.Contains("LP"))
            //        {
            //            string map = string.Join("", _slotMap);
            //            string strEVT = strACK.Replace(ACK, "EVT");
            //            strEVT = strEVT.Replace("WAFSH", "MAPDT");
            //            strEVT = strEVT.TrimEnd(';');
            //            string str = $"{strEVT}/{map};";
            //            OnWriteMessage(str);
            //        }
            //        strINF = strACK.Replace(ACK, "INF");
            //        break;
            //    case EfemOperation.Load:                  
            //            strINF = strACK.Replace(ACK, "INF"); 
            //        break;
            //    case EfemOperation.StateTrack:
            //        strINF = "INF:STATE/TRACK/NONE/NONE;";
            //        break;
            //    case EfemOperation.CarrierId:


            //        break;

            //    case EfemOperation.Size:

            //        break;
            //    case EfemOperation.Dock:
            //        Match mDock = Regex.Match(strACK, SFOUP);
            //        if (mDock.Success)
            //        {
            //            UpdateLocked(mDock.Groups[1].Value, true);
            //        }
            //        strINF = strACK.Replace(ACK, "INF");
            //        break;
            //    case EfemOperation.Undock:
            //        Match mUnDock = Regex.Match(strACK, SFOUP);
            //        if (mUnDock.Success)
            //        {
            //            UpdateLocked(mUnDock.Groups[1].Value, false);
            //        }
            //        strINF = strACK.Replace(ACK, "INF");
            //        break;
            //    case EfemOperation.Clamp:
            //        Match mClamp= Regex.Match(strACK, SFOUP);
            //        if (mClamp.Success)
            //        {
            //            UpdateClamped(mClamp.Groups[1].Value, true);
            //        }
            //        strINF = strACK.Replace(ACK, "INF");
            //        break;
            //    case EfemOperation.Unclamp:
            //        Match mUnClamp = Regex.Match(strACK, SFOUP);
            //        if (mUnClamp.Success)
            //        {
            //            UpdateClamped(mUnClamp.Groups[1].Value, false);
            //        }
            //        strINF = strACK.Replace(ACK, "INF");
            //        break;
            //    case EfemOperation.Speed:

            //        break;
            //    case EfemOperation.Align:
            //    case EfemOperation.Pick:
            //    case EfemOperation.Place:
            //    case EfemOperation.Orgsh:
            //    case EfemOperation.Light:
            //    case EfemOperation.SigStatus:
            //    default:
            //        strINF = strACK.Replace(ACK, "INF");
            //        break;
            //}

            //OnWriteMessage(strINF);

        }

        private void UpdateLocked(string lpNumber,bool locked)
        {
            if (lpNumber== "1")
            {
                _isLP1Docked = locked;
                SendLP1Data();
            }
            else if (lpNumber == "2")
            {
                _isLP2Docked = locked;
                SendLP2Data();
            }
            else if (lpNumber == "3")
            {
                _isLP3Docked = locked;
                SendLP3Data();
            }
        }

        private void UpdateClamped(string lpNumber, bool clamped)
        {
            if (lpNumber == "1")
            {
                _isLp1Clamped = clamped;
                SendLP1Data();
            }
            else if (lpNumber == "2")
            {
                _isLp2Clamped = clamped;
                SendLP2Data();
            }
            else if (lpNumber == "3")
            {
                _isLp3Clamped = clamped;
                SendLP3Data();
            }
        }

        private void SendLP1Data()
        {
            uint data = GetLP1Data1();

            string msg = $"EVT:SIGSTAT/LP1/{data:X8}/0000;";
            OnWriteMessage(msg);
        }

        private void SendLP2Data()
        {
            uint data = GetLP2Data1();

            string msg = $"EVT:SIGSTAT/LP2/{data:X8}/0000;";
            OnWriteMessage(msg);
        }

        private void SendLP3Data()
        {
            uint data = GetLP3Data1();

            string msg = $"EVT:SIGSTAT/LP3/{data:X8}/0000;";
            OnWriteMessage(msg);
        }

        private void SendAlignData()
        {
            string msg = $"EVT:ALIGN/ALN1/0;";
            OnWriteMessage(msg);
        }

        private void SendDummyMapData(string dummy)
        {
            string s2 = $"EVT:MAPDT/{dummy}/{_slotDummy};\r";
            OnWriteMessage(s2);
        }

        private void SendSystemData()
        {
            uint data = 0b0111111111000001111;

            string msg = $"EVT:SIGSTAT/System/{data:X8}/00000000;";
            OnWriteMessage(msg);
        }

        private ushort SimuOperationTime(EfemOperation op)
        {
            ushort sec = 0;
            switch (op)
            {
            case EfemOperation.Map:
            case EfemOperation.GetWaferInfo:
            case EfemOperation.Align:
                sec = 2200;
                break;
            case EfemOperation.Pick:
            case EfemOperation.Place:
            case EfemOperation.Orgsh:
                sec = 2200;
                break;
            case EfemOperation.Light:
            case EfemOperation.SigStatus:
                sec = 0;
                break;
            default:
                sec = 100;
                break;
            }
            return sec;
        }

        public void PlaceCarrier1()
        {
            _isLp1Placed = true;
            SendLP1Data();
        }

        public void RemoveCarrier1()
        {
            _isLp1Placed = false;
            SendLP1Data();
        }

        public void PlaceCarrier2()
        {
            _isLp2Placed = true;
            SendLP2Data();
        }

        public void RemoveCarrier2()
        {
            _isLp2Placed = false;
            SendLP2Data();
        }
        public void PlaceCarrier3()
        {
            _isLp3Placed = true;
            SendLP3Data();
        }

        public void RemoveCarrier3()
        {
            _isLp3Placed = false;
            SendLP3Data();
        }
        public void ClearWafer()
        {
            for (int i = 0; i < _slotMap.Length; i++)
            {
                _slotMap[i] = "0";
            }
            for (int i = 0; i < _slotDummy.Length; i++)
            {
                _slotDummy[i] = "0";
            }

        }

        public void SetAllWafer()
        {
            for (int i = 0; i < _slotMap.Length; i++)
            {
                _slotMap[i] = "1";
            }
        }

        public void RandomWafer()
        {
            Random _rd = new Random();
            for (int i = 0; i < _slotMap.Length; i++)
            {
                //_slotMap[i] = (i % 9).ToString();
                _slotMap[i]= _rd.Next(0, 10) < 6 ? "0" : "1";
            }
        }

        public void RandomDummyWafer()
        {
            Random _rdDummy = new Random();
            for (int i = 0; i < _slotDummy.Length; i++)
            {
                _slotDummy[i] = _rdDummy.Next(0, 10) < 6 ? "0" : "1";
            }
        }

        private uint GetLP1Data1()
        {
            uint data1 = 0x0u;

            data1 |= (_isLp1Placed  ? 0x00000001u : 0x0);
            data1 |= (_isLp1Clamped ? 0x00000002u : 0x0);
            data1 |= (_isLP1Docked ? 0x00000004u : 0x0);
            data1 |= (_isDoorOpen1 ? 0x00000020u : 0x0);
            return data1;
        }

 

        private uint GetLP2Data1()
        {
            uint data1 = 0x0u;

            data1 |= (_isLp2Placed ? 0x00000001u : 0x0);
            data1 |= (_isLp2Clamped ? 0x00000002u : 0x0);
            data1 |= (_isLP2Docked ? 0x00000004u : 0x0);
            data1 |= (_isDoorOpen2 ? 0x00000020u : 0x0);

            return data1;
        }
        private uint GetLP3Data1()
        {
            uint data1 = 0x0u;

            data1 |= (_isLp3Placed ? 0x00000001u : 0x0);
            data1 |= (_isLp3Clamped ? 0x00000002u : 0x0);
            data1 |= (_isLP3Docked ? 0x00000004u : 0x0);
            data1 |= (_isDoorOpen3 ? 0x00000020u : 0x0);

            return data1;
        }

    }
}