using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Windows.Forms;
using AR;

namespace UIControl
{
    public partial class HMI : System.Windows.Forms.Control
    {
        arDev.DIO.IDIO dio = null;
        arDev.MOT.IMotion mot = null;

        #region "Variable - Private"
        Timer tm;
        Boolean _ardebugmode = false;
        eScean _scean = eScean.Nomal;
        //기타 내부 변수
        int AnimationStepConv = 30; //컨베어 이동 애니메이션 최대 값
        //int AnimationStepPort = 9;  //포트 이동 애니메이션 최대 값
        Boolean bRemakeRect = true; //이값이 활성화되면 각 영역을 다시 그리게 된다
        DateTime updatetime = DateTime.Now; //화면을 다시 그린 시간
        Brush BRPortBg = new SolidBrush(Color.FromArgb(50, Color.DimGray));
        Brush BRDetectDn = new SolidBrush(Color.FromArgb(50, Color.DimGray));
        StringFormat sfCenter;
        StringFormat sfLeft = new StringFormat { Alignment = StringAlignment.Near, LineAlignment = StringAlignment.Center };
        SolidBrush brVacOff = new SolidBrush(Color.FromArgb(150, Color.White));
        SolidBrush brVacOn = new SolidBrush(Color.FromArgb(200, Color.Lime));
        Font arFont_MotPosName { get; set; }

        Pen penVacOn = new Pen(Color.Red, 5);
        Pen penVacOff = new Pen(Color.Black, 5);

        //영역(큰 그림?) (bRemakeRect 에 의 해 생성된다)
        RectangleF rect_main = RectangleF.Empty;
        // RectangleF rect_frontShuttle = RectangleF.Empty;
        //RectangleF rect_rearShuttle = RectangleF.Empty;
        RectangleF rect_conveyor = RectangleF.Empty;
        RectangleF rect_picker = RectangleF.Empty;
        RectangleF rect_printl = RectangleF.Empty;
        RectangleF rect_printr = RectangleF.Empty;


        //영역(피커)
        RectangleF rect_picker_left = RectangleF.Empty;
        RectangleF rect_picker_front_vac1 = RectangleF.Empty;
        RectangleF rect_picker_front_vac2 = RectangleF.Empty;
        RectangleF rect_picker_front_vac3 = RectangleF.Empty;
        RectangleF rect_picker_front_vac4 = RectangleF.Empty;

        //X축 포트 (F-L:0, F-R:1, R-L:2, R-R:3
        //RectangleF[] rect_port = new RectangleF[4];
        RectangleF[] rect_zone = new RectangleF[11];

        //CIcon[] icons = new CIcon[7];
        List<CMenuButton> Buttons = new List<CMenuButton>();
        List<CMenuButton> menuButtons = new List<CMenuButton>();

        #endregion

        #region "Variable - Public"
        // public double[] arMotorPosition = new double[] { 0, 0, 0, 0, 0 };
        public int ConveyorRunPoint = 1;    //컨베어 모터 이동시 이동 화살표의 위치값(내부 타이머에의해 증가함)
        public double arMcLengthW = 1460;
        public double arMcLengthH = 1350;//
        public bool CVLeftBusy = false;
        public bool CVLeftReady = false;
        public bool CVRightBusy = false;
        public bool CVRightReady = false;
        #endregion

        RectangleF rect_vision = RectangleF.Empty;

        public string arVision_RID { get; set; }
        public string arVision_SID { get; set; }

        RectangleF rect_zlaxis = RectangleF.Empty;// new RectangleF((float)motZLPosX, (float)motZPosY, motZwPx, (float)motZhPx);

        public Boolean arVisionProcessL { get; set; }
        public Boolean arVisionProcessC { get; set; }
        public Boolean arVisionProcessR { get; set; }

        #region "Property"

        public int arCountV0 { get; set; }
        public int arCountV1 { get; set; }
        public int arCountV2 { get; set; }

        public int arCountPrint0 { get; set; }
        public int arCountPrint1 { get; set; }

        public Boolean arPortLItemOn { get; set; }
        public Boolean arPortRItemOn { get; set; }

        public Boolean arPLItemON { get; set; }
        public Boolean arPRItemON { get; set; }
        public Boolean arMagnet0 { get; set; }
        public Boolean arMagnet1 { get; set; }
        public Boolean arMagnet2 { get; set; }
        public Boolean arPickerSafeZone { get; set; }

        private Padding _padding = new Padding(0);
        public new Padding Padding { get { return _padding; } set { _padding = value; bRemakeRect = true; this.Invalidate(); } }

        /// <summary>
        /// 현재 메뉴가 표시되어있는가?
        /// </summary>
        public Boolean HasPopupMenu { get; private set; }
        /// <summary>
        /// 현재표시된 메뉴는 사용자의 입력을 반드시 받아야 하는가?
        /// </summary>
        public Boolean PopupMenuRequireInput { get; private set; }
        public Font arFont_PortMessage { get; set; }


        public eScean Scean { get { return _scean; } set { _scean = value; bRemakeRect = true; this.Invalidate(); } }

        //컨베이어에 설치된 자재 감지 센서
        public Boolean[] arDI_Cv_Detect { get; set; }
        //컨베이어 입구 안전 센서
        public Boolean arInitMOT { get; set; }
        public Boolean arJobEND { get; set; }
        public Boolean arLowDiskSpace { get; set; } //용량 부족 메세지 여부
        public double arFreespace { get; set; } //남은 디스크 용량 비율

        public Boolean arFGVision0RDY { get; set; }
        public Boolean arFGVision1RDY { get; set; }
        public Boolean arFGVision2RDY { get; set; }

        public Boolean arFGVision0END { get; set; }
        public Boolean arFGVision1END { get; set; }
        public Boolean arFGVision2END { get; set; }

        public Boolean arFGPrinter0RDY { get; set; }
        public Boolean arFGPrinter1RDY { get; set; }
        public Boolean arFGPrinter2RDY { get; set; }

        public Boolean arFGPrinter0END { get; set; }
        public Boolean arFGPrinter1END { get; set; }
        public Boolean arFGPrinter2END { get; set; }


        public Boolean arDI_SaftyOk { get; set; }

        public string arMotPosNamePX { get; set; }
        public string arMotPosNamePZ { get; set; }
        public string arMotPosNameLM { get; set; }
        public string arMotPosNameLZ { get; set; }
        public string arMotPosNameRM { get; set; }
        public string arMotPosNameRZ { get; set; }

        public Boolean arMotILockPKX { get; set; }
        public Boolean arMotILockPKZ { get; set; }
        public Boolean arMotILockPLM { get; set; }
        public Boolean arMotILockPLZ { get; set; }
        public Boolean arMotILockPRM { get; set; }
        public Boolean arMotILockPRZ { get; set; }

        public Boolean arMotILockPRL { get; set; }
        public Boolean arMotILockPRR { get; set; }
        public Boolean arMotILockVS0 { get; set; }
        public Boolean arMotILockVS1 { get; set; }
        public Boolean arMotILockVS2 { get; set; }
        public Boolean arMotILockCVL { get; set; }
        public Boolean arMotILockCVR { get; set; }

        public Boolean PrintLPICK { get; set; }
        public Boolean PrintRPICK { get; set; }

        public Boolean L_PICK_FW { get; set; }
        public Boolean L_PICK_BW { get; set; }
        public Boolean R_PICK_FW { get; set; }
        public Boolean R_PICK_BW { get; set; }

        public Boolean[] arMOT_LimUp = new bool[] { false, false, false, false, false, false, false };
        public Boolean[] arMOT_LimDn = new bool[] { false, false, false, false, false, false, false };
        public Boolean[] arMOT_Origin = new bool[] { false, false, false, false, false, false, false };
        public Boolean[] arMOT_Alm = new bool[] { false, false, false, false, false, false, false };
        public Boolean[] arMOT_HSet = new bool[] { false, false, false, false, false, false, false };
        public Boolean[] arMOT_SVOn = new bool[] { false, false, false, false, false, false, false };

