using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Security.Cryptography;
using System.Text;
using AR;
using Chilkat;

namespace Project
{
    public partial class FMain
    {
        public Boolean _RUN_ROOT_SEQUENCE(eWorkPort target, eSMStep cmdIndex)
        {
            UInt16 idx = 1;
            var mv = PUB.Result.vModel;
            var mc = PUB.Result.mModel;
            var funcName = System.Reflection.MethodBase.GetCurrentMethod().Name;
            var seqTime = PUB.sm.seq.GetTime(cmdIndex);
            var msgType = (Class.eStatusMesage)target;
            var item = target == eWorkPort.Left ? PUB.Result.ItemDataL : PUB.Result.ItemDataR;
            //var Jobtype = VAR.STR[eVarString.JOB_TYPE];
            var CVMode = VAR.BOOL[eVarBool.Use_Conveyor];

            //option check
            var OPT_PrinterOff = PUB.OPT_PRINTEROFF(target);
            var OPT_CameraOff = PUB.OPT_CAMERA();
            var OPT_BYPASS = PUB.OPT_BYPASS();

            //####################################################
            //###	작업시작
            //####################################################
            if (PUB.sm.seq.Get(cmdIndex) == idx++)
            {
                PUB.StatusMessage.set(msgType, $"[{target}] 작업을 시작 합니다");

                //프린터용 백큠이 켜져있다면 오류로 한다.
                if (target == eWorkPort.Left)
                {
                    if (DIO.GetIOOutput(eDOName.PRINTL_AIRON))
                    {
                        PUB.Result.SetResultMessage(eResult.OPERATION, eECode.NEED_AIROFF_L, eNextStep.PAUSE);
                        return false;
                    }
                }
                else
                {
                    if (DIO.GetIOOutput(eDOName.PRINTR_AIRON))
                    {
                        PUB.Result.SetResultMessage(eResult.OPERATION, eECode.NEED_AIROFF_R, eNextStep.PAUSE);
                        return false;
                    }
                }

                //Keyence_Trigger(true);
                PUB.sm.seq.Update(cmdIndex);
                return false;
            }

            //####################################################
            //###	프린터(Y,Z) 안전위치로
            //####################################################
            if (PUB.sm.seq.Get(cmdIndex) == idx++)
            {
                sPositionData PosY, PosZ;
                if (target == eWorkPort.Left)
                {
                    PosY = MOT.GetLMPos(eLMLoc.READY);
                    PosZ = MOT.GetLZPos(eLZLoc.READY);
                }
                else
                {
                    PosY = MOT.GetRMPos(eRMLoc.READY);
                    PosZ = MOT.GetRZPos(eRZLoc.READY);
                }

                //Y축이 준비위가 아닌경우에만 이 처리를 한다.
                if (MOT.getPositionMatch(PosY) == false)
                {
                    if (MOT.CheckMotionPos(seqTime, PosZ, funcName) == false) return false;
                    if (MOT.CheckMotionPos(seqTime, PosY, funcName) == false) return false;
                }

                PUB.sm.seq.Update(cmdIndex);
                return false;
            }

            //####################################################
            //###	로더에 릴이 감지되어있어야 다음 작업을 진행할 수 있음
            //####################################################
            if (PUB.sm.seq.Get(cmdIndex) == idx++)
            {
                //Check Port Ready
                if (PUB.flag.get(eVarBool.FG_RDY_PORT_PC) == false && DIO.GetIOInput(eDIName.PORTC_DET_UP) == false) return false;

                //Check Reel Detect Sensor				
                if (DIO.GetIOInput(eDIName.PORTC_DET_UP) == false) return false;

                //check Reel Limit Sensor
                if (DIO.GetIOInput(eDIName.PORTC_LIM_UP) == true) return false;

                if (CVMode)
                {
                    if (target == eWorkPort.Left)
                    {
                        if (DIO.GetIOInput(eDIName.L_CONV1)) return false;
                        //혹은 컨베이어 가동시간이 5초전이라면 넘어간다 230926
                        if (VAR.I32[eVarInt32.LEFT_ITEM_COUNT] > 0)
                        {
                            if (seqTime.TotalSeconds > 5)
                            {
                                //if (PUB.flag.get(eVarBool.FG_RDY_CAMERA_L) && PUB.flag.get(eVarBool.VS_DETECT_REEL_L) == false)
                                //{
                                //    //비젼에서  없다고  보고  되어있다면  그대로  진행한다..
                                //    PUB.log.AddAT($"(L)비전에서  자재가  감지되지 않아  강제  진행  합니다");
                                //    VAR.I32[eVarInt32.LEFT_ITEM_COUNT] = 0;
                                //}
                                if (VAR.DBL[eVarDBL.CONVL_RUNTIME] > 15)
                                {
                                    PUB.log.AddE($"(L) Buffer cleared due to conveyor exceeding 15 seconds");
                                    VAR.I32[eVarInt32.LEFT_ITEM_COUNT] = 0;
                                }
                                else return false;
                            }
                            else return false;
                        }
                    }
                    else
                    {
                        if (DIO.GetIOInput(eDIName.R_CONV1)) return false;
                        //혹은 컨베이어 가동시간이 5초전이라면 넘어간다 230926
                        if (VAR.I32[eVarInt32.RIGT_ITEM_COUNT] > 0)
                        {
                            if (seqTime.TotalSeconds > 5)
                            {
                                //if (PUB.flag.get(eVarBool.FG_RDY_CAMERA_R) && PUB.flag.get(eVarBool.VS_DETECT_REEL_R) == false)
                                //{
                                //    //비젼에서  없다고  보고  되어있다면  그대로  진행한다..
                                //    PUB.log.AddAT($"(r)비전에서  자재가  감지되지 않아  강제  진행  합니다");
                                //    VAR.I32[eVarInt32.RIGT_ITEM_COUNT] = 0;
                                //}
                                if (VAR.DBL[eVarDBL.CONVR_RUNTIME] > 15)
                                {
                                    PUB.log.AddE($"(R) Buffer cleared due to conveyor exceeding 15 seconds");
                                    VAR.I32[eVarInt32.RIGT_ITEM_COUNT] = 0;
                                }
                                else return false;
                            }
                            else return false;
                        }
                    }
                    //PUB.log.Add($"CVMODE에서 컨베이어 비어있음(SEQ)");
                }

                VAR.TIME[(int)eVarTime.JOBEVENT] = DateTime.Now;
                PUB.sm.seq.Update(cmdIndex);
                return false;
            }

            //####################################################
            //###	피커 사용확인
            //####################################################
            if (PUB.sm.seq.Get(cmdIndex) == idx++)
            {
                PUB.StatusMessage.set(msgType, $"[{target}] 피커(X) 사용 권한 확인");

                if (LockPK.WaitOne(1) == false) return false;
                LockPK.Reset();
                hmi1.AddLockItem((int)target, "PICKER");

                PUB.mot.ClearPosition((int)eAxis.Z_THETA);
                if (target == eWorkPort.Left)
                {
                    //카트가 없으면 동작하지 않게한다.
                    PUB.flag.set(eVarBool.FG_RUN_RIGHT, false, funcName);
                    PUB.flag.set(eVarBool.FG_RUN_LEFT, true, funcName);
                }
                else
                {
                    PUB.flag.set(eVarBool.FG_RUN_LEFT, false, funcName);
                    PUB.flag.set(eVarBool.FG_RUN_RIGHT, true, funcName);
                }

                PUB.sm.seq.Clear(eSMStep.RUN_PICK_RETRY);
                PUB.Result.ItemDataC.VisionData.STime = DateTime.Now;
                PUB.sm.seq.Update(cmdIndex);
                return false;
            }

            //####################################################
            //###	피커 리딩위치 이동
            //####################################################
            if (PUB.sm.seq.Get(cmdIndex) == idx++)
            {
                var PickerRetryCount = AR.VAR.I32[AR.eVarInt32.PickOnRetry];
                //PUB.StatusMessage.set(msgType, $"[{target}] 피커(X) 읽기위치 이동");

                //비젼이 읽혀지지 않다면 안전위치로 이동시킨다.
                //PUB.log.AddAT("비젼이 읽히지 않은 경우에만 리딩위치로 이동시켜준다");

                //완료되지않았다면 비켜준다 220920
                if (PUB.Result.ItemDataC.VisionData.Confirm == false)
                {

                    if (PickerRetryCount == 0)  //처음작업이다
                    {
                        sPositionData Pos;
                        if (target == eWorkPort.Left)
                        {
                            //우측을 사용하지 않으면 좌측으로 이동한다
                            if (PUB.flag.get(eVarBool.FG_ENABLE_RIGHT) == false) Pos = MOT.GetPXPos(ePXLoc.READYR);
                            else Pos = MOT.GetPXPos(ePXLoc.READYL);
                        }
                        else
                        {
                            //우측이나 좌측을 사용하지 않으면 좌측으로 이동한다
                            if (PUB.flag.get(eVarBool.FG_ENABLE_LEFT) == false) Pos = MOT.GetPXPos(ePXLoc.READYL);
                            else Pos = MOT.GetPXPos(ePXLoc.READYR);
                        }

                        if (MOT.CheckMotionPos(seqTime, Pos, funcName) == false) return false;
                        PUB.log.AddAT($"###### Initial work avoidance movement completed ({target})");
                    }
                    else
                    {
                        //재시도 작업이므로 잡아서 79도 돌리는 작업 한다
                        if (PICKER_RETRY(target, eSMStep.RUN_PICK_RETRY) == false) return false;
                        PUB.sm.seq.Clear(eSMStep.RUN_PICK_RETRY);
                    }
                }

                PUB.sm.seq.Update(cmdIndex);
                return false;
            }

            //####################################################
            //###	픽온작업용 시퀀스값 초기화
            //####################################################
            if (PUB.sm.seq.Get(cmdIndex) == idx++)
            {
                VAR.BOOL[eVarBool.wait_for_keyence] = true;
                if (target == eWorkPort.Left)
                {
                    PUB.sm.seq.Clear(eSMStep.RUN_KEYENCE_READ_L);
                    PUB.Result.ItemDataL.Clear(funcName);
                    VAR.BOOL[eVarBool.wait_for_keyenceR] = false;
                    VAR.BOOL[eVarBool.wait_for_keyenceL] = true;
                }
                else
                {
                    PUB.sm.seq.Clear(eSMStep.RUN_KEYENCE_READ_R);
                    PUB.Result.ItemDataR.Clear(funcName);
                    VAR.BOOL[eVarBool.wait_for_keyenceL] = false;
                    VAR.BOOL[eVarBool.wait_for_keyenceR] = true;
                }

                //키엔스데이터 기다리는중
                PUB.sm.seq.Update(cmdIndex);
                return false;
            }

            //####################################################
            //###	키엔스바코드 확인 작업
            //####################################################
            if (PUB.sm.seq.Get(cmdIndex) == idx++)
            {
                EResultKeyence Complete = EResultKeyence.Wait;
                if (target == eWorkPort.Left)
                    Complete = KEYENCE_READ(target, eSMStep.RUN_KEYENCE_READ_L);
                else
                    Complete = KEYENCE_READ(target, eSMStep.RUN_KEYENCE_READ_R);

                if (Complete == EResultKeyence.Wait)
                {
                    //읽을수있도록 좌표를 이동시켜준다
                    sPositionData Pos;
                    if (target == eWorkPort.Left)
                    {
                        //우측을 사용하지 않으면 좌측으로 이동한다
                        if (PUB.flag.get(eVarBool.FG_ENABLE_RIGHT) == false) Pos = MOT.GetPXPos(ePXLoc.READYR);
                        else Pos = MOT.GetPXPos(ePXLoc.READYL);
                    }
                    else
                    {
                        //우측이나 좌측을 사용하지 않으면 좌측으로 이동한다
                        if (PUB.flag.get(eVarBool.FG_ENABLE_LEFT) == false) Pos = MOT.GetPXPos(ePXLoc.READYL);
                        else Pos = MOT.GetPXPos(ePXLoc.READYR);
                    }

                    //sPositionData Pos = target == eWorkPort.Left ? MOT.GetPXPos(ePXLoc.READYL) : MOT.GetPXPos(ePXLoc.READYR);
                    if (MOT.getPositionMatch(Pos) == false)
                    {
                        PUB.log.AddAT($"######Avoidance movement II due to no vision data({target})");
                        MOT.Move(Pos);
                    }
                    return false;
                }
                else if (Complete == EResultKeyence.MultiSID)
                {
                    //이미 사용자 확인창
                    if (PUB.flag.get(eVarBool.FG_WAIT_INFOSELECT))
                    {
                        //아무것도 하지 않는다
                        //사용자가 정보를 설정하는 중
                    }
                    else
                    {
                        bool SHowUserFormINF = true;

                        //사용자 확인창을 표시한다
                        if (SHowUserFormINF) //다중SID정보 선택건
                        {
                            this.Invoke(new Action(() =>
                            {
                                PUB.log.Add("Calling user selection window (INF)");
                                var f = new Dialog.fSelectSIDInformation();
                                f.Show();
                            }));
                        }
                    }
                    return false;
                }
                else if (Complete == EResultKeyence.TimeOut)
                {
                    //이미 사용자 확인창
                    if (PUB.flag.get(eVarBool.FG_WAIT_LOADERINFO))
                    {
                        //아무것도 하지 않는다
                        //사용자가 정보를 설정하는 중
                    }
                    else
                    {
                        //반복시도횟수가 설정되지 않았거나 최대를 초과하면 사용자 확인창을 띄운다
                        bool ShowUserFormBCD = false;
                        if (AR.SETTING.Data.RetryPickOnMaxCount == 0)
                        {
                            PUB.log.Add($"Showing user confirmation window due to no pick-on retry count");
                            ShowUserFormBCD = true;
                        }
                        else if (AR.VAR.I32[AR.eVarInt32.PickOnRetry] >= AR.SETTING.Data.RetryPickOnMaxCount)
                        {
                            PUB.log.Add($"Pick-on retry count exceeded (Max: {AR.SETTING.Data.RetryPickOnMaxCount})");
                            ShowUserFormBCD = true;
                        }
                        else
                        {
                            if (VAR.BOOL[eVarBool.Need_UserConfirm_Data])
                            {
                                PUB.log.Add($"Need to show user confirmation window");
                                ShowUserFormBCD = true;
                            }
                            else
                            {
                                //읽은데이터가 atkstandard라면 바로 팝업을 띄운다
                                if (PUB.Result.ItemDataC.VisionData.SID.isEmpty() || PUB.Result.ItemDataC.VisionData.SID_Trust == false)
                                {
                                    PUB.log.Add($"Retrying pick-on ({AR.VAR.I32[AR.eVarInt32.PickOnRetry]}/{AR.SETTING.Data.RetryPickOnMaxCount})");
                                    ShowUserFormBCD = false;
                                }
                                else
                                {
                                    PUB.log.Add($"SID value exists, showing user confirmation window instead of retrying");
                                    ShowUserFormBCD = true;
                                }
                            }
                        }
                        if (ShowUserFormBCD)
                        {
                            this.Invoke(new Action(() =>
                            {
                                var itemC = PUB.Result.ItemDataC;
                                PUB.log.Add("Calling user confirmation window");
                                var f = new Dialog.fLoaderInfo(itemC.VisionData.bcdMessage);
                                f.Show();
                            }));
                        }
                        else
                        {
                            //픽온재시도
                            PUB.sm.seq.Clear(eSMStep.RUN_PICK_RETRY);
                            VAR.I32[eVarInt32.PickOnRetry] += 1;//, 1);
                            VAR.BOOL[eVarBool.JOB_PickON_Retry] = true;

                            PUB.log.Add($"Pick-on retry ({VAR.I32[eVarInt32.PickOnRetry]})");
                            PUB.sm.seq.Update(cmdIndex, -2);
                        }
                    }
                    return false;
                }

                //키엔스대기상태를 설정해준다
                VAR.BOOL[eVarBool.wait_for_keyence] = false;
                if (target == eWorkPort.Left) VAR.BOOL[eVarBool.wait_for_keyenceL] = false;
                else VAR.BOOL[eVarBool.wait_for_keyenceR] = false;

                PUB.Result.ItemDataC.VisionData.ReelSize = DIO.getCartSize(1);
                PUB.log.AddI($"[{target}] Keyence verification completed (Size: {PUB.Result.ItemDataC.VisionData.ReelSize})");
                PUB.log.AddI($"[{target}] Print Position:{PUB.Result.ItemDataC.VisionData.PrintPositionData}");


                //픽온작업용 시퀀스값 초기화
                if (target == eWorkPort.Left)
                {
                    //프린트Z축을 픽온위치에둔다.
                    var PosLM = MOT.GetLZPos(eLZLoc.PICKON);
                    MOT.Move(PosLM);
                    PUB.sm.seq.Clear(eSMStep.RUN_PICKER_ON_L);
                    PUB.sm.seq.Clear(eSMStep.RUN_PRINTER_F);
                    PUB.sm.seq.Clear(eSMStep.RUN_PRINTER_ON_F);
                    //PUB.sm.seq.Clear(eSMStep.RUN_PRINTER_OFF_F);
                    PUB.Result.ItemDataC.CopyTo(ref PUB.Result.ItemDataL);
                    PUB.log.Add($"[{target}] Vision data copy (C->L) ID:{PUB.Result.ItemDataL.VisionData.RID}");
                }
                else
                {
                    var PosRM = MOT.GetRZPos(eRZLoc.PICKON);
                    MOT.Move(PosRM);
                    PUB.sm.seq.Clear(eSMStep.RUN_PICKER_ON_R);
                    PUB.sm.seq.Clear(eSMStep.RUN_PRINTER_R);
                    PUB.sm.seq.Clear(eSMStep.RUN_PRINTER_ON_R);
                    //PUB.sm.seq.Clear(eSMStep.RUN_PRINTER_OFF_R);
                    PUB.Result.ItemDataC.CopyTo(ref PUB.Result.ItemDataR);
                    PUB.log.Add($"[{target}] Vision data copy (C->R) ID:{PUB.Result.ItemDataR.VisionData.RID}");
                }

                //트리거 OFF
                System.Threading.Tasks.Task.Run(() =>
                {
                    if (PUB.keyenceF != null) PUB.keyenceF.Trigger(false);
                    if (PUB.keyenceR != null) PUB.keyenceR.Trigger(false);
                });


                PUB.log.Add($"[{target}] Print Pos={item.VisionData.PrintPositionData}");
                PUB.sm.seq.Update(cmdIndex);
                return false;
            }

            //####################################################
            //###	릴아이디 사용 체크 221107
            //####################################################
            if (PUB.sm.seq.Get(cmdIndex) == idx++)
            {
                //만약 현재의 바코드가 이전바코드와 동일하다면 오류로 처리한다.
                var pre_ridN = VAR.STR[eVarString.PrePick_ReelIDNew].Trim();
                var pre_ridO = VAR.STR[eVarString.PrePick_ReelIDOld].Trim();
                var pre_targ = VAR.STR[eVarString.PrePick_ReelIDTarget].ToUpper().Trim();

                var cur_ridN = target == eWorkPort.Left ? PUB.Result.ItemDataL.VisionData.RID : PUB.Result.ItemDataR.VisionData.RID.Trim();
                var cur_ridO = target == eWorkPort.Left ? PUB.Result.ItemDataL.VisionData.RID0 : PUB.Result.ItemDataR.VisionData.RID0.Trim();

                if (OPT_BYPASS)
                {
                    PUB.log.Add($"Bypass mode - skipping previous reel ID check");
                }
                else
                {
                    if (pre_ridN.isEmpty() == false) //일단 무조건 신규아이디가 있어야한다
                    {

                        //이전과 동일한 ID를 처리했다 오류, 스카이웍스는 본래의 ID를 사용하므로 이곳에서 걸린다
                        if (pre_ridN.Equals(cur_ridN))
                        {
                            if (pre_targ == "LEFT")
                                PUB.Result.SetResultMessage(eResult.OPERATION, eECode.PRE_USE_REELID_L, eNextStep.ERROR, target, pre_ridN, cur_ridN);
                            else
                                PUB.Result.SetResultMessage(eResult.OPERATION, eECode.PRE_USE_REELID_R, eNextStep.ERROR, target, pre_ridN, cur_ridN);
                        }
                        else
                        {
                            PUB.log.Add($"New ID usage check OK PRE={pre_ridN},NEW={cur_ridN}");

                            if (pre_ridO.isEmpty() == false && cur_ridO.isEmpty() == false) //구형아이디는 둘다 값이 있을때 처리한다.
                            {
                                if (pre_ridO.Equals(cur_ridO))
                                {
                                    if (pre_targ == "LEFT")
                                        PUB.Result.SetResultMessage(eResult.OPERATION, eECode.PRE_USE_REELID_L, eNextStep.ERROR, target, pre_ridO, cur_ridO);
                                    else
                                        PUB.Result.SetResultMessage(eResult.OPERATION, eECode.PRE_USE_REELID_R, eNextStep.ERROR, target, pre_ridO, cur_ridO);
                                }
                                else PUB.log.Add($"New ID usage check (ORG) OK PRE={pre_ridO},NEW={cur_ridO}");
                            }
                            else
                            {
                                PUB.log.Add($"New ID usage check (ORG) SKIP (NO DATA) PRE={pre_ridO},NEW={cur_ridO}");
                            }
                        }
                    }
                    else
                    {
                        PUB.log.Add($"First work - skipping previous reel ID check");
                    }

                    VAR.STR[eVarString.PrePick_ReelIDNew] = cur_ridN;
                    VAR.STR[eVarString.PrePick_ReelIDOld] = cur_ridO;
                    VAR.STR[eVarString.PrePick_ReelIDTarget] = target.ToString();

                    PUB.log.Add($"Previous work reel ID set values N={cur_ridN},O={cur_ridO}");
                }

                PUB.sm.seq.Update(cmdIndex);
                return false;
            }

            //####################################################
            //###	bypass check 230510
            //####################################################
            if (PUB.sm.seq.Get(cmdIndex) == idx++)
            {


                //컨베이어모드에서는 좌측 센서에 릴이 있다면 대기해야한다.  230829
                if (CVMode)
                {
                    if (target == eWorkPort.Left)
                    {
                        if (DIO.GetIOInput(eDIName.L_CONV1)) return false;
                        //혹은 컨베이어 가동시간이 5초전이라면 넘어간다 230926
                        if (VAR.I32[eVarInt32.LEFT_ITEM_COUNT] > 0) return false;
                        //{
                        //    var cvrun = VAR.DBL[eVarDBL.LEFT_ITEM_PICKOFF];
                        //    if (cvrun < 6) return false;
                        //}
                    }
                    else
                    {
                        if (DIO.GetIOInput(eDIName.R_CONV1)) return false;
                        //혹은 컨베이어 가동시간이 5초전이라면 넘어간다 230926
                        if (VAR.I32[eVarInt32.RIGT_ITEM_COUNT] > 0) return false;
                        //{
                        //    var cvrun = VAR.DBL[eVarDBL.RIGT_ITEM_PICKOFF];
                        //    if (cvrun < 6) return false;
                        //}
                    }
                    PUB.log.Add($"Conveyor empty in CV MODE (SEQ)");
                }

                PUB.sm.seq.Update(cmdIndex);
                return false;
            }

            //####################################################
            //###	PICKER ON
            //####################################################
            if (PUB.sm.seq.Get(cmdIndex) == idx++)
            {
                bool Complete = false;
                if (target == eWorkPort.Left)
                {
                    if (PRINTER(target, eSMStep.RUN_PRINTER_F))
                        PRINTER_ON(target, eSMStep.RUN_PRINTER_ON_F);
                    Complete = PICKER_ON(target, eSMStep.RUN_PICKER_ON_L);
                }
                else
                {
                    if (PRINTER(target, eSMStep.RUN_PRINTER_R))
                        PRINTER_ON(target, eSMStep.RUN_PRINTER_ON_R);
                    Complete = PICKER_ON(target, eSMStep.RUN_PICKER_ON_R);
                }

                if (Complete == false) return false;
                //PUB.log.Add($"[{target}] 피커 ON 작업 완료");
                VAR.I32.Clear((int)eVarInt32.PickOnRetry);

                //픽온작업용 시퀀스값 초기화
                if (target == eWorkPort.Left)
                {
                    PUB.sm.seq.Clear(eSMStep.RUN_PICKER_OFF_L);
                    //PUB.Result.ItemData[1].CopyTo(ref PUB.Result.ItemData[0]);
                    PUB.log.Add($"Barcode data copy (LEFT)");

                    PUB.flag.set(eVarBool.FG_BUSY_LEFT, true, funcName);
                    //프린터용 AIR처리해준다.
                    DIO.SetPrintLVac(ePrintVac.inhalation);
                    DIO.SetPrintLAir(true);
                    //PUB.Result.ItemData[1].UpdateTo(ref PUB.Result.ItemData[0]);
                }
                else
                {
                    PUB.sm.seq.Clear(eSMStep.RUN_PICKER_OFF_R);
                    //PUB.Result.ItemData[1].CopyTo(ref PUB.Result.ItemData[0]);
                    PUB.log.Add($"Barcode data copy (RIGHT)");

                    PUB.flag.set(eVarBool.FG_BUSY_RIGHT, true, funcName);
                    //프린터용 AIR처리해준다.
                    DIO.SetPrintRVac(ePrintVac.inhalation);
                    DIO.SetPrintRAir(true);
                    //PUB.Result.ItemData[1].UpdateTo(ref PUB.Result.ItemData[2]);
                }

                PUB.Result.ItemDataC.Clear($"[{target}] Pick-on completed"); //Clear after transmission

                KeyenceBarcodeDataF = string.Empty;
                KeyenceBarcodeDataR = string.Empty;
                //PUB.log.AddAT($"바코드데이터 삭제(CENTER)");

                //다음데이터를 읽을 수 있도록 트리거를 전송한다
                System.Threading.Tasks.Task.Run(() =>
                {
                    if (PUB.keyenceF != null) PUB.keyenceF.Trigger(true);
                    if (PUB.keyenceR != null) PUB.keyenceR.Trigger(true);
                });

                //Keyence_Trigger(true);

                //SID목록을 저장한다 231005

                string sid, prn; sid = prn = "";
                if (target == eWorkPort.Left)
                {
                    sid = PUB.Result.ItemDataL.VisionData.SID;
                    prn = PUB.Result.ItemDataL.VisionData.PrintPositionData;
                }
                else
                {
                    sid = PUB.Result.ItemDataR.VisionData.SID;
                    prn = PUB.Result.ItemDataR.VisionData.PrintPositionData;
                }

                if (sid.isEmpty() == false)
                {
                    if (PUB.Result.PrintPostionList.ContainsKey(sid) == false)
                    {
                        PUB.Result.PrintPostionList.Add(sid, prn);
                        PUB.log.AddAT($"Print position saved SID:{sid} = {prn}");
                    }
                    else
                    {
                        var predata = PUB.Result.PrintPostionList[sid];
                        if (predata != prn)
                        {
                            PUB.log.AddAT($"Print position save value changed SID:{sid} = {predata} -> {prn}");
                            PUB.Result.PrintPostionList[sid] = prn;
                        }
                    }
                }

                PUB.sm.seq.Update(cmdIndex);
                return false;
            }

            //####################################################
            //###	PICKER OFF
            //####################################################
            if (PUB.sm.seq.Get(cmdIndex) == idx++)
            {
                bool Complete = false;
                if (target == eWorkPort.Left)
                {
                    if (PRINTER(target, eSMStep.RUN_PRINTER_F))
                        PRINTER_ON(target, eSMStep.RUN_PRINTER_ON_F);
                    Complete = PICKER_OFF(target, eSMStep.RUN_PICKER_OFF_L);
                }
                else
                {
                    if (PRINTER(target, eSMStep.RUN_PRINTER_R))
                        PRINTER_ON(target, eSMStep.RUN_PRINTER_ON_R);
                    Complete = PICKER_OFF(target, eSMStep.RUN_PICKER_OFF_R);
                }

                if (Complete == false) return false;

                //PUB.log.Add($"[{target}] 피커 OFF 작업 완료");
                PUB.sm.seq.Update(cmdIndex);
                return false;
            }

            //####################################################
            //###	피커위치로 이동시키고 권한을 넘겨준다
            //####################################################
            if (PUB.sm.seq.Get(cmdIndex) == idx++)
            {

                //프린터와 pickoin 작업을 진행한다
                if (target == eWorkPort.Left)
                {
                    if (PRINTER(target, eSMStep.RUN_PRINTER_F))
                        PRINTER_ON(target, eSMStep.RUN_PRINTER_ON_F);
                }
                else
                {
                    if (PRINTER(target, eSMStep.RUN_PRINTER_R))
                        PRINTER_ON(target, eSMStep.RUN_PRINTER_ON_R);
                }

                //X축 중앙으로 이동
                var Pos = MOT.GetPXPos(ePXLoc.PICKON);
                if (target == eWorkPort.Left && PUB.flag.get(eVarBool.FG_ENABLE_RIGHT) == false)
                    Pos = MOT.GetPXPos(ePXLoc.READYR); //우측이 꺼져잇다면 바코드 읽도록 우측으로 비켜준다
                if (target == eWorkPort.Right && PUB.flag.get(eVarBool.FG_ENABLE_LEFT) == false)
                    Pos = MOT.GetPXPos(ePXLoc.READYL);  //좌측이 꺼져있다면 바코드 읽도록 좌측으로 비켜준다


                if (MOT.CheckMotionPos(seqTime, Pos, funcName) == false) return false;

                //X축을 놓아준다
                LockPK.Set();
                hmi1.RemoveLockItem((int)target, "LD-FRONT");
                PUB.logDbg.Add($"[{target}] X축 권한 해제");
                PUB.mot.ClearPosition((int)eAxis.Z_THETA);

                //if (target == eWorkShuttle.Left)
                //	PUB.sm.seq.Clear(eSMStep.RUN_PRINTER_F);
                //else
                //	PUB.sm.seq.Clear(eSMStep.RUN_PRINTER_R);

                PUB.sm.seq.Update(cmdIndex);
                return false;
            }

            //####################################################
            //###	프린터
            //####################################################
            if (PUB.sm.seq.Get(cmdIndex) == idx++)
            {
                bool Complete = false;
                if (target == eWorkPort.Left)
                    Complete = PRINTER(target, eSMStep.RUN_PRINTER_F);
                else
                    Complete = PRINTER(target, eSMStep.RUN_PRINTER_R);
                if (Complete == false) return false;

                //PUB.log.Add($"[{target}] 프린터 작업 완료");

                //if (target == eWorkShuttle.Left)
                //	PUB.sm.seq.Clear(eSMStep.RUN_PRINTER_ON_F);
                //else
                //	PUB.sm.seq.Clear(eSMStep.RUN_PRINTER_ON_R);

                PUB.sm.seq.Update(cmdIndex);
                return false;
            }


            //####################################################
            //###	프린터 PICK ON
            //####################################################
            if (PUB.sm.seq.Get(cmdIndex) == idx++)
            {
                bool Complete = false;
                if (target == eWorkPort.Left)
                    Complete = PRINTER_ON(target, eSMStep.RUN_PRINTER_ON_F);
                else
                    Complete = PRINTER_ON(target, eSMStep.RUN_PRINTER_ON_R);
                if (Complete == false) return false;

                //PUB.log.Add($"[{target}] 프린터 ON 작업 완료");

                if (target == eWorkPort.Left)
                {
                    PUB.sm.seq.Clear(eSMStep.RUN_PRINTER_OFF_F);
                    DIO.SetPrintLAir(false);
                }
                else
                {
                    PUB.sm.seq.Clear(eSMStep.RUN_PRINTER_OFF_R);
                    DIO.SetPrintRAir(false);
                }

                PUB.sm.seq.Update(cmdIndex);
                return false;
            }


            //####################################################
            //###	프린터 PICK OFF
            //####################################################
            if (PUB.sm.seq.Get(cmdIndex) == idx++)
            {
                bool Complete = false;
                if (target == eWorkPort.Left)
                    Complete = PRINTER_OFF(target, eSMStep.RUN_PRINTER_OFF_F);
                else
                    Complete = PRINTER_OFF(target, eSMStep.RUN_PRINTER_OFF_R);
                if (Complete == false) return false;

                //PUB.log.Add($"[{target}] 프린터 OFF 작업 완료");
                PUB.sm.seq.Update(cmdIndex);
                return false;
            }

            //####################################################
            //###	프린터(Y,Z) 안전위치로
            //####################################################
            if (PUB.sm.seq.Get(cmdIndex) == idx++)
            {
                sPositionData PosZ;
                if (target == eWorkPort.Left)
                {
                    PosZ = MOT.GetLZPos(eLZLoc.READY);
                }
                else
                {
                    PosZ = MOT.GetRZPos(eRZLoc.READY);
                }
                if (MOT.CheckMotionPos(seqTime, PosZ, funcName) == false) return false;

                //카메라를 사용한다면  검증해야하니  컨베이어를  멈춘다
                if (OPT_CameraOff == false)
                {
                    if (target == eWorkPort.Left)
                        PUB.iLockCVL.set((int)eILockCV.VISION, true, funcName);
                    else
                        PUB.iLockCVR.set((int)eILockCV.VISION, true, funcName);
                }


                //Z가 올라갔으니 컨베이어를 돌려도된다
                if (CVMode)
                {
                    //카메라를 사용하지 않는다면 바로 OFF 한다
                    if (VAR.BOOL[eVarBool.Opt_DisableCamera] == false)
                    {
                        if (target == eWorkPort.Left)
                            PUB.iLockCVL.set((int)eILockCV.BUSY, false, funcName);
                        else
                            PUB.iLockCVR.set((int)eILockCV.BUSY, false, funcName);
                    }
                }

                PUB.sm.seq.Update(cmdIndex);
                return false;
            }

            //####################################################
            //###	실리더 원위치 이동시킨다
            //####################################################
            if (PUB.sm.seq.Get(cmdIndex) == idx++)
            {
                if (target == eWorkPort.Left)
                {
                    DIO.SetOutput(eDOName.PRINTL_FWD, false);
                }
                else
                {
                    DIO.SetOutput(eDOName.PRINTR_FWD, false);
                }
                PUB.sm.seq.Update(cmdIndex);
                return false;
            }
            if (PUB.sm.seq.Get(cmdIndex) == idx++)
            {
                if (target == eWorkPort.Left)
                {
                    if (DIO.checkDigitalO(eDIName.L_PICK_BW, seqTime, true) != eNormalResult.True) return false;
                }
                else
                {
                    if (DIO.checkDigitalO(eDIName.R_PICK_BW, seqTime, true) != eNormalResult.True) return false;
                }
                PUB.sm.seq.Update(cmdIndex);
                return false;
            }


            //####################################################
            //###	프린터(Y,Z) 안전위치로
            //####################################################
            if (PUB.sm.seq.Get(cmdIndex) == idx++)
            {
                sPositionData PosY, PosZ;
                if (target == eWorkPort.Left)
                {
                    PosY = MOT.GetLMPos(eLMLoc.READY);
                    PosZ = MOT.GetLZPos(eLZLoc.READY);
                    PUB.sm.seq.Clear(eSMStep.RUN_QRVALID_F);
                }
                else
                {
                    PosY = MOT.GetRMPos(eRMLoc.READY);
                    PosZ = MOT.GetRZPos(eRZLoc.READY);
                    PUB.sm.seq.Clear(eSMStep.RUN_QRVALID_R);
                }
                if (MOT.CheckMotionPos(seqTime, PosZ, funcName) == false) return false;
                if (MOT.CheckMotionPos(seqTime, PosY, funcName) == false) return false;
                PUB.sm.seq.Update(cmdIndex);
                return false;
            }


            //####################################################
            //###	QR코드 검증
            //####################################################
            if (PUB.sm.seq.Get(cmdIndex) == idx++)
            {
                bool Complete = false;

                if (OPT_CameraOff)  //카메라사용하지 않음
                {
                    PUB.log.Add($"QR Validation SKIP:{target} - Camera Off");
                    Complete = true;
                    item.PrintQRValidResult = "SKIP";


                    //var sendok = WS_Send(target, WS, item.guid, "TRIG", item.VisionData.PrintQRData);
                }
                else
                {
                    if (target == eWorkPort.Left)
                        Complete = QR_VALIDATION(target, eSMStep.RUN_QRVALID_F);
                    else
                        Complete = QR_VALIDATION(target, eSMStep.RUN_QRVALID_R);
                }
                if (Complete == false) return false;
                PUB.log.Add($"QR Validation Complete:{target}");

                //작업이완료되었다
                if (target == eWorkPort.Left)
                {
                    PUB.iLockCVL.set((int)eILockCV.BUSY, false, funcName);
                    PUB.iLockCVL.set((int)eILockCV.VISION, false, funcName);
                    WS_Send(eWorkPort.Left, PUB.wsL, "", "OFF", "");
                }
                else
                {
                    PUB.iLockCVR.set((int)eILockCV.BUSY, false, funcName);
                    PUB.iLockCVR.set((int)eILockCV.VISION, false, funcName);
                    WS_Send(eWorkPort.Right, PUB.wsR, "", "OFF", "");
                }

                PUB.sm.seq.Update(cmdIndex);
                return false;
            }


            //####################################################
            //###	결과업데이트(22/07/07)
            //####################################################
            if (PUB.sm.seq.Get(cmdIndex) == idx++)
            {
                item.JobEnd = DateTime.Now;

                //전송한다
                var reelsize = "0";
                if (item.VisionData.ReelSize == eCartSize.Inch7) reelsize = "7";
                else if (item.VisionData.ReelSize == eCartSize.Inch13) reelsize = "13";
                var reelinfo = new
                {
                    AMKOR_SID = item.VisionData.SID,// tbsid.Text,
                    AMKOR_BATCH = item.VisionData.BATCH,// tbbatch.Text,
                    LABEL_ID = item.VisionData.RID,// tbrid.Text,
                    LABEL_VENDOR_LOT = item.VisionData.VLOT,// tblot.Text,
                    LABEL_AMKOR_SID = item.VisionData.SID,// tbsid.Text,
                    LABEL_QTY = item.VisionData.QTY,// tbqty.Text,
                    LABEL_MANUFACTURER = item.VisionData.VNAME,// tbvname.Text,
                    LABEL_PRODUCTION_DATE = item.VisionData.MFGDATE,// tbmfg.Text,
                    LABEL_INCH_INFO = reelsize,// tbinch.Text,
                    LABEL_PART_NUM = item.VisionData.PARTNO,// tbpart.Text,
                    EQP_ID = AR.SETTING.Data.McName,// tbeqid.Text,
                    EQP_NAME = $"Auto Label Attach {SETTING.Data.McName}",
                    BADGE = string.Empty,
                    OPER_NAME = string.Empty,
                    CPN = item.VisionData.MCN,
                    TARGET = item.VisionData.Target,
                };

                bool rlt = false;
                string errmsg = string.Empty;
                //var systembypassmode = SETTING PUB.Result.vModel.Title.Equals("BYPASS"); CVMode == true && 
                if (SETTING.Data.SystemBypass == false)
                {
                    rlt = PUB.UpdateWMS(item.VisionData); //rlt = Amkor.RestfulService.Inbound_label_attach_reel_info(reelinfo, out errmsg);
                    PUB.log.AddE("WMS transmission " + (rlt ? "success" : "failed") + $": {errmsg}");
                    if (rlt == false)   //230927 - 오류발생시 
                    {
                        PUB.Result.SetResultMessage(eResult.OPERATION, eECode.INBOUNDWEBAPIERROR, eNextStep.PAUSE, target, errmsg);
                        return false; ;
                    }
                }
                else
                {
                    errmsg = "bypass";
                    rlt = false;
                    PUB.log.AddAT($"WMS save disabled due to System bypass");
                }
                if (errmsg.Length > 190) errmsg = errmsg.Substring(0, 190); //230810 maxlength error
                SaveData_EE(item, (target == eWorkPort.Left ? "L" : "R"), (rlt ? "OK" : errmsg), "root_sequence");
                //RefreshList();  //목록업데이트
                EEMStatus.AddStatusCount(1, $"{item.VisionData.SID}|{item.VisionData.RID}");    //eem 추가 230620
                PUB.sm.seq.Update(cmdIndex);
                return false;
            }

            //####################################################
            //### 다시`` 처음으로 이동
            //####################################################
            if (PUB.sm.seq.Get(cmdIndex) == idx++)
            {
                PUB.StatusMessage.set(msgType, $"[{target}] 전체작업완료 초기화");
                UserStepWait(target);

                item.Clear($"{target}:{funcName}");
                if (target == eWorkPort.Left)
                {
                    PUB.flag.set(eVarBool.FG_BUSY_LEFT, false, funcName);
                }
                else
                {
                    PUB.flag.set(eVarBool.FG_BUSY_RIGHT, false, funcName);
                }

                VAR.TIME[(int)eVarTime.JOBEVENT] = DateTime.Now;
                PUB.log.AddI($"[{target}] Work completed");
                PUB.sm.seq.Clear(cmdIndex);
                return true;
            }

            PUB.sm.seq.Clear(cmdIndex);
            return true;
        }
    }
}