using System;
using System.Collections.Generic;
using System.Text;
using WCS.Data;
using System.Linq;
using WCS.Data.Models;
using SqlSugar;
using System.Threading;
using WCS.PLC.Model.Equipment;
namespace WCS.PLC
{
    public enum RgvPosEnum
    {
        一号工位 = 1,
        二号工位 = 2,
    }
    public class WaitExecInfo
    {
        /// 
        /// 预执行任务号
        /// 
        public int WaitExecTaskNo { get; set; }
        /// 
        /// 预执行上料点
        /// 
        public string WaitExecOnMatPosNo { get; set; }
        /// 
        /// 预执行下料点
        /// 
        public string WaitExecUpMatPosNo { get; set; }
        public bool IsNotEmpty()
        {
            if (WaitExecTaskNo > 0 &&
               (string.IsNullOrWhiteSpace(WaitExecOnMatPosNo) == false) &&
               (string.IsNullOrWhiteSpace(WaitExecUpMatPosNo) == false))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        public void SetInfo(int waiteExecTaskNo, string waitExecOnMatPosNo, string waitExecUpMatPosNo)
        {
            WaitExecTaskNo = waiteExecTaskNo;
            WaitExecOnMatPosNo = waitExecOnMatPosNo;
            WaitExecUpMatPosNo = waitExecUpMatPosNo;
        }
        public void Clear()
        {
            WaitExecTaskNo = 0;
            WaitExecOnMatPosNo = string.Empty;
            WaitExecUpMatPosNo = string.Empty;
        }
    }
    public abstract class Base_Rgv : Base_EquPlc
    {
        /// 
        /// 预执行信息
        /// 
        protected WaitExecInfo WaitExecTask = new WaitExecInfo();
        #region Constructor
        public Base_Rgv() : base() { }
        #endregion;
        #region 属性 
        /// 
        /// RGV当前位置
        /// 
        protected string RgvCurrentSition
        {
            get
            {
                //RGV当前地址
                string curPosNo = string.Empty;
                if (Rgv.DB521_ToSition_1) curPosNo = Rgv.DB521_DestPosition_1.ToString();
                else if (Rgv.DB521_ToSition_2) curPosNo = Rgv.DB521_DestPosition_2.ToString();
                if (string.IsNullOrWhiteSpace(curPosNo))
                {
                    var tempList = Current.WCS_RGVOutInInfoSet.Where(v => v.RGVOUTIN_RGVNO == PlcName).ToList();
                    curPosNo = tempList[0].RGVOUTIN_CONVNO;
                }
                return curPosNo;
            }
        }
        protected PLC RgvPlc
        {
            get
            {
                return WCS_PLCItem.Plc;
            }
        }
        protected WCS_EQUIPMENTINFO RgvData
        {
            get
            {
                return WCS_PLCItem.WCS_EquipmentInfoSet[0];
            }
        }
        public RGVSignal Rgv
        {
            get
            {
                return WCS_PLCItem.WCS_EquipmentInfoSet[0].EquSignal_Rgv;
            }
        }
        /// 
        /// RGV上下料列表
        /// 
        protected List RGVOnUpPosList
        {
            get
            {
                var tempList = Current.WCS_RGVOutInInfoSet.Where(v => v.RGVOUTIN_RGVNO == PlcName).ToList();
                var curItem = tempList.FirstOrDefault(v => v.RGVOUTIN_CONVNO == RgvCurrentSition);
                if (curItem != null)
                {
                    foreach (var item in tempList)
                    {
                        int difference = item.RGVOUTIN_SEQUENCE - curItem.RGVOUTIN_SEQUENCE;
                        item.RGVCURRENT_SEQUENCE = Math.Abs(difference);
                    }
                }
                return tempList.OrderBy(v => v.RGVCURRENT_SEQUENCE).ToList();
            }
        }
        /// 
        /// RGV上料点列表
        /// 
        protected virtual List RGVOnPosList
        {
            get
            {
                var _onPosList = RGVOnUpPosList.Where(v => v.RGVOUTIN_ISSTOP == false && (v.RGVOUTIN_OUTINTYPE == "OnMat" || v.RGVOUTIN_OUTINTYPE == "OnUpMat")).ToList();
                return _onPosList;
            }
        }
        /// 
        /// RGV下料点列表
        /// 
        protected virtual List RGVUpPosList
        {
            get
            {
                var _upPosList = RGVOnUpPosList.Where(v => v.RGVOUTIN_ISSTOP == false && (v.RGVOUTIN_OUTINTYPE == "UpMat" || v.RGVOUTIN_OUTINTYPE == "OnUpMat")).ToList();
                return _upPosList;
            }
        }
        #endregion;
        #region 方法
        /// 
        /// 写入任务到穿梭车
        /// 
        /// Rgv写入信号
        protected virtual void WriteTaskToRgv(WCSWriteToRgvSignal rgvwrite)
        {
            if (CheckTaskInfo(Rgv, rgvwrite))
            {
                WaitExecTask.Clear();
                string result = TryCachHelper.TryTranExecute((db) =>
                {
                    UpdateRgvTaskStatus(db, rgvwrite);
                    WriteTrigger(Rgv, rgvwrite);
                });
                if (!string.IsNullOrWhiteSpace(result))
                    throw new Exception(string.Format("任务[{0}]RGV执行失败,原因:[{1}]", rgvwrite.Tasknum, result));
            }
            else
            {
                WriteTaskToBuffer(rgvwrite);
            }
        }
        protected void WriteTask(WCSWriteToRgvSignal rgvwrite)
        {
            string cacheAreaName = rgvwrite.Tasknum.ToString();
            var cacheInfo = SugarBase.DB.Queryable().First(v => v.Cache_ConvNo == rgvwrite.DestPosition.ToString());
            if (cacheInfo != null)
            {
                cacheAreaName = cacheInfo.Cache_AreaName;
            }
            string errorMsg = WriteTaskToRgv(rgvwrite, cacheAreaName);
            if (!string.IsNullOrWhiteSpace(errorMsg)) throw new Exception(errorMsg);
        }
        protected string WriteTaskToRgv(WCSWriteToRgvSignal rgvwrite, string cacheAreaName)
        {
            using (var mutex = new Mutex(false, cacheAreaName))
            {
                string resultMsg = string.Empty;
                try
                {
                    if (mutex.WaitOne(-1, false))
                    {
                        WriteTaskToRgv(rgvwrite);
                    }
                }
                catch (Exception ex)
                {
                    resultMsg = ex.Message;
                }
                finally
                {
                    mutex.ReleaseMutex();
                }
                return resultMsg;
            }
        }
        private bool CheckTaskInfo(RGVSignal rgvSignal, WCSWriteToRgvSignal rgvwrite)
        {
            bool result = false;
            if (rgvwrite.RgvPos == RgvPosEnum.一号工位)
            {
                if (rgvSignal.DB520_TaskID_1 == rgvwrite.Tasknum &&
                    rgvSignal.DB520_TaskType_1 == rgvwrite.TaskType &&
                    rgvSignal.DB520_StartPosition_1 == rgvwrite.StartPosition &&
                    rgvSignal.DB520_DestPosition_1 == rgvwrite.DestPosition &&
                    rgvSignal.DB520_Priority_1 == rgvwrite.Priority &&
                    rgvSignal.DB520_Res1_1 == rgvwrite.RES1 &&
                    rgvSignal.DB520_Res2_1 == rgvwrite.RES2)
                {
                    result = true;
                }
                else
                {
                    result = false;
                }
            }
            else if (rgvwrite.RgvPos == RgvPosEnum.二号工位)
            {
                if (rgvSignal.DB520_TaskID_2 == rgvwrite.Tasknum &&
                    rgvSignal.DB520_TaskType_2 == rgvwrite.TaskType &&
                    rgvSignal.DB520_StartPosition_2 == rgvwrite.StartPosition &&
                    rgvSignal.DB520_DestPosition_2 == rgvwrite.DestPosition &&
                    rgvSignal.DB520_Priority_2 == rgvwrite.Priority &&
                    rgvSignal.DB520_Res1_2 == rgvwrite.RES1 &&
                    rgvSignal.DB520_Res2_2 == rgvwrite.RES2)
                {
                    result = true;
                }
                else
                {
                    result = false;
                }
            }
            return result;
        }
        private void WriteTrigger(RGVSignal rgvSignal, WCSWriteToRgvSignal rgvwrite)
        {
            if (rgvwrite.RgvPos == RgvPosEnum.一号工位)
            {
                if (rgvSignal.DB520_Trigger_1 != 1)
                {
                    if (rgvwrite.Plc.WriteSignal((ushort)rgvwrite.DBName, 16, 2, 1))
                    {
                        WaitExecTask.Clear(); 
                        Log4netHelper.Logger_Info.InfoFormat(string.Format("任务[{0}]穿梭车[{1}]写入触发信号成功!", rgvwrite.Tasknum, PlcName));
                    }
                    else
                    {
                        throw new Exception(string.Format("任务[{0}]穿梭车[{1}]写入触发信号失败!", rgvwrite.Tasknum, PlcName));
                    }
                }
            }
            else if (rgvwrite.RgvPos == RgvPosEnum.二号工位)
            {
                if (rgvSignal.DB520_Trigger_2 != 1)
                {
                    if (rgvwrite.Plc.WriteSignal((ushort)rgvwrite.DBName, 34, 2, 1))
                    {
                        Log4netHelper.Logger_Info.InfoFormat(string.Format("任务[{0}]穿梭车[{1}]写入触发信号成功!", rgvwrite.Tasknum, PlcName));
                    }
                    else
                    {
                        throw new Exception(string.Format("任务[{0}]穿梭车[{1}]写入触发信号失败!", rgvwrite.Tasknum, PlcName));
                    }
                }
            }
        }
        /// 
        /// 写入任务信息
        /// 
        /// 写入的信息
        protected void WriteTaskToBuffer(WCSWriteToRgvSignal rgvwrite)
        {
            List list = new List();
            //写入任务号
            list.AddRange(ExtendsUtil.UintToByte((uint)rgvwrite.Tasknum).ToList());
            //类型
            list.AddRange(ExtendsUtil.UshortToByte((ushort)rgvwrite.TaskType).ToList());
            //写入起点地址
            list.AddRange(ExtendsUtil.UshortToByte((ushort)rgvwrite.StartPosition).ToList());
            //写入目标地址
            list.AddRange(ExtendsUtil.UshortToByte((ushort)rgvwrite.DestPosition).ToList());
            //优先级
            list.AddRange(ExtendsUtil.UshortToByte((ushort)rgvwrite.Priority).ToList());
            list.AddRange(ExtendsUtil.UshortToByte((ushort)rgvwrite.RES1).ToList());
            list.AddRange(ExtendsUtil.UshortToByte((ushort)rgvwrite.RES2).ToList());
            bool result = rgvwrite.Plc.Write((ushort)rgvwrite.DBName, (ushort)(rgvwrite.WriteStartAddress), list.ToArray());
            if (result)
            {
                WaitExecTask.SetInfo(rgvwrite.Tasknum, rgvwrite.StartPosition.ToString(), rgvwrite.DestPosition.ToString());
                Log4netHelper.Logger_Info.InfoFormat(string.Format("RGV[{0}]写入任务[{1}]起点地址[{2}]目标地址[{3}]是否托盘异常退回[{4}]成功。", rgvwrite.RgvNo, rgvwrite.Tasknum, rgvwrite.StartPosition, rgvwrite.DestPosition, rgvwrite.RES1));
            }
            else
            {
                throw new Exception(string.Format("RGV[{0}]写入任务[{1}]起点地址[{2}]目标地址[{3}]失败。", rgvwrite.RgvNo, rgvwrite.Tasknum, rgvwrite.StartPosition, rgvwrite.DestPosition));
            }
        }
        /// 
        /// 修改任务信息
        /// 
        protected virtual void UpdateRgvTaskStatus(SqlSugarClient db, WCSWriteToRgvSignal rgvwrite) { }
        #endregion;
    }
    public struct WCSWriteToRgvSignal
    {
        /// 
        /// 工位
        /// 
       public RgvPosEnum RgvPos;
        public PLC Plc;
        /// 
        /// DB名称
        /// 
        public int DBName;
        /// 
        /// RGV编号
        /// 
        public string RgvNo;
        /// 
        /// 写入信号起始地址
        /// 
        public int WriteStartAddress;
        /// 
        /// 任务号
        /// 
        public int Tasknum;
        /// 
        /// 1取货、2放货、3移动、4码盘、5拆盘 、6、变更放货站台、7变更取货站台(环穿、双工位使用) 
        /// 
        public int TaskType;
        /// 
        /// 起始地址 
        /// 
        public int StartPosition;
        /// 
        /// 目标地址
        /// 
        public int DestPosition;
        /// 
        /// 优先级
        /// 
        public int Priority;
        public int RES1;
        public int RES2;
        /// 
        /// WCS写入1,plc清零
        /// 
        public int Trigger;
    }
    //public class RGVList
    //{
    //    /// 
    //    /// Rgv运行
    //    /// 
    //    public static void RgvRun()
    //    {
    //        try
    //        {
    //            foreach (var rgv in Current.RgvSet)
    //            {
    //                ThreadHelper.TaskThread(rgv.RgvRun);
    //            }
    //        }
    //        catch (Exception ex)
    //        {
    //            Log4netHelper.Logger_Error.ErrorFormat(ex.ToString());
    //        }
    //    }
    //}
}