        public Boolean arFlag_Minspace { get; set; }

        public byte arUnloaderSeq { get; set; }
        public Boolean arFlag_UnloaderBusy { get; set; }
        public Boolean arFlag_UnloaderErr { get; set; }
        public Boolean arConn_REM { get; set; }


        public Boolean arFG_RDY_YP_FPICKON { get; set; }
        public Boolean arFG_RDY_YP_FPICKOF { get; set; }
        public Boolean arFG_RDY_YP_RPICKON { get; set; }
        public Boolean arFG_RDY_YP_RPICKOF { get; set; }

        public Boolean arFG_CMD_YP_FPICKON { get; set; }
        //public Boolean arFG_CMD_YP_FPICKOF { get; set; }
        public Boolean arFG_CMD_YP_RPICKON { get; set; }
        //public Boolean arFG_CMD_YP_RPICKOF { get; set; }




        //비상정지 센서 상태
        public Boolean arDI_Emergency { get; set; }

        public Boolean arDIAir { get; set; }

        public Boolean arConn_MOT { get; set; }
        public Boolean arConn_DIO { get; set; }
        public Boolean arAIRDetect { get; set; }
        public Boolean arConn_BCD { get; set; }
        public Boolean arConn_PLC { get; set; }

        public int arLastDetectIndex { get; set; }


        public Boolean arDebugMode { get { return _ardebugmode; } set { this._ardebugmode = value; Invalidate(); } }

        public CPort[] arVar_Port { get; set; }
        public CPicker[] arVar_Picker { get; set; }

        public Boolean arConvRun { get; set; }


        public Boolean arIsRunning { get; set; }


        private List<CItem> zitem = new List<CItem>();
        public long[] zonetime = new long[11];

        public Font arFont_count { get; set; }
        public Font arFont_picker { get; set; }

        public double arMotorLengthY { get; set; }
        public double arMotorLengthZL { get; set; }
        public double arMotorLengthZR { get; set; }

        private double[] _armotpos = new double[] { 0, 0, 0, 0, 0, 0, 0 };
        public double[] arMotorPosition { get { return _armotpos; } set { _armotpos = value; } }
        private double[] _arhomepgoress = new double[] { 0, 0, 0, 0, 0, 0, 0 };
        public double[] arHomeProgress { get { return _arhomepgoress; } set { _arhomepgoress = value; } }

        private CMenu[] _menus = null;
        public CMenu[] arMenus { get { return _menus; } set { _menus = value; this.Invalidate(); } }

        #endregion

        public Boolean PickerSafezone = false;
        public HMI()
        {
            // Set Optimized Double Buffer to reduce flickering
            this.SetStyle(ControlStyles.UserPaint, true);
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            this.SetStyle(ControlStyles.ContainerControl, false);
            this.SetStyle(ControlStyles.Selectable, true);

            // Redraw when resized
            this.SetStyle(ControlStyles.ResizeRedraw, true);

            this.Resize += Loader_Resize;

            sfCenter = new StringFormat();
            sfCenter.Alignment = StringAlignment.Center;
            sfCenter.LineAlignment = StringAlignment.Center;


            tm = new Timer();
            tm.Interval = 50; //10frame;
            tm.Tick += Tm_Tick;

            arLastDetectIndex = -1;
            arFont_PortMessage = new Font("Consolas", 11, FontStyle.Bold);
            arFont_picker = new Font("Arial", 10, FontStyle.Bold);
            arFont_MotPosName = new Font("Consolas", 10, FontStyle.Bold);

            arUnloaderSeq = 0;
            arMotorLengthY = 400;
            arMotorLengthZL = 580;
            arMotorLengthZR = 590;

            arDI_Cv_Detect = new bool[8];
            for (int i = 0; i < arDI_Cv_Detect.Length; i++)
                arDI_Cv_Detect[i] = false;

            bool designMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);
            if (designMode == false) tm.Start();

            arFont_count = new Font("Consolas", 30, FontStyle.Bold);

            //기본수량설정됨
            arVar_Port = new CPort[3];
            arVar_Picker = new CPicker[1];

            for (int i = 0; i < rect_zone.Length; i++)
                rect_zone[i] = RectangleF.Empty;

            for (int i = 0; i < zonetime.Length; i++)
                zonetime[i] = 0;

            //미리 10개를 생성한다. 슬롯에 10개이상 생기기 않는다.            
            zitem = new List<CItem>(10);
            for (int i = 0; i < zitem.Count; i++)
                zitem[i] = new CItem();
        }


        public void ClearMessage()
        {

        }

        private List<string> lkitemsF = new List<string>();
        private List<string> lkitemsR = new List<string>();



        #region "Common Data & Device"

        DateTime UpdateTime = DateTime.Now.AddSeconds(-1);

        //public void SetFLAG(arUtil.IInterLock dio_)
        //{
        //    this.flag = dio_;
        //    this.flag.ValueChanged += Flag_ValueChanged;
        //}
        public void SetDIO(arDev.DIO.IDIO dio_)
        {
            this.dio = dio_;
            this.dio.IOValueChanged += Dio_IOValueChanged;
        }
        public void SetMOT(arDev.MOT.IMotion dio_)
        {
            this.mot = dio_;
            this.mot.HomeStatusChanged += Mot_HomeStatusChanged;
            this.mot.PositionChanged += Mot_PositionChanged;
            this.mot.StatusChanged += Mot_StatusChanged;
        }
        private void Dio_IOValueChanged(object sender, arDev.DIO.IOValueEventArgs e)
        {
            var ts = DateTime.Now - UpdateTime;
            if (ts.TotalMilliseconds < 500) return;
            else UpdateTime = DateTime.Now;
            this.Invalidate();
        }

        private void Mot_StatusChanged(object sender, arDev.MOT.StatusChangeEventArags e)
        {
            var ts = DateTime.Now - UpdateTime;
            if (ts.TotalMilliseconds < 500) return;
            else UpdateTime = DateTime.Now;
            this.Invalidate();
        }

        private void Mot_PositionChanged(object sender, arDev.MOT.PositionChangeEventArgs e)
        {
            var ts = DateTime.Now - UpdateTime;
            if (ts.TotalMilliseconds < 500) return;
            else UpdateTime = DateTime.Now;
            this.Invalidate();
        }

        private void Mot_HomeStatusChanged(object sender, arDev.MOT.HomeStatusChangeEventArgs e)
        {
            var ts = DateTime.Now - UpdateTime;
            if (ts.TotalMilliseconds < 500) return;
            else UpdateTime = DateTime.Now;
            this.Invalidate();
        }

        //private void Flag_ValueChanged(object sender, arUtil.InterfaceValueEventArgs e)
        //{
        //    var ts = DateTime.Now - UpdateTime;
        //    if (ts.TotalMilliseconds < 500) return;
        //    else UpdateTime = DateTime.Now;
        //    this.Invalidate();
        //}

        public Boolean MotionHome { get; set; }

        bool GetBOOL(eVarBool idx)
        {
            return VAR.BOOL?[(int)idx] ?? false;
        }
        string GetSTR(eVarString idx)
        {
            return VAR.STR?[(int)idx] ?? string.Empty;
        }

        bool GetDOValue(eDOName pin)
        {
            return dio?.GetDOValue((int)pin) ?? false;
        }
        bool GetDIValue(eDIName pin)
        {
            return dio?.GetDIValue((int)pin) ?? false;
        }

        #endregion

