using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using WCS.Data;
using WCS.Data.Models;
using WCS.Data.Utils;
using WCS.PLC.Model.Equipment;
namespace WCS.PLC
{
    public class Base_Srm3 : Base_EquPlc
    {
        private int task_no_Last = 0;//上一次的任务号
        private readonly string SrmOutInInfo_in = "in";
        private readonly string SrmOutInInfo_out = "out";
        private readonly string SrmOutInInfo_outIn = "outIn";
        private readonly string WriteSrmSignalException = "520写入取放货信号失败";
        private readonly string WriteSrmTriggerException = "520写入触发信号失败";
        #region Properties   
        /// 
        /// 任务要执行的当前路由信息
        /// 
        //protected WCS_EQUIPMENTROUTE CurrentRoute { get; set; }
        /// 
        /// 堆垛机信号
        /// 
        protected SrmSignal EquSignal
        {
            get
            {
                return WCS_PLCItem.WCS_EquipmentInfoSet[0].EquSignal_Srm;
            }
        }
        /// 
        /// 写入DB名称
        /// 
        protected int WriteDbName
        {
            get
            {
                return WCS_PLCItem.WCS_DBSet[0].DB_NAME;
            }
        }
        /// 
        /// 堆垛机出入库口设置列表
        /// 
        protected List SrmOutInInfoSet = new List();
        #endregion;
        #region Constructor
        public Base_Srm3() : base()
        {
        }
        #endregion;
        #region Method 
        private int _locExecute = 0;
        public override void Run()
        {
            if (Interlocked.Exchange(ref _locExecute, 1) == 0)
            {
                try
                {
                    //加载刷新堆垛机执行需要的最新参数设置
                    Init_Refresh();
                    //分配入库货位
                    ThreadHelper.TaskThread(AssignInWareCell);
                    if (WCS_PLCItem.IsConnSuccess == false) return;
                    if (string.IsNullOrWhiteSpace(PlcName)) return;
                    //完成任务
                    SRMCompleteTask();
                    //执行任务
                    SRMStartExecuteTask();
                }
                catch (Exception ex)
                {
                    string errormsg = string.Format("堆垛机[{0}]执行异常,消息:{1}", PlcName, ex.ToString());
                    LogMessageHelper.RecordLogMessage(errormsg, ex);
                }
                finally
                {
                    Interlocked.Exchange(ref _locExecute, 0);
                }
            }
        }
        /// 
        /// 堆垛机任务完成
        /// 
        protected virtual void SRMCompleteTask()
        {
            try
            {
                //当前任务完成
                if (EquSignal.DB521_Task_Finishi == false) return;
                //查询任务
                var task = SugarBase.DB.Queryable().First(v => v.TASK_NO == EquSignal.DB521_Taskfinishi_ID);
                if (task == null) return;
                if (task.TASK_WKSTATUS >= 99) return;
                if ((task.TASK_COMTYPE == (int)ComTypeEnum.入库 && task.TASK_POSIDTO.Length > 5) || task.TASK_COMTYPE == (int)ComTypeEnum.移库)
                {
                    //完成任务
                    string result = TryCachHelper.TryTranExecute((db) =>
                    {
                        //修改任务的状态
                        db.Updateable(it => new WCS_TASK() { TASK_WKSTATUS = 99, TASK_EDITUSERNO = "WCS", TASK_EDITDATETIME = DateTime.Now })
                                    .Where(it => it.TASK_NO == task.TASK_NO)
                                    .ExecuteCommand();
                        //添加修改明细
                        string msg = string.Format("任务[{0}]完成", task.TASK_NO);
                        CommonData.AddWCS_TASK_DTL(db, task.TASK_NO, task.TASK_NO, task.TASK_POSIDCUR, task.TASK_POSIDTO, msg);
                    });
                    if (string.IsNullOrWhiteSpace(result))
                    {
                        if (task.TASK_COMTYPE == (int)ComTypeEnum.入库)
                        {
                            SrmConvNoMoveToLast(task.TASK_POSIDCUR);
                        }
                    }
                }
                else if (task.TASK_COMTYPE == (int)ComTypeEnum.出库 || task.TASK_COMTYPE == (int)ComTypeEnum.搬运)
                {
                    if (task.TASK_WKSTATUS == (int)WkStatus.堆垛机执行)
                    {
                        //var routeSet = EquRouteHelper.QueryRoute(task.TASK_SRMNO, task.TASK_POSIDTO);
                        //var routes = routeSet.Where(v => v.ROUTE_STARTPOS == task.TASK_SRMNO).ToList();
                        //var route = QueryOutEquRouteItem(task, routes);
                        int wksstatus = 6;
                        //if (route.ISEND)
                        //{
                        //    wksstatus = 99;
                        //}
                        string result = TryCachHelper.TryTranExecute((db) =>
                        {
                            //修改任务的状态
                            db.Updateable(it => new WCS_TASK() { TASK_WKSTATUS = wksstatus, TASK_POSIDCUR = task.TASK_POSIDNEXT, TASK_EDITUSERNO = "WCS", TASK_EDITDATETIME = DateTime.Now })
                                        .Where(it => it.TASK_NO == task.TASK_NO)
                                        .ExecuteCommand();
                            //添加修改明细
                            string msg = string.Format("任务[{0}]堆垛机完成,修改当前地址为[{1}]", task.TASK_NO, task.TASK_POSIDNEXT);
                            CommonData.AddWCS_TASK_DTL(db, task.TASK_NO, task.TASK_NO, task.TASK_POSIDNEXT, task.TASK_POSIDNEXT, msg);
                        });
                        if (string.IsNullOrWhiteSpace(result))
                        {
                            SrmConvNoMoveToLast(task.TASK_POSIDNEXT);
                        }
                    }
                }
                //TaskComplete(task.TASK_SRMNO, task.TASK_ID, task.TASK_COMTYPE);
            }
            catch (Exception ex)
            {
                LogMessageHelper.RecordLogMessage(ex);
            }
        }
        private void SRMStartExecuteTask()
        {
            //检测堆垛机模式
            if (EquSignal.DB521_Auto_status != (int)SrmModeEnum.远程) return;
            //检测堆垛机报警
            if (EquSignal.SrmDB541_Alarm) return;
            //检测堆垛机状态
            if (EquSignal.DB521_Srm_Status != (int)SrmStateFork1Enum.空闲) return;
            if (EquSignal.DB520_Task_trigger != 0) return;
            //检测堆垛机禁用
            //if (Current.SysSets.FirstOrDefault(v => v.SET_ID == SrmNo).SET_VALUE.Trim() == "1") return;
            var task = SugarBase.DB.Queryable().First(v => v.TASK_SRMNO == PlcName && v.TASK_WKSTATUS == (int)WkStatus.堆垛机执行);
            if (task == null)
            {
                var taskSet = SugarBase.DB.Queryable().Where(v => v.TASK_SRMNO == PlcName &&
                              ((v.TASK_COMTYPE == (int)TaskTypeEnum.TaskType_OutStorage && v.TASK_WKSTATUS <= 1) ||
                               (v.TASK_COMTYPE == (int)TaskTypeEnum.TaskType_InStorage && SrmOutInInfoSet.Any(t => v.TASK_POSIDCUR == t.SRMOUTIN_CONVNO)) ||
                               (v.TASK_COMTYPE == (int)TaskTypeEnum.TaskType_StockTransfer && v.TASK_WKSTATUS <= 1) ||
                               (v.TASK_COMTYPE == (int)TaskTypeEnum.TaskType_Carry && SrmOutInInfoSet.Any(t => v.TASK_POSIDCUR == t.SRMOUTIN_CONVNO)))).ToList();
                taskSet = taskSet.Where(v => v.TASK_COMTYPE == (int)TaskTypeEnum.TaskType_StockTransfer && v.TASK_WKSTATUS <= 1 && v.TASK_SRMNO == PlcName).ToList();
                if (taskSet.Count() > 0)
                {
                    //移库
                    MoveStock(taskSet.First());
                }
                else
                {
                    OutInStock(taskSet);
                    //taskSet = taskSet.Where(v => v.TASK_WKSTATUS <= 2).ToList();
                    //if (taskSet.Count > 0)
                    //{
                    //    OutInStock(taskSet);
                    //}
                }
            }
            else
            {
                Log4netHelper.Logger_Error.ErrorFormat(string.Format("堆垛机[{0}]状态正常,但是存在执行中的任务[{1}]", PlcName, task.TASK_NO));
            }
        }
        private void OutInStock(List tasks)
        {
            var tasktemp = tasks.FirstOrDefault(v => v.TASK_NO == task_no_Last);
            if (tasktemp == null)
            {
                tasktemp = SugarBase.DB.Queryable()
                                    .First(v => !SqlFunc.IsNullOrEmpty(v.TASK_POSIDMOVE) &&
                                    v.TASK_COMTYPE == 2 &&
                                    v.TASK_WKSTATUS <= 1 &&
                                    v.TASK_WMSNO == PlcName);
                if (tasktemp != null)
                {
                    if (ExecuteTask(tasktemp)) return;
                }
            }
            else
            {
                if ((tasktemp.TASK_COMTYPE == 1 && tasktemp.TASK_WKSTATUS == 2) ||
                    (tasktemp.TASK_COMTYPE == 2 && tasktemp.TASK_WKSTATUS <= 1) ||
                    (tasktemp.TASK_COMTYPE == 3 && tasktemp.TASK_WKSTATUS <= 1) ||
                    (tasktemp.TASK_COMTYPE == 4 && tasktemp.TASK_WKSTATUS == 2))
                {
                    if (ExecuteTask(tasktemp)) return;
                }
            }
            int taskMaxPriority = tasks.Max(v => v.TASK_PRIORITY);
            for (int index = taskMaxPriority; index >= 0; index--)
            {
                var tasks_Temp = tasks.Where(v => v.TASK_PRIORITY == index).ToList();
                if (tasks_Temp.Count > 0)
                {
                    //查询硬件条件满足的可用出入库任务
                    var taskSet = QueryTask(tasks_Temp);
                    //调用扩展函数返回可用出入库任务
                    var taskList = QueryOutTasks(taskSet);
                    //克隆集合
                    List outininfoSet = SrmOutInInfoSet.GetRange(0, SrmOutInInfoSet.Count);
                    bool isEixt = false;
                    foreach (var outininfo in outininfoSet)
                    {
                        if (outininfo.SRMOUTIN_OUTINTYPE == SrmOutInInfo_in || outininfo.SRMOUTIN_OUTINTYPE == SrmOutInInfo_outIn)
                        {
                            var taskitem = taskList.SingleOrDefault(v => v.TASK_POSIDCUR == outininfo.SRMOUTIN_CONVNO);
                            if (taskitem != null)
                            {
                                if (taskitem.TASK_COMTYPE == (int)TaskTypeEnum.TaskType_InStorage)
                                {
                                    if (InStock(taskitem))
                                    {
                                        task_no_Last = taskitem.TASK_NO;
                                        isEixt = true;
                                        break;
                                    }
                                }
                                else if (taskitem.TASK_COMTYPE == (int)TaskTypeEnum.TaskType_Carry)
                                {
                                    if (Carry(taskitem))
                                    {
                                        task_no_Last = taskitem.TASK_NO;
                                        isEixt = true;
                                        break;
                                    }
                                }
                            }
                        }
                        if (outininfo.SRMOUTIN_OUTINTYPE == SrmOutInInfo_out || outininfo.SRMOUTIN_OUTINTYPE == SrmOutInInfo_outIn)
                        {
                            var tasktempList = taskList.Where(v => v.TASK_COMTYPE == (int)TaskTypeEnum.TaskType_OutStorage).ToList();
                            bool iscreateSuccess = false;
                            foreach (var item in tasktempList)
                            {
                                //检测是否允许出库
                                if (QueryOutTask(item))
                                {
                                    if (OutStock(item))
                                    {
                                        task_no_Last = item.TASK_NO;
                                        iscreateSuccess = true;
                                        break;
                                    }
                                }
                            }
                            if (iscreateSuccess)
                            {
                                isEixt = true;
                                break;
                            }
                        }
                    }
                    if (isEixt)
                    {
                        break;
                    }
                }
            }
        }
        protected virtual bool QueryOutTask(WCS_TASK task) { return true; }
        private bool ExecuteTask(WCS_TASK task)
        {
            bool isExecuteFinish = false;
            if (task.TASK_COMTYPE == (int)ComTypeEnum.入库)
            {
                if (InStock(task)) isExecuteFinish = true;
            }
            else if (task.TASK_COMTYPE == (int)ComTypeEnum.出库)
            {
                if (OutStock(task)) isExecuteFinish = true;
            }
            else if (task.TASK_COMTYPE == (int)ComTypeEnum.搬运)
            {
                if (Carry(task)) isExecuteFinish = true;
            }
            return isExecuteFinish;
        }
        protected virtual List QueryOutTasks(List taskSet) { return taskSet.OrderBy(n => n.TASK_ADDDATETIME).ToList(); }
        private List QueryTask(List tasks)
        {
            List wcs_taskSet = new List();
            //克隆集合
            List outininfoSet = SrmOutInInfoSet.GetRange(0, SrmOutInInfoSet.Count);
            foreach (var outininfo in outininfoSet)
            {
                if (outininfo.SRMOUTIN_OUTINTYPE == SrmOutInInfo_in || outininfo.SRMOUTIN_OUTINTYPE == SrmOutInInfo_outIn)
                {
                    var intask = tasks.SingleOrDefault(v => v.TASK_WKSTATUS != (int)WkStatus.堆垛机执行 && v.TASK_POSIDCUR == outininfo.SRMOUTIN_CONVNO);
                    if (intask != null)
                    {
                        if ((intask.TASK_COMTYPE == 1 && intask.TASK_POSIDTO != PlcName && intask.TASK_POSIDTO != srm) || //入库任务已分配货位
                             intask.TASK_COMTYPE == 4) //搬运任务
                        {
                            var temptask = QueryInConvTask(outininfo, intask);
                            if (temptask != null)
                            {
                                wcs_taskSet.Add(temptask);
                            }
                        }
                    }
                }
                else if (outininfo.SRMOUTIN_OUTINTYPE == SrmOutInInfo_out || outininfo.SRMOUTIN_OUTINTYPE == SrmOutInInfo_outIn)
                {
                    //检测出口状态
                    var convSignal = ConveyorHelper.GetConveyorSignal(outininfo.SRMOUTIN_CONVPLCNAME, outininfo.SRMOUTIN_CONVNO);
                    if (convSignal.DB521_Request == false && convSignal.DB521_Tasknum <= 0 && convSignal.CvDB51_PH_Status == false)
                    {
                        var outTask = SugarBase.DB.Queryable().First(v => v.TASK_POSIDCUR == outininfo.SRMOUTIN_CONVNO);
                        if (outTask == null ||
                           ((outTask.TASK_WKSTATUS != (int)WkStatus.输送机执行) && (outTask.TASK_WKSTATUS != (int)WkStatus.堆垛机完成)))
                        {
                            //检测是否存在该出口的任务列表
                            List list = new List();
                            var taskList = tasks.Where(v => v.TASK_COMTYPE == 2 && v.TASK_WKSTATUS <= 1).ToList();
                            foreach (var task in taskList)
                            {
                                var routes = EquRouteHelper.QueryRoute(task.TASK_SRMNO, task.TASK_POSIDTO).Where(v => v.ROUTE_STARTPOS == PlcName).ToList();
                                var routeitem = routes.FirstOrDefault(v => v.ROUTE_SONPOS == outininfo.SRMOUTIN_CONVNO);
                                if (routeitem != null && CheckAreaOutAddress(task, routeitem))
                                {
                                    if (wcs_taskSet.Any(v => v.TASK_NO == task.TASK_NO) == false)
                                    {
                                        list.Add(task);
                                    }
                                }
                            }
                            if (list.Count() > 0) wcs_taskSet.AddRange(list);
                        }
                    }
                }
            }
            return wcs_taskSet;
        }
        /// 
        /// 检测区域出口地址(弯轨堆垛机,多项道转换堆垛机)
        /// 
        protected virtual bool CheckAreaOutAddress(WCS_TASK task, WCS_EQUIPMENTROUTE route)
        {
            return true;
        }
        protected virtual WCS_EQUIPMENTROUTE QueryOutEquRouteItem(WCS_TASK task, List routeSet)
        {
            return routeSet.Single();
        }
        /// 
        /// 查询堆垛机入库口任务
        /// 
        protected virtual WCS_TASK QueryInConvTask(WCS_SrmOutInInfo outininfo, WCS_TASK task)
        {
            WCS_TASK wcs_task = null;
            var convSignal = ConveyorHelper.GetConveyorSignal(outininfo.SRMOUTIN_CONVPLCNAME, outininfo.SRMOUTIN_CONVNO);
            if (convSignal.DB521_Tasknum == task.TASK_NO && convSignal.CvDB51_PH_Status
                //&& convSignal.DB521_Goodsend.ToString() == outininfo.SRMOUTIN_CONVNO
                )
            {
                if (task.TASK_COMTYPE == 1)
                {
                    wcs_task = task;
                }
                else if (task.TASK_COMTYPE == 4)
                {
                    var route = EquRouteHelper.QueryRoute(task.TASK_SRMNO, task.TASK_POSIDTO).FirstOrDefault(v => v.ROUTE_STARTPOS == PlcName);
                    var srmoutin = SrmOutInInfoSet.SingleOrDefault(v => v.SRMOUTIN_CONVNO == route.ROUTE_NEXTPOS && v.SRMOUTIN_SRMNO == PlcName);
                    //检测出口状态
                    var outConv = ConveyorHelper.GetConveyorSignal(srmoutin.SRMOUTIN_CONVPLCNAME, srmoutin.SRMOUTIN_CONVNO);
                    if (outConv.DB521_Tasknum == 0 && outConv.CvDB51_PH_Status == false)
                    {
                        wcs_task = task;
                    }
                }
            }
            return wcs_task;
        }
        protected bool InStock(WCS_TASK task)
        {
            bool result = true;
            try
            {
                var writeSignal = new WCSWriteToSrmSignal();
                writeSignal.Start_number = 0;
                writeSignal.Goodtype = 0;
                writeSignal.TaskID = task.TASK_NO;
                if (task.TASK_COMTYPE == 4)//移动
                {
                    //var startCvToEnd = ConveyorHelper.SrmMoveCvSet.FirstOrDefault(v => v.StartConveyor == task.TASK_POSIDCUR);
                    //writeSignal.RowPos1 = startCvToEnd.SrmStartRow;
                    //writeSignal.Travelpos1 = startCvToEnd.SrmStartColumn;
                    //writeSignal.Liftpos1 = startCvToEnd.SrmStartLayer;
                    //writeSignal.Fork_start_pos1 = startCvToEnd.SrmStartDepth;
                    //writeSignal.RowPos2 = startCvToEnd.SrmEndRow;
                    //writeSignal.Travelpos2 = startCvToEnd.SrmEndColumn;
                    //writeSignal.Liftpos2 = startCvToEnd.SrmEndLayer;
                    //writeSignal.Fork_dest_pos2 = startCvToEnd.SrmEndDepth;
                }
                else
                {
                    var route = Current.EquRouteSet.FirstOrDefault(v => v.ROUTE_STARTPOS == task.TASK_POSIDCUR);
                    writeSignal.RowPos1 = (int)route.SRMROW;
                    writeSignal.Travelpos1 = (int)route.SRMCOLUMN;
                    writeSignal.Liftpos1 = (int)route.SRMLAYER;
                    //writeSignal.Fork_start_pos1 = (int)route.DEPTH;
                    //查询货位表巷道,深度
                    //var location = db.Queryable().First(v => v.Loc_No == task.TASK_POSIDTO);
                    writeSignal.RowPos2 = task.ToRow;// location.Loc_Tunnel;
                    writeSignal.Travelpos2 = task.ToCol;
                    writeSignal.Liftpos2 = task.ToLayer;
                    //writeSignal.Fork_dest_pos2 = task.ToDepth; //location.Loc_Depth;
                }
                //执行任务
                SrmOutIn(writeSignal, task.TASK_POSIDCUR, task.TASK_POSIDTO);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains(WriteSrmSignalException) == false &&
                    ex.Message.Contains(WriteSrmTriggerException) == false)
                {
                    result = false;
                }
            }
            return result;
        }
        protected bool OutStock(WCS_TASK task)
        {
            bool result = true;
            try
            {
                var writeSignal = new WCSWriteToSrmSignal();
                writeSignal.Start_number = 0;
                writeSignal.End_number = 0;
                writeSignal.Goodtype = 0;
                writeSignal.TaskID = task.TASK_NO;
                //查询货位表巷道,深度
                //var location = db.Queryable().First(v => v.Loc_No == outtask.TASK_POSIDFROM);
                //堆垛机出库
                writeSignal.RowPos1 = task.FromRow;//location.Loc_Tunnel;
                writeSignal.Travelpos1 = task.FromCol;//outtask.ToCol;
                writeSignal.Liftpos1 = task.FromLayer;//outtask.ToLayer;
                if (task.TASK_COMTYPE == 2)
                {
                    var routeSet = EquRouteHelper.QueryRoute(task.TASK_SRMNO, task.TASK_POSIDTO);
                    var routes = routeSet.Where(v => v.ROUTE_STARTPOS == task.TASK_SRMNO).ToList();
                    var route = QueryOutEquRouteItem(task, routes);
                    writeSignal.RowPos2 = (int)route.SRMROW;
                    writeSignal.Travelpos2 = (int)route.SRMCOLUMN;
                    writeSignal.Liftpos2 = (int)route.SRMLAYER;
                    //writeSignal.Fork_dest_pos2 = (int)route.DEPTH;
                    //执行任务
                    SrmOutIn(writeSignal, task.TASK_POSIDFROM, route.ROUTE_SONPOS);
                }
                else if (task.TASK_COMTYPE == 3)
                {
                    writeSignal.RowPos2 = task.ToRow;
                    writeSignal.Travelpos2 = task.ToCol;
                    writeSignal.Liftpos2 = task.ToLayer;
                    //writeSignal.Fork_dest_pos2 = outtask.ToDepth;
                    writeSignal.TaskID = task.TASK_NO;
                    //执行任务
                    SrmOutIn(writeSignal, task.TASK_POSIDFROM, task.TASK_POSIDTO);
                }
            }
            catch (Exception ex)
            {
                LogMessageHelper.RecordLogMessage(ex);
                if (ex.Message.Contains(WriteSrmSignalException) == false && 
                    ex.Message.Contains(WriteSrmTriggerException) == false)
                {
                    result = false;
                }
            }
            return result;
        }
        protected bool Carry(WCS_TASK task)
        {
            bool result = true;
            try
            {
                var writeSignal = new WCSWriteToSrmSignal();
                writeSignal.Start_number = 0;
                writeSignal.End_number = 0;
                writeSignal.Goodtype = 0;
                var routeItem = Current.EquRouteSet.SingleOrDefault(v => v.ROUTE_STARTPOS == task.TASK_POSIDNEXT && v.ROUTE_SONPOS == PlcName);
                //查询货位表巷道,深度
                //var location = db.Queryable().First(v => v.Loc_No == outtask.TASK_POSIDFROM);
                writeSignal.RowPos1 = (int)routeItem.SRMROW;//task.FromRow;//location.Loc_Tunnel;
                writeSignal.Travelpos1 = (int)routeItem.SRMCOLUMN; //task.FromCol;//outtask.ToCol;
                writeSignal.Liftpos1 = (int)routeItem.SRMLAYER;//task.FromLayer;//outtask.ToLayer;
                                                               //writeSignal.Fork_start_pos1 = outtask.FromDepth;// location.Loc_Depth; location.Loc_EquimentNo
                var routeSet = EquRouteHelper.QueryRoute(task.TASK_SRMNO, task.TASK_POSIDTO);
                var routes = routeSet.Where(v => v.ROUTE_STARTPOS == task.TASK_SRMNO).ToList();
                var route = QueryOutEquRouteItem(task, routes);
                writeSignal.RowPos2 = (int)route.SRMROW;
                writeSignal.Travelpos2 = (int)route.SRMCOLUMN;
                writeSignal.Liftpos2 = (int)route.SRMLAYER;
                //writeSignal.Fork_dest_pos2 = (int)route.DEPTH;
                writeSignal.TaskID = task.TASK_NO;
                //执行任务
                SrmOutIn(writeSignal, task.TASK_POSIDNEXT, route.ROUTE_SONPOS);
            }
            catch (Exception ex)
            {
                LogMessageHelper.RecordLogMessage(ex);
                if (ex.Message.Contains(WriteSrmSignalException) == false &&
                    ex.Message.Contains(WriteSrmTriggerException) == false)
                {
                    result = false;
                }
            }
            return result;
        }
        protected void MoveStock(WCS_TASK task)
        {
            var writeSignal = new WCSWriteToSrmSignal();
            writeSignal.Start_number = 0;
            writeSignal.End_number = 0;
            writeSignal.Goodtype = 0;
            //查询货位表巷道,深度
            //var location1 = db.Queryable().First(v => v.F_NO == task.TASK_POSIDFROM);
            writeSignal.RowPos1 = task.FromRow; // location1.F_LINE;
            writeSignal.Travelpos1 = task.FromCol;
            writeSignal.Liftpos1 = task.FromLayer;
            //writeSignal.Fork_start_pos1 = location1.F_DEPTH;
            writeSignal.End_number = 0;
            //查询货位表巷道,深度
            //var location2 = db.Queryable().First(v => v.F_NO == task.TASK_POSIDTO);
            writeSignal.RowPos2 = task.ToRow;//location2.F_LINE;
            writeSignal.Travelpos2 = task.ToCol;
            writeSignal.Liftpos2 = task.ToLayer;
            //writeSignal.Fork_dest_pos2 = location2.F_DEPTH;
            writeSignal.TaskID = task.TASK_NO;
            writeSignal.End_number = 0;
            //执行任务
            SrmOutIn(writeSignal, task.TASK_POSIDFROM, task.TASK_POSIDTO);
        }
        private void SrmOutIn(WCSWriteToSrmSignal srmSignal, string startPos, string posIdnext)
        {
            var task = Current.TaskSet.First(v => v.TASK_NO == srmSignal.TaskID);
            WCS_CacheInfo cahcheinfo = Current.WCS_CacheInfoSet.FirstOrDefault(v => v.Cache_TrafficControlEquSet.Contains(PlcName) && (task.TASK_POSIDTO.Contains(v.Cache_ConvNo) || task.TASK_POSIDTO.Contains(v.Cache_AreaName)));
            string cacheAreaName = cahcheinfo == null ? srmSignal.TaskID.ToString() : cahcheinfo.Cache_AreaName;
            //string errorMsg = ThreadLockHelper.SrmOutIn(EquSignal, srmSignal, WCS_PLCItem.Plc, WriteDbName, startPos, posIdnext, cacheAreaName, PlcName);
            string errorMsg = SrmOutIn(EquSignal, srmSignal, startPos, posIdnext, cacheAreaName);
            if (!string.IsNullOrWhiteSpace(errorMsg)) throw new Exception(errorMsg);
        }
        public string SrmOutIn(SrmSignal equSignal, WCSWriteToSrmSignal srmSignal, string startPos, string posIdnext, string cacheAreaName)
        {
            using (var mutex = new Mutex(false, cacheAreaName))
            {
                string resultMsg = string.Empty;
                try
                {
                    if (mutex.WaitOne(-1, false))
                    {
                        SrmTaskRun(equSignal, srmSignal, startPos, posIdnext, cacheAreaName);
                    }
                }
                catch (Exception ex)
                {
                    resultMsg = ex.Message;
                }
                finally
                {
                    mutex.ReleaseMutex();
                }
                return resultMsg;
            }
        }
        private void SrmTaskRun(SrmSignal equSignal, WCSWriteToSrmSignal srmSignal, string startPos, string posIdnext, string cacheAreaName)
        {
            //检测并生成移库任务
            CheckCreateMoveTask(srmSignal, ref startPos, ref posIdnext);
            bool isExecute = CheckIsExecuteTask(cacheAreaName);
            if (isExecute)
            {
                if (equSignal.DB520_Start_number == srmSignal.Start_number &&
                    equSignal.DB520_End_number == srmSignal.End_number &&
                    equSignal.DB520_Goodtype == srmSignal.Goodtype &&
                    equSignal.DB520_Runmode == srmSignal.Runmode &&
                    equSignal.DB520_FromRowPos == srmSignal.RowPos1 &&
                    equSignal.DB520_FromColumnPos == srmSignal.Travelpos1 &&
                    equSignal.DB520_FromLayerPos == srmSignal.Liftpos1 &&
                    equSignal.DB520_Fork_start_pos1 == srmSignal.Fork_start_pos1 &&
                    equSignal.DB520_ToRowPos == srmSignal.RowPos2 &&
                    equSignal.DB520_ToColumnPos == srmSignal.Travelpos2 &&
                    equSignal.DB520_ToLayerPos == srmSignal.Liftpos2 &&
                    equSignal.DB520_Fork_dest_pos2 == srmSignal.Fork_dest_pos2 &&
                    equSignal.DB520_TaskID == srmSignal.TaskID)
                {
                    string convNo = string.Empty;
                    string result = TryCachHelper.TryTranExecute((db) =>
                    {
                        var task = db.Queryable().First(t => t.TASK_NO == srmSignal.TaskID);
                        if (task.TASK_COMTYPE == (int)TaskTypeEnum.TaskType_OutStorage)
                        {
                            convNo = posIdnext;
                        }
                        else if (task.TASK_COMTYPE == (int)TaskTypeEnum.TaskType_InStorage ||
                                 task.TASK_COMTYPE == (int)TaskTypeEnum.TaskType_Carry)
                        {
                            convNo = task.TASK_POSIDCUR;
                        }
                        db.Updateable(it => new WCS_TASK() { TASK_WKSTATUS = (int)WkStatus.堆垛机执行, TASK_POSIDNEXT = posIdnext, TASK_EDITUSERNO = "WCS", TASK_EDITDATETIME = DateTime.Now })
                           .Where(it => it.TASK_NO == srmSignal.TaskID).ExecuteCommand();
                        string msg = string.Format("任务[{0}]已下发给堆垛机执行,起点位置[{1}]目标地址[{2}]", task.TASK_NO, startPos, posIdnext);
                        CommonData.AddWCS_TASK_DTL(db, task.TASK_NO, task.TASK_NO, task.TASK_POSIDCUR, posIdnext, msg);
                        if (equSignal.DB520_Task_trigger != 1)
                        {
                            //string mes = string.Format("读取plc信息:任务号[{0}]起始行[{1}]起始列[{2}]起始层[{3}]目标行[{4}]目标列[{5}]目标层[{6}]",
                            //equSignal.DB520_TaskID, equSignal.DB520_FromRowPos, equSignal.DB520_FromColumnPos, equSignal.DB520_FromLayerPos,
                            //equSignal.DB520_ToRowPos, equSignal.DB520_ToColumnPos, equSignal.DB520_ToLayerPos);
                            //Log4netHelper.Logger_Info.InfoFormat(mes);
                            if (WCS_PLCItem.Plc.WriteSignal((ushort)WriteDbName, 30, 2, 1))
                            {
                                Log4netHelper.Logger_Info.InfoFormat(string.Format("任务[{0}]写入触发信号成功。", srmSignal.TaskID));
                            }
                            else
                            {
                                throw new Exception(string.Format("任务[{0}]520写入触发信号失败。", srmSignal.TaskID));
                            }
                        }
                    });
                    if (string.IsNullOrWhiteSpace(result))
                    {
                        task_no_Last = 0;
                        //移动到最后
                        SrmConvNoMoveToLast(convNo);
                    }
                    else
                    {
                        throw new Exception(string.Format("任务[{0}]堆垛机执行失败,原因:[{1}]", srmSignal.TaskID, result));
                    }
                }
                else
                {
                    WriteTaskToSrm(srmSignal);
                }
            }
            else
            {
                throw new Exception(string.Format("目标地址[{0}]交通管制,暂无法执行出库任务,将优先执行其它任务。", cacheAreaName));
            }
        }
        private void CheckCreateMoveTask(WCSWriteToSrmSignal srmSignal, ref string startPos, ref string posIdnext)
        {
            var task = SugarBase.DB.Queryable().Single(v => v.TASK_NO == srmSignal.TaskID);
            if (task == null)
            {
                throw new Exception(string.Format("堆垛机[{0}]执行的任务[{1}]不存在", PlcName, srmSignal.TaskID));
            }
            if (task.TASK_COMTYPE == (int)TaskTypeEnum.TaskType_OutStorage && 
                task.FromDepth == 2 &&
                task.TASK_POSIDCUR == task.TASK_POSIDFROM &&
                string.IsNullOrWhiteSpace(task.TASK_POSIDMOVE))
            {
                var tasktemps = SugarBase.DB.Queryable().Where(v => v.TASK_SRMNO == PlcName).ToList();
                var task_DepthOne = tasktemps.FirstOrDefault(v => v.FromNo == task.FromNo &&
                    v.FromCol == task.FromCol &&
                    v.FromLayer == task.FromLayer &&
                    v.FromDepth == 1 &&
                    v.TASK_WKSTATUS <= 1 &&
                    (v.TASK_COMTYPE == 2 || v.TASK_COMTYPE == 3));
                if (task_DepthOne == null)
                {
                    //调用生成移库任务接口
                    var moveTaskresult = Current.WmsInterface.I_WCS_GetMoveTask(new GetMoveTaskParam() { WMSTaskNum = task.TASK_WMSNO });
                    if (moveTaskresult.ResType == 0)
                    {
                        throw new Exception(string.Format("任务[{0}]调用移库接口报错:[{1}]", task.TASK_NO, moveTaskresult.ResMessage));
                    }
                    else if (moveTaskresult.ResType == 2)
                    {
                        //创建移库任务并执行
                        var moveTask = new WCS_TASK()
                        {
                            TASK_WMSNO = moveTaskresult.WMSTaskNum,
                            TASK_COMTYPE = 3,
                            TASK_SYSTYPE = "wcs",
                            TASK_POSIDFROM = moveTaskresult.MoveStartWareCell,
                            TASK_POSIDCUR = moveTaskresult.MoveStartWareCell,
                            TASK_POSIDNEXT = moveTaskresult.MoveStartWareCell,
                            TASK_POSIDTO = moveTaskresult.MoveEndWareCell,
                            TASK_POSIDMOVE = moveTaskresult.MoveEndWareCell,
                            TASK_PRIORITY = 0,
                            TASK_WKSTATUS = 0,
                            TASK_WHID = moveTaskresult.WareHouseName,
                            TASK_ADDUSERNO = "wcs",
                            TASK_ADDDATETIME = SugarBase.DB.GetDate(),
                            TASK_EDITUSERNO = "wcs",
                            TASK_EDITDATETIME = SugarBase.DB.GetDate(),
                            TASK_NOTES = string.Empty,
                            TASK_SRMNO = PlcName,
                            TASK_BOXBARCODE = moveTaskresult.ContainerBarCode,
                            TASK_FromTunnelNum = moveTaskresult.FromTunnelNum,
                            TASK_EndTunnelNum = moveTaskresult.EndTunnelNum
                        };
                        string result = TryCachHelper.TryTranExecute((db) =>
                        {
                            int inserttask = db.Insertable(moveTask).ExecuteCommand();
                            if (inserttask <= 0)
                            {
                                throw new Exception(string.Format("任务[{0}]生成移库添加移库任务失败.", task.TASK_NO));
                            }
                            //修改任务的移库字段
                            int updatetask = db.Updateable(it => new WCS_TASK() { TASK_POSIDMOVE = moveTask.TASK_POSIDMOVE, TASK_PRIORITY = 111, TASK_EDITUSERNO = "WCS", TASK_EDITDATETIME = DateTime.Now })
                                               .Where(it => it.TASK_NO == task.TASK_NO)
                                               .ExecuteCommand();
                            if (updatetask <= 0)
                            {
                                throw new Exception(string.Format("任务[{0}]生成移库时修改需要移库的任务失败.", task.TASK_NO));
                            }
                        });
                        if (!string.IsNullOrWhiteSpace(result))
                        {
                            throw new Exception(result);
                        }
                        task = SugarBase.DB.Queryable().First(v => v.TASK_WMSNO == moveTask.TASK_WMSNO);
                    }
                    else if (moveTaskresult.ResType == 3)
                    {
                        if (string.IsNullOrWhiteSpace(moveTaskresult.Memo1.Trim()))
                        {
                            throw new Exception(string.Format("调用移库接口报错:堆垛机[{0}]优先执行的入库任务号不能为空。", PlcName));
                        }
                        else
                        {
                            int task_no = Convert.ToInt16(moveTaskresult.Memo1.Trim());
                            if (task_no <= 0)
                            {
                                throw new Exception(string.Format("调用移库接口报错:堆垛机[{0}]优先执行的入库任务号不能为零。", PlcName));
                            }
                            SugarBase.DB.Updateable(it => new WCS_TASK() { TASK_PRIORITY = 10, TASK_EDITDATETIME = DateTime.Now })
                                     .Where(it => it.TASK_NO == task_no)
                                     .ExecuteCommand();
                        }
                    }
                }
                else if (task_DepthOne.TASK_WKSTATUS <= 1)
                {
                    task = task_DepthOne;
                }
            }
            if (task.TASK_COMTYPE == 3)
            {
                srmSignal.TaskID = task.TASK_NO;
                #region 堆垛机取货地址
                srmSignal.RowPos1 = task.FromRow;
                srmSignal.Travelpos1 = task.FromCol;
                srmSignal.Liftpos1 = task.FromLayer;
                #endregion;
                #region 堆垛机放货地址 
                srmSignal.RowPos2 = task.ToRow;
                srmSignal.Travelpos2 = task.ToCol;
                srmSignal.Liftpos2 = task.ToLayer;
                //writeSignal.Fork_dest_pos2 = (int)route.DEPTH;
                #endregion;
                startPos = task.TASK_POSIDFROM;
                posIdnext = task.TASK_POSIDTO;
            }
        }
        private static bool CheckIsExecuteTask(string cacheAreaName)
        {
            bool isExecute = false;
            var cacheInfoSet = Current.WCS_CacheInfoSet.Where(v => v.Cache_AreaName == cacheAreaName).ToList();
            if (cacheInfoSet.Count <= 0)
            {
                isExecute = true;
            }
            else
            {
                int cacheCount = cacheInfoSet.Sum(v => v.Cache_Count);
                var tasks = SugarBase.DB.Queryable()
                     .Where(v => v.TASK_COMTYPE == (int)TaskTypeEnum.TaskType_OutStorage &&
                                (v.TASK_WKSTATUS > 1 || (v.TASK_WKSTATUS <= 1 && SqlFunc.IsNullOrEmpty(v.TASK_POSIDMOVE) == false)))
                     .ToList();
                int curTaskCount = tasks.Count(v => v.TASK_POSIDTO.Contains(cacheAreaName) || cacheInfoSet.Any(t => v.TASK_POSIDNEXT.Contains(t.Cache_ConvNo) || v.TASK_POSIDTO.Contains(t.Cache_ConvNo)));
                if (curTaskCount < cacheCount)
                {
                    int ph_StatusCount = 0;//光电信号数量
                    foreach (var item in cacheInfoSet)
                    {
                        var cv = ConveyorHelper.GetConveyorSignal(item.Cache_PlcName, item.Cache_ConvNo);
                        if (cv != null && (cv.DB521_Tasknum > 0 || cv.CvDB51_PH_Status))
                        {
                            if (tasks.Any(v => v.TASK_NO == cv.DB521_Tasknum) == false)
                            {
                                ph_StatusCount++;
                            }
                        }
                    }
                    if ((curTaskCount + ph_StatusCount) < cacheCount)
                    {
                        isExecute = true;
                    }
                }
            }
            return isExecute;
        }
        private void WriteTaskToSrm(WCSWriteToSrmSignal srmSignal)
        {
            List list = new List();
            list.AddRange(ExtendsUtil.UshortToByte((ushort)srmSignal.Start_number).ToList());
            list.AddRange(ExtendsUtil.UshortToByte((ushort)srmSignal.End_number).ToList());
            list.AddRange(ExtendsUtil.UshortToByte((ushort)srmSignal.Goodtype).ToList());
            list.AddRange(ExtendsUtil.UshortToByte((ushort)srmSignal.Runmode).ToList());
            list.AddRange(ExtendsUtil.UshortToByte((ushort)srmSignal.RowPos1).ToList());
            list.AddRange(ExtendsUtil.UshortToByte((ushort)srmSignal.Travelpos1).ToList());
            list.AddRange(ExtendsUtil.UshortToByte((ushort)srmSignal.Liftpos1).ToList());
            list.AddRange(ExtendsUtil.UshortToByte((ushort)srmSignal.Fork_start_pos1).ToList());
            list.AddRange(ExtendsUtil.UshortToByte((ushort)srmSignal.RowPos2).ToList());
            list.AddRange(ExtendsUtil.UshortToByte((ushort)srmSignal.Travelpos2).ToList());
            list.AddRange(ExtendsUtil.UshortToByte((ushort)srmSignal.Liftpos2).ToList());
            list.AddRange(ExtendsUtil.UshortToByte((ushort)srmSignal.Fork_dest_pos2).ToList());
            list.AddRange(ExtendsUtil.UintToByte((uint)srmSignal.TaskID).ToList());
            Log4netHelper.Logger_Info.InfoFormat(string.Format("写入任务[{0}]信息", srmSignal.TaskID));
            bool result = WCS_PLCItem.Plc.Write((ushort)WriteDbName, 2, list.ToArray());
            if (result)
            {
                Log4netHelper.Logger_Info.InfoFormat(string.Format("堆垛机[{0}]写入任务[{1}]信息成功", PlcName, srmSignal.TaskID));
            }
            else
            {
                throw new Exception(string.Format("堆垛机[{0}]写入任务[{1}]520写入取放货信号失败", PlcName, srmSignal.TaskID));
            }
        }
        private WCS_TASK QueryMoveTask()
        {
            WCS_TASK task = null;
            var movetaskSet = SugarBase.DB.Queryable().Where(v => v.TASK_COMTYPE == (int)ComTypeEnum.移库 && v.TASK_WKSTATUS <= 1 && v.TASK_SRMNO == WCS_PLCItem.PLC_NAME).ToList();
            if (movetaskSet.Count > 0) task = movetaskSet[0];
            return task;
        }
        /// 
        /// 调整堆垛机出入口顺序
        /// 
        /// 
        private void SrmConvNoMoveToLast(string convNo)
        {
            try
            {
                if (!string.IsNullOrWhiteSpace(convNo))
                {
                    //检测是否是最后一项
                    if (SrmOutInInfoSet[SrmOutInInfoSet.Count() - 1].SRMOUTIN_CONVNO == convNo) return;
                    //查询要调整执行顺序的输送线
                    var outininfo = SrmOutInInfoSet.FirstOrDefault(v => v.SRMOUTIN_CONVNO == convNo);
                    //删除当前
                    SrmOutInInfoSet.Remove(outininfo);
                    //添加到最后
                    SrmOutInInfoSet.Add(outininfo);
                }
            }
            catch (Exception ex)
            {
                Log4netHelper.Logger_Info.ErrorFormat(ex.ToString());
            }
        }
        /// 
        /// 加载堆垛机刷新数据
        /// 
        private void Init_Refresh()
        {
            var srmconvinfoset = Current.WCS_SrmOutInInfoSet.Where(v => v.SRMOUTIN_SRMNO == PlcName && v.SRMOUTIN_ISSTOP == false).OrderBy(p => p.SRMOUTIN_PRIORITY).OrderBy(t => t.SRMOUTIN_SEQUENCE).ToList();
            if (SrmOutInInfoSet.Count != srmconvinfoset.Count ||  //元素个数不相同
                srmconvinfoset.Any(v => v.SRMOUTIN_ISUPDATE))  //元素已更新
            {
                SrmOutInInfoSet = srmconvinfoset;
                SugarBase.DB.Updateable(it => new WCS_SrmOutInInfo() { SRMOUTIN_ISUPDATE = false })
                            .Where(it => it.SRMOUTIN_SRMNO == PlcName)
                            .ExecuteCommand();
            }
        }
        private int _assignInWareCell = 0;
        /// 
        /// 分配入库货位
        /// 
        private void AssignInWareCell()
        {
            if (Interlocked.Exchange(ref _assignInWareCell, 1) == 0)
            {
                try
                {
                    var taskSet = SugarBase.DB.Queryable().Where(v => v.TASK_SRMNO == PlcName && v.TASK_WKSTATUS != 5 && v.TASK_WKSTATUS > 1).ToList().OrderByDescending(v => v.TASK_PRIORITY).ToList();
                    var taskSet_In = taskSet.Where(v => v.TASK_COMTYPE == 1).ToList();
                    foreach (var task in taskSet_In)
                    {
                        if (SrmOutInInfoSet.Any(v => v.SRMOUTIN_CONVNO == task.TASK_POSIDCUR && (v.SRMOUTIN_OUTINTYPE == "in" || v.SRMOUTIN_OUTINTYPE == "outIn")) || task.TASK_POSIDCUR == "1025")
                        {
                            if (string.IsNullOrWhiteSpace(task.TASK_POSIDTO) || task.TASK_POSIDTO == PlcName)
                            {
                                //入库任务分配货位
                                GetWareCell(task);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    LogMessageHelper.RecordLogMessage(string.Format("分配入库货位异常:[{0}]", ex.Message), ex);
                }
                finally
                {
                    Interlocked.Exchange(ref _assignInWareCell, 0);
                }
            }
        }
        public bool GetWareCell(WCS_TASK task)
        {
            string resultMsg = string.Empty;
            //调度接口获取货位
            var getWareCell = Current.WmsInterface.I_WCS_GetWareCell(new GetWareCellParam() { WMSTaskNum = task.TASK_WMSNO.ToString(), TunnelNum = task.TASK_EndTunnelNum, PickUpEquipmentNo = task.TASK_POSIDNEXT });
            if (getWareCell.ResType)
            {
                resultMsg = TryCachHelper.TryTranExecute((db) =>
                {
                    //修改任务分配货位
                    db.Updateable(it => new WCS_TASK() { TASK_WKSTATUS = 2, TASK_POSIDNEXT = getWareCell.CellNo, TASK_POSIDTO = getWareCell.CellNo, TASK_EDITUSERNO = "WCS", TASK_EDITDATETIME = DateTime.Now })
                                .Where(it => it.TASK_NO == task.TASK_NO)
                                .ExecuteCommand();
                    //添加修改明细
                    string msg = string.Format("任务[{0}]分配货位[{1}]成功。", task.TASK_NO, getWareCell.CellNo);
                    CommonData.AddWCS_TASK_DTL(db, task.TASK_NO, task.TASK_NO, task.TASK_POSIDCUR, task.TASK_POSIDNEXT, msg);
                });
            }
            else
            {
                resultMsg = string.Format("任务[{0}]调用接口分配货位[{1}]失败,原因:{2}", task.TASK_NO, getWareCell.CellNo, getWareCell.ResMessage);
                LogMessageHelper.RecordLogMessage(resultMsg);
            }
            if (string.IsNullOrWhiteSpace(resultMsg))
            {
                task.TASK_POSIDNEXT = getWareCell.CellNo;
                task.TASK_POSIDTO = getWareCell.CellNo;
                return true;
            }
            else
            {
                return false;
            }
        }
        #endregion;
    }
}