        public void ClearLockItem(int idx)
        {
            if (idx == 0)
            {
                lock (lkitemsF)
                    lkitemsF.Clear();
            }
            else
            {
                lock (lkitemsR)
                    lkitemsR.Clear();
            }
        }
        public void AddLockItem(int idx, params string[] values)
        {
            if (idx == 0)
            {
                lock (lkitemsF)
                {
                    foreach (var value in values)
                    {
                        if (lkitemsF.Contains(value) == false)
                            lkitemsF.Add(value);
                    }
                }
            }
            else
            {
                lock (lkitemsR)
                {
                    foreach (var value in values)
                    {
                        if (lkitemsR.Contains(value) == false)
                            lkitemsR.Add(value);
                    }
                }
            }
        }
        public void RemoveLockItem(int idx, params string[] values)
        {
            if (idx == 0)
            {
                lock (lkitemsF)
                {
                    foreach (var value in values)
                    {
                        if (lkitemsF.Contains(value) == true)
                            lkitemsF.Remove(value);
                    }
                }
            }
            else
            {
                lock (lkitemsR)
                {
                    foreach (var value in values)
                    {
                        if (lkitemsR.Contains(value) == true)
                            lkitemsR.Remove(value);
                    }
                }
            }

        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            //if (this.icons == null || icons.Length < 1) return;

            //var item = this.icons.Where(t => t.Rect.Contains(e.Location)).FirstOrDefault();

            ////선택된 것이 잇다면 모두 해제를 해준다.
            //icons.Where(t => t.Focus == true).ToList().ForEach(t => t.Focus = false);


            //if (item != null)
            //{
            //    item.Focus = true;
            //    this.Cursor = Cursors.Hand;
            //}
            //else
            //{
            //    this.Cursor = Cursors.Arrow;
            //}
        }

        public class ZoneItemClickEventargs : EventArgs
        {
            public CItem item { get; private set; }
            public ZoneItemClickEventargs(CItem item_)
            {
                this.item = item_;
            }
        }
        public class IconClickEventargs : EventArgs
        {
            public CIcon item { get; private set; }
            public IconClickEventargs(CIcon item_)
            {
                this.item = item_;
            }
        }
        public class MenuItemClickEventargs : EventArgs
        {
            public CMenuButton item { get; private set; }
            public MenuItemClickEventargs(CMenuButton item_)
            {
                this.item = item_;
            }
        }
        public event EventHandler<MenuItemClickEventargs> ButtonClick;
        public event EventHandler<IconClickEventargs> IConClick;
        public event EventHandler<ZoneItemClickEventargs> ZoneItemClick;
        protected override void OnMouseClick(MouseEventArgs e)
        {
            base.OnMouseClick(e);

            if (e.Button == MouseButtons.Left)
            {
                //var item = this.icons.Where(t => t.Rect.Contains(e.Location)).FirstOrDefault();
                //if (item != null)
                //{
                //    //다른 메뉴가 선택되어잇다면 동작하지 않게 한다.
                //    if (IConClick != null)
                //        IConClick(this, new IconClickEventargs(item));
                //}

                var zitem = this.zitem.Where(t => t.Rect.Contains(e.Location)).FirstOrDefault();
                if (zitem != null)
                {
                    //특정 존의 아이템을 선택했다
                    if (ZoneItemClick != null)
                        ZoneItemClick(this, new ZoneItemClickEventargs(zitem));

                }

                //메뉴의해 생성된 버튼
                var zbbut = this.menuButtons.Where(t => t.Rect.Contains(e.Location)).FirstOrDefault();
                if (zbbut != null)
                {
                    //특정 존의 아이템을 선택했다
                    if (ButtonClick != null)
                        ButtonClick(this, new MenuItemClickEventargs(zbbut));

                }

                //아이콘
                var zbut = this.Buttons.Where(t => t.Rect.Contains(e.Location)).FirstOrDefault();
                if (zbut != null)
                {
                    //특정 존의 아이템을 선택했다
                    if (ButtonClick != null)
                        ButtonClick(this, new MenuItemClickEventargs(zbut));
                }

            }
        }
        void Loader_Resize(object sender, EventArgs e)
        {
            bRemakeRect = true;
        }


        public void RemakeRect()
        {
            bRemakeRect = true;
        }

        /// <summary>
        /// 각 영역을 현재 크기대비하여 재계산 한다
        /// </summary>
        void makeRect_Normal()
        {

            rect_main = new RectangleF(
                DisplayRectangle.Left + Padding.Left,
                DisplayRectangle.Top + Padding.Top,
                DisplayRectangle.Width - Padding.Left - Padding.Right,
                DisplayRectangle.Height - Padding.Top - Padding.Bottom);

            //X축 모션(셔틀) 표시
            var xPos1 = rect_main.Left + (rect_main.Width * 0.175);
            var xPos2 = rect_main.Right - xPos1;
            var yposR = rect_main.Height * 0.15;
            var yposF = rect_main.Height * 0.85;
            var h0p5 = rect_main.Height * 0.03;
            var w0p5 = (rect_main.Width * 0.035) * ((rect_main.Height * 1.0) / rect_main.Width);

            //var conv_height = rect_main.Height * 0.3;

            var cx = (float)(rect_main.Top + (rect_main.Width / 2.0));
            var cy = (float)(rect_main.Top + (rect_main.Height / 2.0));


            var conv_height = CvtMMtoPX_H(350, 0); //컨베이어 높이
            var conv_width = CvtMMtoPX_W(arMcLengthW, 0); //컨베어이어너비는 장비 너비와 같다

            rect_conveyor = new RectangleF(rect_main.Left,
               (float)(rect_main.Top + (rect_main.Height - conv_height) / 2.0f),
               (float)conv_width,
               (float)conv_height);

            var h10p = rect_main.Height * 0.03;


            //프론트셔틀의 영역(가동 영역) - 아래서 450mm 떨어진곳
            var xAxisLengthMM = arMcLengthW - 200; // 컨베어 길이에서 좌우 100mm 씩 리밋센서가 있다
            var xAxisLengthPX = CvtMMtoPX_W(xAxisLengthMM, rect_conveyor.Left);
            //rect_frontShuttle = new RectangleF(
            //    (float)(CvtMMtoPX_W(100, rect_conveyor.Left)),
            //    (float)(CvtMMtoPX_H(100, rect_main.Top)),
            //    (float)xAxisLengthPX,
            //    (float)(CvtMMtoPX_H(20, 0)));


            //세로축 총길이 1400mm Y축 모터는 양끝에 100mm 의 여유가 있으며, Y축 

            var pickWidth = rect_main.Width * 0.6f;
            var pickerX = rect_main.Width / 2.0f;//  CvtMMtoPX_W(750, rect_conveyor.Left);

            var YAxisLenWMM = arMcLengthW - 100 * 2;
            var YAxisLenHMM = 100;//
            var yAxisLenWPx = CvtMMtoPX_W(YAxisLenWMM, 0);  //너비
            var yAxisLenHPx = CvtMMtoPX_H(YAxisLenHMM, 0);  //길이
            var yAxisX = CvtMMtoPX_W(100, rect_main.Left);
            var yAxisY = CvtMMtoPX_H(200, rect_main.Top);

            rect_picker = new RectangleF(
                   (float)(yAxisX),
                   (float)(yAxisY),
                   (float)(yAxisLenWPx),
                   (float)(yAxisLenHPx)
               );

            rect_printl = new RectangleF(rect_main.Left + 30, rect_picker.Bottom + 30, 30, rect_main.Height * 0.25f);
            rect_printr = new RectangleF(rect_main.Right - rect_printl.Width - rect_printl.Left, rect_printl.Top, rect_printl.Width, rect_printl.Height);


            //Y축 피커 관련 세부 영역 설정 (VAC 와 원)

            //전체영역의 80% 영역에 Y-로봇의 축을 그린다.
            //var motorMax = 400; //전체 가동 길이 400mm
            RectangleF rect = rect_picker;
            var MotPosPx = rect.Left + rect.Width * (this.arMotorPosition[0] / (this.arMotorLengthY * 1.0f));
            cx = rect.Left + rect.Width / 2.0f;

            //상(Rear), 하(Front)로 영역을 그린다
            var port_height = rect.Height * 0.25f;
            var port_width = port_height;
            //;// var port_width = rect.Width * 3f;
            //port_width = port_height;
            var port_space = CvtMMtoPX_H(350 / 2.0f, 0);
            var port_spacex = CvtMMtoPX_W(10, 0); ;

            var PickerSizeW = CvtMMtoPX_W(200, 0);// (float)(Math.Max(CvtMMtoPX_W(150, 0), CvtMMtoPX_H(15, 0)));
            var PickerSizeH = PickerSizeW;// CvtMMtoPX_H(130, 0);//(float)(Math.Max(CvtMMtoPX_W(150, 0), CvtMMtoPX_H(15, 0)));
            var PickerSpaceW = CvtMMtoPX_H(100, 0);


            rect_picker_left = new RectangleF(
             (float)(MotPosPx - PickerSpaceW),
            (float)(rect.Top + 50),
            (float)PickerSizeW,
            (float)PickerSizeH);


            var pointoffset = 5;


            //진공표시영역
            rect_picker_front_vac1 = new RectangleF(
           (float)rect_picker_left.Left + pointoffset,
           (float)rect_picker_left.Top + pointoffset,
           (float)rect_picker_left.Width * 0.2f,
           (float)rect_picker_left.Height * 0.2f);
            rect_picker_front_vac2 = new RectangleF(
               (float)rect_picker_left.Right - rect_picker_front_vac1.Width - pointoffset,
               (float)rect_picker_front_vac1.Top,
               (float)rect_picker_front_vac1.Width,
               (float)rect_picker_front_vac1.Height);
            rect_picker_front_vac3 = new RectangleF(
               (float)rect_picker_left.Left + pointoffset,
               (float)rect_picker_left.Bottom - rect_picker_front_vac1.Height - pointoffset,
               (float)rect_picker_front_vac1.Width,
               (float)rect_picker_front_vac1.Height);
            rect_picker_front_vac4 = new RectangleF(
               (float)rect_picker_left.Right - rect_picker_front_vac1.Width - pointoffset,
               (float)rect_picker_left.Bottom - rect_picker_front_vac1.Height - pointoffset,
               (float)rect_picker_front_vac1.Width,
               (float)rect_picker_front_vac1.Height);


            //각 존의 영역 확인

            //컨베어의 릴감지센서 위치를 표시한다
            var senseW = rect_conveyor.Width * 0.02f;
            var senseH = rect_conveyor.Height * 0.05f;
            var slist = new double[] { 20, 340, 550, 890, 1110, 1440 };// new double[] { 0.02, 0.25, 0.4, 0.6, 0.75, 0.9 };   //센서의 위치정보(컨베어좌측기준)



            //센서가 포함된 존의 영역을 생성한다
            for (int i = 0; i < slist.Length; i++)
            {
                //선으로 영역을 표시해준다.
                var PosMM = rect_conveyor.Width * (slist[i] / arMcLengthW);
                var x = (float)(rect_conveyor.Left + PosMM);
                var rx = x - senseW / 2.0f;
                rect_zone[i * 2] = new RectangleF(rx, rect_conveyor.Top, senseW, rect_conveyor.Height);
            }

            var arraylis = new int[] { 1, 3, 5, 7, 9 };
            var zterm = 4;
            for (int i = 0; i < arraylis.Length; i++)
            {
                var idx = arraylis[i];
                rect_zone[idx] = new RectangleF(
                    rect_zone[idx - 1].Right + zterm,
                    rect_zone[idx - 1].Top,
                    rect_zone[idx + 1].Left - rect_zone[idx - 1].Right - zterm * 2,
                    rect_zone[idx - 1].Height);
            }

            //입출력포트의 영역을 다시 계산한다
            var portW = (int)(rect_main.Width * 0.175f);
            var portH = (int)(rect_main.Height * 0.25f);
            var portPad = (int)(rect_main.Width / 7f);
            var MarginX = (int)((rect_main.Width - portW * 3 - portPad * 2) / 2.0);
            var MarginY = (int)(rect_main.Height - portH - (portPad / 2f));

            for (int i = 0; i < arVar_Port.Length; i++)
            {
                arVar_Port[i].Rect = new Rectangle(
                            (int)rect_main.Left + MarginX + (i * portW) + (i * portPad),
                            (int)rect_main.Top + MarginY,
                            portW, portH);
                zitem.Add(new CItem
                {
                    Rect = arVar_Port[i].Rect.toRect(),
                    index = i,
                    Tag = $"PORT{i}",
                });

            }

        }
        void makeRect_xmove()
        {
            rect_main = new RectangleF(
              DisplayRectangle.Left + DisplayRectangle.Width * 0.05f,
              DisplayRectangle.Top + DisplayRectangle.Height * 0.05f,
              DisplayRectangle.Width * 0.9f,
              DisplayRectangle.Height * 0.9f);

            //화면에 꽉차도록 전체 영역을 할당한다.
            var cx = rect_main.Left + rect_main.Width / 2.0f;
            var cy = rect_main.Top + rect_main.Height / 2.0f;

            var padding = (int)(rect_main.Width * 0.03);

            var width = (int)((cx - rect_main.Left) - padding * 2);
            var height = (int)((cy - rect_main.Top) - padding * 2);
            arVar_Port[0].Rect = new Rectangle(
                (int)rect_main.Left + padding,
                (int)cy + padding,
                width, height);

            arVar_Port[1].Rect = new Rectangle(
               (int)cx + padding,
               (int)cy + padding,
               width, height);


            arVar_Port[2].Rect = new Rectangle(
                (int)(rect_main.Left + (rect_main.Width - width) / 2f),
                (int)rect_main.Top + padding,
                width, height);

        }
        void makeRect_MotHome()
        {
            rect_main = new RectangleF(
              DisplayRectangle.Left + DisplayRectangle.Width * 0.05f,
              DisplayRectangle.Top + DisplayRectangle.Height * 0.05f,
              DisplayRectangle.Width * 0.9f,
              DisplayRectangle.Height * 0.9f);
        }

        double CvtMMtoPX_W(double PosMM, double startPos)
        {
            //컨베어 기준으로 값을 반환한ㄷ.
            return startPos + rect_main.Width * (PosMM / arMcLengthW);
        }
        double CvtMMtoPX_H(double PosMM, double startPos)
        {
            //컨베어 기준으로 값을 반환한ㄷ.
            return startPos + rect_main.Height * (PosMM / arMcLengthH);
        }

        #region "Menu Method"
        public void ClearMenu()
        {
            _menus = null;
            this.Invalidate();
        }
        public void AddMenu(CMenu menu)
        {
            var curCnt = 0;
            if (this._menus != null) curCnt = this._menus.Length;
            Array.Resize(ref _menus, curCnt + 1);
            _menus[curCnt] = menu;
            this.Invalidate();
        }

        public void DelMenu(CMenu menu)
        {
            List<CMenu> newlist = new List<CMenu>();
            for (int i = 0; i < _menus.Length; i++)
            {
                if (_menus[i] != menu) newlist.Add(_menus[i]);
            }
            this._menus = newlist.ToArray();
            this.Invalidate();
        }

        public void DelMenu(int idx)
        {
            List<CMenu> newlist = new List<CMenu>();
            for (int i = 0; i < _menus.Length; i++)
            {
                if (i != idx) newlist.Add(_menus[i]);
            }
            this._menus = newlist.ToArray();
            this.Invalidate();
        }
        public void DelMenu()
        {
            //제거할 아이템이 없다
            if (_menus == null || _menus.Length < 1) return;

            if (_menus.Length == 1) _menus = null;
            else
            {
                //마지막요소를 제거 해주낟
                Array.Resize(ref _menus, _menus.Length - 1);

            }

            this.Invalidate();
        }
        #endregion

        protected override void OnPaint(PaintEventArgs e)
        {
            e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
            e.Graphics.InterpolationMode = InterpolationMode.High;
            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;

            base.OnPaint(e);

            if (bRemakeRect)
            {
                this.zitem.Clear();
                if (Scean == eScean.Nomal) makeRect_Normal();
                else if (Scean == eScean.MotHome) makeRect_MotHome();
                else if (Scean == eScean.xmove) makeRect_xmove();
                bRemakeRect = false;
            }

            if (this.Scean == eScean.Nomal) Scean_Normal(e.Graphics);
            else if (this.Scean == eScean.MotHome) Scean_MotHome(e.Graphics);
            else if (this.Scean == eScean.xmove) Scean_XMove(e.Graphics);
        }

        /// <summary>
        /// Z축이 아이템을 내려놓은 시간(연속으로 놓는 증상이 발생하여, 일단 이것으로 2초이상 빠르게 놓는일이 없도록 한다)
        /// </summary>
        public DateTime LastDropTime = DateTime.Now;


        void RaiseMessage(string m, Boolean iserr, params object[] args)
        {
            if (args != null && args.Length > 0) m = string.Format(m, args);
            if (Message != null) Message(this, new MessageArgs(m, iserr));
        }

        /// <summary>
        /// 아이템을 DROP해도 되는가? 존 3번 부터 아이템이 존재하면 drop 불가능으로 한다
        /// </summary>

        void Scean_XMove(Graphics g)
        {
            //g.DrawRect(arVar_Port[0].Rect, Color.White, 3);
            Pen p = new Pen(Color.White, 5);

            var pts = new List<PointF>();
            pts.Add(new PointF(arVar_Port[0].Rect.Right, arVar_Port[0].Rect.Top));
            pts.Add(new PointF(arVar_Port[0].Rect.Left, arVar_Port[0].Rect.Bottom - arVar_Port[0].Rect.Height / 2f));
            pts.Add(new PointF(arVar_Port[0].Rect.Right, arVar_Port[0].Rect.Bottom));
            g.FillPolygon(Brushes.Blue, pts.ToArray());
            g.DrawPolygon(p, pts.ToArray());
            g.DrawString("[START]\nLEFT", this.Font, Brushes.Gold, arVar_Port[0].Rect, new StringFormat { Alignment = StringAlignment.Far, LineAlignment = StringAlignment.Center });

            pts.Clear();
            pts.Add(new PointF(arVar_Port[1].Rect.Left, arVar_Port[1].Rect.Top));
            pts.Add(new PointF(arVar_Port[1].Rect.Right, arVar_Port[1].Rect.Bottom - arVar_Port[1].Rect.Height / 2f));
            pts.Add(new PointF(arVar_Port[1].Rect.Left, arVar_Port[1].Rect.Bottom));
            g.FillPolygon(Brushes.Brown, pts.ToArray());
            g.DrawPolygon(p, pts.ToArray());
            g.DrawString("[STOP]\nRIGHT", this.Font, Brushes.Gold, arVar_Port[1].Rect, new StringFormat { Alignment = StringAlignment.Near, LineAlignment = StringAlignment.Center });

            if (arPickerSafeZone)
                g.FillEllipse(Brushes.Lime, arVar_Port[2].Rect);
            else
                g.FillEllipse(Brushes.Tomato, arVar_Port[2].Rect);
            g.DrawEllipse(new Pen(Color.White, 3), arVar_Port[2].Rect);
            g.DrawString("PICKER\nSAFTY\n" + (arPickerSafeZone ? "ON" : "OFF"), this.Font, Brushes.Black, arVar_Port[2].Rect, new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });


            //중앙에 메세지를 표시한다.
            var cpad = rect_main.Width * 0.1f;
            var cheigh = rect_main.Height * 0.20f;
            var crect = new RectangleF(rect_main.Left + cpad, rect_main.Top + (rect_main.Height - cheigh) / 2f, rect_main.Width - cpad * 2f, cheigh);
            g.FillRectangle(new SolidBrush(Color.FromArgb(20, 20, 20)), crect);

            if (arPickerSafeZone)
                g.DrawString("Home search is possible", new Font("Tahoma", 20, FontStyle.Bold), Brushes.Lime, crect, new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
            else
            {
                if (MessageOn)
                    g.DrawString("Move the picker to a safe position", new Font("Tahoma", 12, FontStyle.Bold), Brushes.Red, crect, new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
                else
                    g.DrawString("Move the picker to a safe position", new Font("Tahoma", 12, FontStyle.Bold), Brushes.White, crect, new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
            }

            g.DrawRect(crect, Color.White, 5);
            p.Dispose();
            var ts = DateTime.Now - ScreenUpdateTime;
            if (ts.TotalMilliseconds >= 200)
            {
                MessageOn = !MessageOn;
                ScreenUpdateTime = DateTime.Now;
            }

        }

        DateTime ScreenUpdateTime = DateTime.Now;
        Boolean MessageOn = false;


        void Scean_MotHome(Graphics g)
        {
            //g.DrawString("mot home", this.Font, Brushes.Black, 100, 100);
            g.DrawRectangle(new Pen(Color.SteelBlue, 10), this.rect_main.Left, rect_main.Top, rect_main.Width, rect_main.Height);
            Font f = new Font(this.Font.Name, 20f, FontStyle.Bold);

            var titleSize = g.MeasureString("HOME", f);

            var rectTitle = new RectangleF(
                rect_main.Left,
                rect_main.Top + 10,
                rect_main.Width,
                titleSize.Height * 1.2f);

            g.DrawString("MOTION HOME", f, Brushes.White, rectTitle, sfCenter); ;
            // g.DrawRectangle(Pens.Red, rectTitle.Left, rectTitle.Top, rectTitle.Width, rectTitle.Height);

            var rectBody = new RectangleF(
                rect_main.Left + 10,
                rectTitle.Bottom + 10,
                rect_main.Width - 20,
                rect_main.Height - rectTitle.Height - 10 - 20);

            //g.DrawRectangle(Pens.White, rectBody.Left, rectBody.Top, rectBody.Width, rectBody.Height);



            var rectT = new Rectangle(
                (int)(rectBody.Left + 20),
                (int)(rectBody.Top + 30),
                (int)(rectBody.Width * 0.3f),
                (int)(rectBody.Height * 0.07));

            var rectXF = new Rectangle(
              (int)(rectT.Right + 20),
              (int)(rectBody.Top + 30),
              (int)(rectBody.Width - rectT.Width - rectT.Left - 10),
              (int)(rectBody.Height * 0.07));

            //g.DrawRect(rectT, Color.White, 1);
            //g.DrawRect(rectXF, Color.Red, 1);


            var titles = new string[] { "[0] PICKER-Y", "[1] PICKER-Z", "[2] PRINTL-Y", "[3] PRINTL-Z", "[4] PRINTR-Y", "[5] PRINTR-Z", "[6] ANGLE" };
            for (int i = 0; i < titles.Length; i++)
            {
                var perc = arHomeProgress[i];
                var title = titles[i];
                var offsetY = (rectBody.Height * 0.12f);

                //0번은 처리하지 않음
                if (i > 0)
                {
                    rectXF.Offset(0, (int)offsetY);
                    rectT.Offset(0, (int)offsetY);
                }


                //g.DrawRectangle(Pens.Yellow, rectT.Left, rectT.Top, rectT.Width, rectT.Height);

                using (Font f2 = new Font(this.Font.Name, 10f, FontStyle.Bold))
                {
                    g.DrawString("* " + title, f2, Brushes.Lime, rectT, sfLeft);
                }

                LinearGradientBrush brProgr = new LinearGradientBrush(rectXF, Color.Gold, Color.Yellow, LinearGradientMode.Vertical);
                var rectXF_P = new Rectangle(rectXF.Left, rectXF.Top, (int)(rectXF.Width * (perc / 100.0)), rectXF.Height);
                g.FillRectangle(brProgr, rectXF_P);
                g.DrawRectangle(Pens.Gray, rectXF);
                brProgr.Dispose();
            }





            f.Dispose();

        }

        void Scean_Normal(Graphics g)
        {
            //전체 영역 테두리
            g.DrawRectangle(new Pen(Color.White, 2), rect_main.Left, rect_main.Top, rect_main.Width, rect_main.Height);

            //포트표시(셔틀위에 표시됨)
            Draw_Port(g);    //front
       

            //프린터영역그리기  201228
            var printareahei = 50;
            var printareaw = 100;
            var printbordersize = 5;
            var rectpl = new RectangleF(arVar_Port[0].Rect.Right + printbordersize, arVar_Port[0].Rect.Top - 85, printareaw, printareahei);
            var fColorPrn = arFGPrinter0END ? Color.Lime : (arFGPrinter0RDY ? Color.Gold : Color.Gray);
            g.DrawRect(rectpl, fColorPrn, printbordersize);
            var prnstrbase = "";// "Print Qty:" + arCountPrint0.ToString("000") + "\n";
            var prnstr = prnstrbase + (arFGPrinter0END ? "Print Complete" : (arFGPrinter0RDY ? "Printing" : "Print Ready"));
            prnstr += "\n" + arCountPrint0.ToString("0000");
            g.DrawString(prnstr, new Font("Tahoma", 10, FontStyle.Bold), new SolidBrush(fColorPrn), rectpl,
                new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });

            rectpl = new RectangleF(arVar_Port[2].Rect.Left - 90 - printbordersize, arVar_Port[2].Rect.Top - 85, printareaw, printareahei);
            fColorPrn = arFGPrinter1END ? Color.Lime : (arFGPrinter1RDY ? Color.Gold : Color.Gray);
            g.DrawRect(rectpl, fColorPrn, printbordersize);
            prnstrbase = "";// "Print Qty:" + arCountPrint1.ToString("000") + "\n";
            prnstr = prnstrbase + (arFGPrinter1END ? "Print Complete" : (arFGPrinter1RDY ? "Printing" : "Print Ready"));
            prnstr += "\n" + arCountPrint1.ToString("0000");
            g.DrawString(prnstr, new Font("Tahoma", 10, FontStyle.Bold), new SolidBrush(fColorPrn), rectpl,
                new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
          
            //모터 Y/Z축
            Draw_PickerY(g, rect_picker);

            //왼쪽 프린터
            Draw_PickerPrinter(g, rect_printl, 2, 3, false, arMotILockPLM, arMotILockPLZ, arPLItemON, PrintLPICK, L_PICK_FW, L_PICK_BW);

            //오른쪽 프린터
            Draw_PickerPrinter(g, rect_printr, 4, 5, true, arMotILockPRM, arMotILockPRZ, arPRItemON, PrintRPICK, R_PICK_FW, R_PICK_BW);

            //정보 표시 (나중에 제거해야함) 별도 인포박스형태를 취해야 함
            Draw_Error(g);

            //메뉴는 최상위에 표시한다
            Draw_Menu(g);

            if (arDebugMode)
            {

                var sb = new System.Text.StringBuilder();
                sb.AppendLine("Debug Message");
                sb.AppendLine(string.Format("Display {0}", rect_main));
                sb.AppendLine(string.Format("Mot Name : {0}/{1}/{2}/{3}/{4}/{5}", arMotPosNamePX, arMotPosNamePZ, arMotPosNameLM, arMotPosNameLZ, arMotPosNameRM, arMotPosNameRZ));

                updatetime = DateTime.Now;

                //작업 수량 및 전체수량을 표시함
                var sb2 = new System.Text.StringBuilder();
                if (arVar_Port != null && arVar_Port.Length > 0)
                {
                    sb.AppendLine(string.Format("DIO:{4},BCD:{5},PLC:{6}\n" +
              "YP_RDY {7},{8},{9},{10}\n" +
              "YP_CMD {7},{8},{9},{10}\n",
                      arVar_Port[0].reelCount,
                      arVar_Port[1].reelCount,
                      arVar_Port[2].reelCount,
                      arConn_DIO,
                      arConn_BCD,
                      arConn_PLC,
                      arFG_RDY_YP_FPICKON, arFG_RDY_YP_FPICKOF, arFG_RDY_YP_RPICKON, arFG_RDY_YP_RPICKOF,
                      arFG_CMD_YP_FPICKON, arFG_CMD_YP_RPICKON));

                }
            }
        }

        void Draw_Screw(Graphics g, Rectangle rect)
        {
            //모터표시(X축)
            g.FillRectangle(new SolidBrush(Color.FromArgb(50, 150, 150, 150)), rect);

            //해다 영역에 사선으로그림을 그린다.
            var termcount = 50;
            var lineterm = rect.Width / termcount;
            var skew = rect.Width * 0.01f;
            Pen p = new Pen(Color.FromArgb(50, 120, 120, 120), 2);
            for (int i = 0; i < termcount; i++)
            {
                var pt1 = new PointF(rect.Left + i * lineterm, rect.Top);
                var pt2 = new PointF(pt1.X + skew, rect.Bottom);
                g.DrawLine(p, pt1, pt2);
            }
            p.Dispose();
            g.DrawRectangle(new Pen(Color.FromArgb(50, Color.Gray)), rect.Left, rect.Top, rect.Width, rect.Height);
        }

        void Draw_BallScrewRail(Graphics g, RectangleF rect, int divCount, int alpha, Boolean downDirection, Boolean MLock, Boolean Org, Boolean LimDn, Boolean LimUp)
        {
            //모터표시(X축)
            if (Org) g.FillRectangle(new SolidBrush(Color.FromArgb(alpha, Color.SkyBlue)), rect);
            else if (LimUp) g.FillRectangle(new SolidBrush(Color.FromArgb(alpha, Color.Red)), rect);
            else if (LimDn) g.FillRectangle(new SolidBrush(Color.FromArgb(alpha, Color.Blue)), rect);
            else g.FillRectangle(new SolidBrush(Color.FromArgb(alpha, 150, 150, 150)), rect);

            //해다 영역에 사선으로그림을 그린다.
            var baseSize = (downDirection == false ? rect.Width : rect.Height);
            var lineterm = baseSize / divCount;
            var skew = baseSize * 0.01f;
            Pen p = new Pen(Color.FromArgb(alpha, 120, 120, 120), 2);
            PointF pt1 = PointF.Empty;
            PointF pt2 = PointF.Empty;
            for (int i = 0; i < divCount; i++)
            {
                if (downDirection)
                {
                    pt1 = new PointF(rect.Left, rect.Top + i * lineterm);
                    pt2 = new PointF(rect.Right, pt1.Y + skew);
                }
                else
                {
                    pt1 = new PointF(rect.Left + i * lineterm, rect.Top);
                    pt2 = new PointF(pt1.X + skew, rect.Bottom);
                }
                g.DrawLine(p, pt1, pt2);
            }
            p.Dispose();

            //limi이 걸려있다면 해당 영역에 적색으로 표시한다.
            var limwidth = 30;
            if (LimUp)
            {
                RectangleF rectlu;
                if (downDirection) rectlu = new RectangleF(rect.Left, rect.Top, rect.Width, limwidth);
                else rectlu = new RectangleF(rect.Right - limwidth, rect.Top, limwidth, rect.Height);

                g.FillRectangle(Brushes.Red, rectlu.Left, rectlu.Top, rectlu.Width, rectlu.Height);
            }

            if (LimDn)
            {
                RectangleF rectlu;
                if (downDirection) rectlu = new RectangleF(rect.Left, rect.Bottom - limwidth, rect.Width, limwidth);
                else rectlu = new RectangleF(rect.Left, rect.Top, limwidth, rect.Height);

                g.FillRectangle(Brushes.Red, rectlu.Left, rectlu.Top, rectlu.Width, rectlu.Height);
            }
            //전체 테두리
            g.DrawRectangle(new Pen(Color.FromArgb(alpha, Color.Gray)), rect.Left, rect.Top, rect.Width, rect.Height);
        }

        Boolean NeedHomeSet()
        {
            return arConn_MOT && (this.arMOT_HSet[0] == false || this.arMOT_HSet[1] == false || this.arMOT_HSet[2] == false || this.arMOT_HSet[3] == false || this.arMOT_HSet[4] == false);
        }

        byte errstep = 0;
        bool errstepR = true;
        void Draw_Error(Graphics g)
        {
            //디자인 모드에서는 표시하지 않는다  200714
            if (DesignMode == true) return;

            if (arConn_DIO && this.arDI_Emergency == true) ShowPopupMessage(g, "EMERGENCY BUTTON", "Check emergency stop\nEMERGENCY or POWER LOSS", Properties.Resources.error, true);
            else if (this.arDI_SaftyOk == false) ShowPopupMessage(g, "SAFTY SENSOR", "Check safety sensor", Properties.Resources.alert, true);
            else if (arConn_MOT && this.arMOT_Alm[0] == true) ShowPopupMessage(g, "SERVO ALARM", "Y-PICKER motor alarm occurred", Properties.Resources.error, true);
            else if (arConn_MOT && this.arMOT_Alm[1] == true) ShowPopupMessage(g, "SERVO ALARM", "Z-FRONT motor alarm occurred", Properties.Resources.error, true);
            else if (arConn_MOT && this.arMOT_Alm[2] == true) ShowPopupMessage(g, "SERVO ALARM", "Z-REAR motor alarm occurred", Properties.Resources.error, true);

            else if (arConn_MOT && this.arMOT_SVOn[0] == false) ShowPopupMessage(g, "SERVO ALARM", "Y-PICKER\nSERVO-OFF", Properties.Resources.alert, true);
            else if (arConn_MOT && this.arMOT_SVOn[1] == false) ShowPopupMessage(g, "SERVO ALARM", "Z-PICKER\nSERVO-OFF", Properties.Resources.alert, true);
            else if (arConn_MOT && this.arMOT_SVOn[2] == false) ShowPopupMessage(g, "SERVO ALARM", "L-PRINT-Y\nSERVO-OFF", Properties.Resources.alert, true);
            else if (arConn_MOT && this.arMOT_SVOn[3] == false) ShowPopupMessage(g, "SERVO ALARM", "L-PRINT-Z\nSERVO-OFF", Properties.Resources.alert, true);
            else if (arConn_MOT && this.arMOT_SVOn[4] == false) ShowPopupMessage(g, "SERVO ALARM", "R-PRINT-Y\nSERVO-OFF", Properties.Resources.alert, true);

            else if (arConn_DIO && this.arAIRDetect == false) ShowPopupMessage(g, "AIR DETECT", "*Press the blue AIR button on the front to supply AIR\n* Check the AIR line", Properties.Resources.error, true);

            else if (arConn_MOT && (this.arMOT_HSet[0] == false || this.arMOT_HSet[1] == false || this.arMOT_HSet[2] == false))
            {
                //안전오류도 표시해줘야한다
                var SaftyMessage = string.Empty;
                if (arVar_Port[0].SaftyErr == true) SaftyMessage += "DOOR:LEFT";
                if (arVar_Port[1].SaftyErr == true) SaftyMessage += (string.IsNullOrEmpty(SaftyMessage) == false ? "," : string.Empty) + "DOOR:CENTER";
                if (arVar_Port[2].SaftyErr == true) SaftyMessage += (string.IsNullOrEmpty(SaftyMessage) == false ? "," : string.Empty) + "DOOR:RIGHT";

                if (arPickerSafeZone == false) SaftyMessage += (string.IsNullOrEmpty(SaftyMessage) == false ? "\n" : string.Empty) + "Picker safety position: OFF";
                else SaftyMessage += "Picker safety position: ON"; ;

                ShowPopupMessage(g, "SYSTEM NOT READY", "Initialization required\n" + SaftyMessage, Properties.Resources.error, true);
            }
            else if (arConn_MOT && this.arMOT_HSet[0] == false) ShowPopupMessage(g, "SERVO ALARM", "Y-PICKER home search required", Properties.Resources.alert, true);
            else if (arConn_MOT && this.arMOT_HSet[1] == false) ShowPopupMessage(g, "SERVO ALARM", "Z-FRONT home search required", Properties.Resources.alert, true);
            else if (arConn_MOT && this.arMOT_HSet[2] == false) ShowPopupMessage(g, "SERVO ALARM", "Z-REAR home search required", Properties.Resources.alert, true);

            else if (arVar_Port[0].OverLoad) ShowPopupMessage(g, "## OVERLOAD ##", "FRONT-LEFT", Properties.Resources.alert, true);
            else if (arVar_Port[1].OverLoad) ShowPopupMessage(g, "## OVERLOAD ##", "FRONT-RIGHT", Properties.Resources.alert, true);
        }


        void Draw_Menu(Graphics g)
        {
            if (arMenus == null || arMenus.Length < 1) { this.HasPopupMenu = false; return; }
            else HasPopupMenu = true;

            ShowMaskLayer(g, Color.FromArgb(250, Color.Black));
            var item = this.arMenus.Last();//.Peek();
                                           //이 메뉴를 표시 합니다.

            PopupMenuRequireInput = item.RequireInput;

            var buttonSpace = 10;
            var hSpace = 5;
            var vSpace = 10;
            var iconSize = 80;
            var menuheight = 64;
            var padding = 10;
            var msgW = 900;// (int)(this.rect_main.Width * 0.65f);// 640;// (int)(rect_main.Width * 0.7f);
            var msgH = 400;
            var rect = new RectangleF(
                rect_main.Left + (rect_main.Width - msgW) / 2.0f,
                rect_main.Top + (rect_main.Height - msgH) / 2.0f,
                msgW, msgH);

            Rectangle rectT = Rectangle.Empty;  //title
            Rectangle rectI = Rectangle.Empty;  //icon
            Rectangle rectC = Rectangle.Empty;  //content
            Rectangle rectB = Rectangle.Empty;  //button

            rectT = new Rectangle((int)rect.Left + padding, (int)rect.Top + padding, (int)rect.Width - (padding * 2), (int)(rect.Height * 0.1));
            rectI = new Rectangle((int)rect.Left + padding + 10, (int)rectT.Bottom + vSpace, iconSize, iconSize); //icon size
            rectB = new Rectangle((int)(rect.Left + padding * 2), (int)(rect.Bottom - menuheight - padding), (int)rect.Width - (padding * 4), menuheight);
            rectC = new Rectangle((int)rectI.Right + 20 + hSpace * 2, (int)rectT.Bottom + 10 + vSpace,
                (int)(rect.Width - hSpace - (padding * 2) - rectI.Width),
                (int)(rect.Height - rectT.Height - rectB.Height - (padding * 2) - vSpace * 2));

            g.FillRectangle(new SolidBrush(Color.FromArgb(220, item.BackColor)), rect);

            //제목줄 표시
            using (LinearGradientBrush sb = new LinearGradientBrush(rectT,
                Color.FromArgb(160, 160, 160),
                Color.FromArgb(180, 180, 180),
                LinearGradientMode.Vertical))
            {
                g.FillRectangle(sb, rectT);
            }


            g.DrawString(item.Title, item.Font, new SolidBrush(item.ForeColor), rectT, sfCenter);

            //버튼표시
            if (item.buttons != null && item.buttons.Length > 0)
            {
                //현재 버튼 영역의 갯수가 다르면 다시 생성한다.
                if (menuButtons.Count != item.buttons.Length)
                {

                    menuButtons = new List<CMenuButton>();
                    foreach (var bt in item.buttons)
                        menuButtons.Add(bt);

                    g.DrawString("!!", this.Font, Brushes.Red, rectB.Left + 10, rectB.Top + 10);
                }
                else
                {
                    for (int i = 0; i < menuButtons.Count; i++)
                        menuButtons[i] = item.buttons[i];
                }

                g.DrawString(item.buttons.Length.ToString() + "/" + menuButtons.Count.ToString(), this.Font, Brushes.Red, rectB);
                var butidx = 0;
                var butwid = (rectB.Width - (item.buttons.Length - 1) * buttonSpace) / item.buttons.Length;
                foreach (var but in item.buttons)
                {
                    but.menutag = item.Tag;
                    but.Rect = new Rectangle(rectB.Left + butwid * butidx + buttonSpace * butidx, rectB.Top, butwid, rectB.Height);
                    g.FillRectangle(new SolidBrush(but.BackColor), but.Rect);
                    g.DrawRectangle(new Pen(but.BorderColor, but.BorderSize), but.Rect);
                    g.DrawString(but.Text, item.Font, new SolidBrush(but.ForeColor), but.Rect, sfCenter);
                    butidx++;
                }
            }
            else menuButtons.Clear();

            //아이콘 영역에 그림표시
            if (rectI.IsEmpty == false)
            {
                g.DrawImage(Properties.Resources.info, rectI);
            }

            //본문데이터표시
            if (string.IsNullOrEmpty(item.Text) == false)  //contec
            {
                g.DrawString(item.Text, item.Font, new SolidBrush(item.ForeColor), rectC);
            }

            g.DrawRectangle(new Pen(Color.FromArgb(180, 180, 180), 10) { Alignment = PenAlignment.Center }, rect.Left, rect.Top, rect.Width, rect.Height);
        }

        void ShowMaskLayer(Graphics g, Color maskColor)
        {
            g.FillRectangle(new SolidBrush(maskColor), this.DisplayRectangle.Left, DisplayRectangle.Top, DisplayRectangle.Width, DisplayRectangle.Height);

        }

        public Font MessageBody { get; set; } = new Font("Tahoma", 20, FontStyle.Bold);
        public Font MessageTitle { get; set; } = new Font("Tahoma", 10, FontStyle.Bold);

        void ShowPopupMessage(Graphics g, string title, string msg, Image icon, Boolean isError)
        {
            if (isError == false)
            {
                //팝업표시할때마다 배경 마스킹을 한다

                var maskColor = Color.FromArgb(50, Color.Gray);
                ShowMaskLayer(g, maskColor);

                var msgW = (int)(this.rect_main.Width * 0.65f);// 640;// (int)(rect_main.Width * 0.7f);
                var msgH = 105;
                var rect = new RectangleF(
                    rect_main.Left + (rect_main.Width - msgW) / 2.0f,
                    rect_main.Top + (rect_main.Height - msgH) / 2.0f,
                    msgW, msgH);

                var TitleHeight = 25;
                var rectT = new Rectangle((int)rect.Left, (int)rect.Bottom - TitleHeight, (int)rect.Width, TitleHeight);
                var rectI = new Rectangle((int)rect.Left, (int)rect.Top, (int)rect.Width, (int)rect.Height - rectT.Height);

                //g.FillRectangle(new SolidBrush(Color.FromArgb(220, Color.Black)), rect);
                g.FillRectangle(new SolidBrush(Color.FromArgb(120, Color.White)), rect);

                var rectTL = new RectangleF(rectT.Left, rectT.Top, rectT.Width / 2.0f, rectT.Height);
                var rectTR = new RectangleF(rectTL.Right, rectT.Top, rectTL.Width, rectTL.Height);
                using (var sb = new LinearGradientBrush(rectT, Color.Transparent, Color.White, LinearGradientMode.Horizontal))
                    g.FillRectangle(sb, rectTL);
                using (var sb = new LinearGradientBrush(rectT, Color.White, Color.Transparent, LinearGradientMode.Horizontal))
                    g.FillRectangle(sb, rectTR);

                //g.DrawImage(icon,
                //    (int)(rect.Left + 20),
                //    (int)(rect.Top + (rect.Height - icon.Height) / 2.0f));

                g.DrawString(title, MessageTitle, Color.Black, rectT, ContentAlignment.MiddleCenter);
                g.DrawString(msg, MessageBody, Color.White, rectI, ContentAlignment.MiddleCenter, Color.FromArgb(24, 24, 24));

                if (errstep % 5 == 0) errstepR = !errstepR;

                if (errstepR)
                    g.DrawRectangle(new Pen(Color.Gold, 2), rect.Left, rect.Top, rect.Width, rect.Height);
                else
                    g.DrawRectangle(new Pen(Color.White, 2), rect.Left, rect.Top, rect.Width, rect.Height);

                if (errstep < 255) errstep += 1;
                else errstep = 0;
            }
            else
            {
                //팝업표시할때마다 배경 마스킹을 한다
                var maskColor = Color.FromArgb(253, 15, 15, 15);
                ShowMaskLayer(g, maskColor);

                var msgW = (int)(this.rect_main.Width * 0.8f);// 640;// (int)(rect_main.Width * 0.7f);
                var msgH = (int)(this.rect_main.Height * 0.8f);//
                var rect = new RectangleF(
                    rect_main.Left + (rect_main.Width - msgW) / 2.0f,
                    rect_main.Top + (rect_main.Height - msgH) / 2.0f,
                    msgW, msgH);

                var rectT = new Rectangle((int)rect.Left, (int)rect.Bottom - 200, (int)rect.Width, 200);
                var rectI = new Rectangle((int)rect.Left, (int)rect.Top, (int)rect.Width, (int)rect.Height - rectT.Height);

                //g.FillRectangle(new SolidBrush(Color.FromArgb(220, Color.Black)), rect);
                g.FillRectangle(new SolidBrush(Color.FromArgb(253, Color.Black)), rect);

                g.DrawImage(icon,
                    (int)(rectI.Left + rectI.Width / 2.0f) - 40,
                    (int)(rectI.Top + rectI.Height / 2.0f) + 10);

                g.DrawString(msg, MessageBody, Brushes.Gold, rectT, sfCenter);

                if (errstep % 5 == 0) errstepR = !errstepR;

                if (errstepR)
                    g.DrawRectangle(new Pen(Color.Red, 10), rect.Left, rect.Top, rect.Width, rect.Height);
                else
                    g.DrawRectangle(new Pen(Color.Gold, 10), rect.Left, rect.Top, rect.Width, rect.Height);

                if (errstep < 255) errstep += 1;
                else errstep = 0;
            }
        }

        void Draw_Port(Graphics g)
        {
            var fSizeCnt = 20;
            var convmode = VAR.BOOL?[eVarBool.Use_Conveyor] ?? false;
            using (Font fCnt = new Font("consolas", fSizeCnt, FontStyle.Bold))
            {
                using (Font fMSg = new Font("Tahoma", 15, FontStyle.Bold))
                {
                    if (convmode)
                        this.arVar_Port[0].DisplayConv(g, fCnt, fMSg, arMagnet0, arFGVision0RDY, arFGVision0END, arPortLItemOn, arMotILockVS0, arCountV0, CVLeftBusy, CVLeftReady);
                    else
                        this.arVar_Port[0].Display(g, fCnt, fMSg, arMagnet0, arFGVision0RDY, arFGVision0END, arPortLItemOn, arMotILockVS0, arCountV0);

                    this.arVar_Port[1].Display(g, fCnt, fMSg, arMagnet1, arFGVision1RDY, arFGVision1END, false, arMotILockVS1, arCountV1);

                    if (convmode)
                        this.arVar_Port[2].DisplayConv(g, fCnt, fMSg, arMagnet2, arFGVision2RDY, arFGVision2END, arPortRItemOn, arMotILockVS2, arCountV2, CVRightBusy, CVRightReady);
                    else
                        this.arVar_Port[2].Display(g, fCnt, fMSg, arMagnet2, arFGVision2RDY, arFGVision2END, arPortRItemOn, arMotILockVS2, arCountV2);
                }
            }
        }

      
    

        private void Tm_Tick(object sender, EventArgs e)
        {

            if (ConveyorRunPoint < (AnimationStepConv - 3)) ConveyorRunPoint += 1;
            else ConveyorRunPoint = 1;

            for (int i = 0; i < 3; i++)
            {

                if (this.arVar_Port[i].arrowIndex < (arVar_Port[i].AnimationStepPort - 3)) this.arVar_Port[i].arrowIndex += 1;
                else this.arVar_Port[i].arrowIndex = 1;
            }
            this.Invalidate();
        }

    }
}
