using AR;
using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Management;
using System.Net;
using System.Net.NetworkInformation;
using System.Runtime.CompilerServices;
using System.Runtime.Remoting;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Project
{
    public static class PUB
    {
        public static string MCCode = "R0";
        public static Class.StatusMessage StatusMessage { get; set; } = new Class.StatusMessage();
        public static string[] WaitMessage = new string[] { "", "", "", "", "", "", "", "", "", "", "" };

        public static byte[] swPLCBuffer = new byte[16];

        //########################################################
        //                   DEVICE DEFINE
        //########################################################
        public static arDev.DIO.IDIO dio;    //Ajin 
        public static arDev.MOT.IMotion mot;    //Ajin
        public static arDev.RS232 remocon;
        public static arDev.RS232 BarcodeFix;
        public static AR.MemoryMap.Client plc;

        public static Device.SATOPrinterAPI PrinterL;
        public static Device.SATOPrinterAPI PrinterR;

        public static WatsonWebsocket.WatsonWsClient wsL;
        public static WatsonWebsocket.WatsonWsClient wsR;
        public static Device.KeyenceBarcode keyenceF = null;
        public static Device.KeyenceBarcode keyenceR = null;

        public static int uploadcount = 0;
        public static DateTime BuzzerTime;
        public static DateTime MGZRunTime;
        public static MessageWindow popup;

        //interlock check
        public static CInterLock[] iLock;
        public static CInterLock iLockPRL;   //printer -left
        public static CInterLock iLockPRR;   //printer -right
        public static CInterLock iLockVS0;   //visoin - 0
        public static CInterLock iLockVS1;   //vision - 1
        public static CInterLock iLockVS2;   //vision - 2
        public static CInterLock iLockCVL;
        public static CInterLock iLockCVR;

        public static System.Threading.ManualResetEvent LockModel = new System.Threading.ManualResetEvent(true);

        /// <summary>
        /// database manager
        /// </summary>
        public static Manager.DatabaseManagerCount dbmCount;     //Quantity records (by ID)
        public static Manager.DatabaseManagerSIDHistory dbmSidHistory;


        /// <summary>
        /// model manager
        /// </summary>
        public static Manager.ModelManager mdm;

        public static System_MotParameter system_mot;

        public static Log logVision;
        public static Log log;
        public static Log logILStop;
        public static Log logDbg;
        public static Log logFlag;
        public static Log logILock;
        public static Log logWS;
        public static Log logKeyence;
        public static Log logbarcode;

        public static DataSet1.UsersDataTable userList;
        public static DataSet1.MailRecipientDataTable mailList;
        public static DataSet1.MailFormatDataTable mailForm;

        public static DateTime LastInputTime = DateTime.Now;
        public static CResult Result;
        public static double FreeSpace = 0;

        //########################################################
        //                   DEVICE DEFINE
        //########################################################
        public static Device.CStateMachine sm;    //State machine separation 190529


        public static Boolean UserAdmin { get { return true; } }

        public static bool OPT_CAMERA()
        {
            var retval = VAR.BOOL[eVarBool.Opt_DisableCamera];
            if (retval == false)
            {
                //Overall option is available but doesn't work when individual option in environment settings is off
                retval = !AR.SETTING.Data.Enable_Unloader_QRValidation;
            }
            return retval;
        }
        public static bool OPT_BYPASS()
        {
            return SETTING.Data.SystemBypass;
        }
        public static bool OPT_PRINTEROFF(eWorkPort target)
        {
            var retval = VAR.BOOL[eVarBool.Opt_DisablePrinter];
            if (retval == false)
            {
                //Overall option is available but doesn't work when individual option in environment settings is off
                if (target == eWorkPort.Left)
                    retval = AR.SETTING.Data.Disable_PrinterL;
                else
                    retval = AR.SETTING.Data.Disable_PrinterR;
            }
            return retval;
        }





        public static void AddDebugLog(string div, string msg, Boolean iserr = false)
        {
            if (AR.SETTING.Data.Log_Debug == false) return;
            if (iserr) PUB.logDbg.AddE(msg);
            else PUB.logDbg.Add(div, msg);
        }

        /// <summary>
        /// SQL Database Connection String
        /// </summary>
        /// <returns></returns>
        public static string GetWMSConnectionString()
        {
            if (SETTING.Data.WMS_DB_PROD)
                return Properties.Settings.Default.WMS_PRD;
            else
                return Properties.Settings.Default.WMS_DEV;
        }
        public static bool SelectModelM(string modelName, bool bUploadConfig = true)
        {
            //if (this.InvokeRequired)
            //{
            //    this.Invoke(new SelectModelHandler(SelectModelM), new object[] { modelName, bUploadConfig });
            //    return;
            //}

            //Initialize
            var rlt = PUB.Result.mModel.ReadValue(modelName);
            if (rlt && PUB.Result.mModel.isSet)
            {
                PUB.log.AddAT("Motion model selection complete: " + PUB.Result.mModel.Title);

                //Save the model name used
                if (SETTING.User.LastModelM != PUB.Result.mModel.Title)
                {
                    SETTING.User.LastModelM = PUB.Result.mModel.Title;
                    SETTING.User.Save();
                }
                return true;
            }
            else
            {
                PUB.log.AddE("Motion model selection failed (non-existent model name:" + modelName + ")");
                return false;
            }
        }
        public static void AddDebugLog(string msg, Boolean iserr = false)
        {
            PUB.logDbg.Add("NORMAL", msg, iserr);
        }

        //public static bool PrintSend(bool left, string zpl)
        //{
        //    var dev = left ? PUB.PrinterL : PUB.PrinterR;
        //    var tag = left ? COMM.SETTING.Data.PrintL_AddSend : COMM.SETTING.Data.PrintR_AddSend;
        //    if (dev.IsOpen == false) return false;
        //    try
        //    {
        //        dev.Write(zpl);

        //        //추가
        //        if (tag.isEmpty() == false)
        //        {
        //            var addbytes = UTIL.ConvertHexStringToByte(tag);
        //            dev.Write(addbytes);
        //        }
        //        return true;
        //    }
        //    catch (Exception ex)
        //    {
        //        return false;
        //    }
        //}

        public static bool UpdateWMS(Class.VisionData Data)
        {
            PUB.log.AddE("updatewms wms 데이터베이스 기록 연결해야 함(아세테크)");
            return true;
        }
        public static bool SelectModelV(string modelName, bool bUploadConfig = true)
        {
            //Initialize
            PUB.Result.vModel.Title = string.Empty;
            PUB.PrinterL.ZPLFileName = UTIL.MakePath("Data", "zpl.txt");   //Set as default file
            PUB.PrinterR.ZPLFileName = UTIL.MakePath("Data", "zpl.txt");

            var modelVision = PUB.mdm.GetDataV(modelName);
            if (modelVision != null)
            {
                var mv = PUB.Result.vModel;
                mv.ReadValue(modelVision); //Util.CopyData(model, Pub.Result.vModel);                
                PUB.log.AddAT("Work model selection complete: " + mv.Title);

                //Save the selected model
                if (SETTING.User.LastModelV != mv.Title)
                {
                    SETTING.User.LastModelV = mv.Title;
                    SETTING.User.Save();
                }

                lock (PUB.Result.BCDPatternLock)
                {
                    PUB.Result.BCDPattern = PUB.GetPatterns(modelName, false);
                    PUB.Result.BCDIgnorePattern = PUB.GetPatterns(modelName, true);

                    PUB.log.Add($"Model pattern loading:{PUB.Result.BCDPattern.Count}/{PUB.Result.BCDIgnorePattern.Count}");
                }

                if (modelVision.Code.isEmpty())
                {
                    //PUB.Result.CustCode = string.Empty;
                    VAR.STR[eVarString.JOB_CUSTOMER_CODE] = string.Empty;
                }
                else
                {
                    var codlist = modelVision.Code.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);

                    string custcode = string.Empty;
                    if (codlist.Length == 1) custcode = codlist[0];
                    VAR.STR[eVarString.JOB_CUSTOMER_CODE] = custcode;
                }

                //Delete all saved barcodes
                PUB.Result.ItemDataC.Clear("SELCTMODEL");

                //Update barcode configuration file
                if (bUploadConfig)
                {
                    //SAVE
                    var k1 = MemLoadBarcodeConfig(PUB.keyenceF);
                    var k2 = MemLoadBarcodeConfig(PUB.keyenceR);
                }

                if (mv.bOwnZPL)
                {
                    var fn = UTIL.MakePath("Model", mv.idx.ToString(), "zpl.txt");
                    if (System.IO.File.Exists(fn))
                    {
                        PUB.PrinterL.ZPLFileName = fn;
                        PUB.PrinterR.ZPLFileName = fn;
                        PUB.log.AddI($"Dedicated ZPL settings {fn}");
                    }
                    else
                    {
                        PUB.log.AddE($"No dedicated ZPL file {fn}");
                    }
                }
                else
                {
                    PUB.log.AddI($"Using shared ZPL file ({PUB.PrinterL.ZPLFileName})");
                }
                return true;
            }
            else
            {
                //PUB.Result.CustCode = string.Empty;
                VAR.STR[eVarString.JOB_CUSTOMER_CODE] = string.Empty;
                PUB.log.AddE("Model selection failed (non-existent model name:" + modelName + ")");
                return false;
            }

        }

        public static bool MemLoadBarcodeConfig(Device.KeyenceBarcode keyence)
        {
            var BarcodeMemoryNo = PUB.Result.vModel.BSave;
            if (BarcodeMemoryNo < 1)
            {
                PUB.log.AddAT($"The currently selected model does not have a barcode memory number (BSAVE) specified.");
                return false;
            }

            if (keyence == null || keyence.IsConnect == false)
            {
                var tagstr = keyence?.Tag ?? string.Empty;

                PUB.log.AddAT($"Barcode ({tagstr}) is not connected, configuration file will not be uploaded." +
                    "This information will be retransmitted when starting a new job." +
                    $"This error will not occur if you select the model after checking the barcode connection at the {(tagstr == "F" ? "left" : "right")} bottom.");
                return false;
            }

            try
            {
                //접속되어잇ㅇ츠면 끈다
                var isTriggeronL = keyence.IsTriggerOn;
                var tagstr = keyence?.Tag ?? string.Empty;
                if (keyence.IsConnect)
                {
                    keyence.Trigger(false);
                    PUB.log.Add($"[{tagstr}] Send BLoad({BarcodeMemoryNo})");
                    keyence.BLoad(BarcodeMemoryNo);
                }

                if (isTriggeronL && keyence.IsConnect) keyence.Trigger(true);
                return true;
            }
            catch (Exception ex)
            {
                PUB.log.AddE($"Barcode({keyence.Tag}) FTP transfer failed:{ex.Message}");
            }

            return false;
        }
        public static bool UpLoadBarcodeConfig(Device.KeyenceBarcode keyence)
        {
            if (keyence == null || keyence.IsConnect == false)
            {
                var tagstr = keyence?.Tag ?? string.Empty;

                PUB.log.AddAT($"Barcode ({tagstr}) is not connected, configuration file will not be uploaded." +
                    "This information will be retransmitted when starting a new job." +
                    $"This error will not occur if you select the model after checking the barcode connection at the {(tagstr == "F" ? "left" : "right")} bottom.");
                return false;
            }

            //Input barcode configuration file
            var mv = PUB.Result.vModel;
            var configfilenameB = mv.Title;
            if (configfilenameB.isEmpty()) configfilenameB = mv.Title;
            if (configfilenameB.EndsWith(keyence.Tag) == false) configfilenameB += keyence.Tag;

            var configfilenameJ = configfilenameB;
            //var jobcode = VAR.STR[eVarString.JOB_TYPE];
            //if (jobcode.isEmpty() == false) configfilenameJ += $"_{jobcode}";
            //else PUB.log.AddAT($"작업형태값이 없어 모델 기본을  사용  합니다");


            if (configfilenameB.ToLower().EndsWith("ptc") == false) configfilenameB += ".ptc";
            if (configfilenameJ.ToLower().EndsWith("ptc") == false) configfilenameJ += ".ptc";

            var configpathB = System.IO.Path.Combine(UTIL.CurrentPath, "Model", configfilenameB);
            var configpathJ = System.IO.Path.Combine(UTIL.CurrentPath, "Model", configfilenameJ);
            var configfiB = new System.IO.FileInfo(configpathB);
            var configfiJ = new System.IO.FileInfo(configpathJ);

            if (configfiB.Exists == false && configfiJ.Exists == false)
            {
                PUB.log.AddAT($"Barcode({keyence.Tag}) configuration file({configfiB.Name}) not found");
            }
            else
            {
                try
                {
                    //접속되어잇ㅇ츠면 끈다
                    var ip = keyence.Tag == "F" ? SETTING.Data.Keyence_IPF : SETTING.Data.Keyence_IPR;
                    if (keyence.IsConnect) keyence.Trigger(false);
                    var ftp = new AR.FTPClient.FTPClient();
                    ftp.Host = ip;// COMM.SETTING.Data.Keyence_IPF;
                    ftp.Port = 21;
                    var UPFileName = @"\CONFIG\CONFIG.PTC";

                    var fn = configfiJ.Exists ? configfiJ.FullName : configfiB.FullName;
                    var upOk = ftp.Upload(UPFileName, fn);
                    if (upOk == false) PUB.log.AddE($"Barcode({keyence.Tag}) configuration file upload failed");
                    else PUB.log.AddI($"Barcode({keyence.Tag}) configuration file upload completed({fn})");
                    if (keyence.IsConnect) keyence.Trigger(true);
                    return true;
                }
                catch (Exception ex)
                {
                    PUB.log.AddE($"Barcode({keyence.Tag}) FTP transfer failed:{ex.Message}");
                }
            }
            return false;
        }

        public static Task<Tuple<bool, string, int>> UpdateSIDInfo()
        {
            var rlt = Task.Run<Tuple<bool, string, int>>(() =>
            {
                bool result = false;
                string message = string.Empty;
                int cnt = 0;
                int rdy = 0;
                System.Diagnostics.Stopwatch wat = new System.Diagnostics.Stopwatch();
                wat.Restart();

                //기존  SID정보에서  데이터를  취합니다.
                var mc = AR.SETTING.Data.McName;
                PUB.log.AddAT($"SID Information Data will be generated from existing information  MC={mc}");
                using (var tainfo = new DataSet1TableAdapters.K4EE_Component_Reel_SID_InformationTableAdapter())
                {
                    var cntd = tainfo.DeleteAll("IB");
                    PUB.log.AddAT($"{cntd} records deleted");
                    var cnti = tainfo.MakeIBData(mc);
                    PUB.log.AddAT($"{cnti} records duplicated");
                }
                message = "SID Information : Only M/C Data";
                result = true;
                rdy = 1;

                wat.Stop();
                PUB.log.Add($"SID Information Add ({cnt}) - {wat.ElapsedMilliseconds:N2}ms");
                return new Tuple<bool, string, int>(result, message, rdy);
            });
            return rlt;
        }


        /// <summary>
        /// 전체 작업목록을 별도파일에 저장한다
        /// </summary>
        /// <param name="seqdate"></param>
        /// <param name="seqno"></param>
        /// <param name="file"></param>
        public static void AddJobList(string seqdate, string seqno, string file)
        {

            //해당 차수로 저장된 파일이 잇는지 체크한다. 
            var savepath = System.IO.Path.Combine(AR.SETTING.Data.GetDataPath(), "JobData", seqdate.Substring(0, 6), seqdate + "-" + seqno + ".txt");
            var fi = new System.IO.FileInfo(savepath);
            if (fi.Directory.Exists == false) fi.Directory.Create(); //폴더가 없다면 생성

            //신규파일이므로, 해당 내용을 모두 옴겨놓는다(번호는 중요치않다)
            List<string> savedList = new List<string>();
            if (fi.Exists)
            {
                var oldlist = System.IO.File.ReadAllLines(fi.FullName, System.Text.Encoding.UTF8);
                savedList.AddRange(oldlist);
            }

            //기존목록을 불러와서 없는 데이터만 추가해준다.
            var newbuffer = System.IO.File.ReadAllLines(file, System.Text.Encoding.UTF8);
            foreach (var line in newbuffer)
            {
                if (line.isEmpty() || line.StartsWith("#")) continue;
                var buffer = line.Split('\t');
                var raw = buffer[3].Trim();
                if (savedList.Where(t => t == raw).Count() == 0)
                    savedList.Add(raw);
            }

            //전체목록을 저장한다
            System.IO.File.WriteAllLines(fi.FullName, savedList.ToArray(), System.Text.Encoding.UTF8);
        }

        public static bool GetSIDConverDB()
        {
            //230509
            try
            {
                //sid정보테이블을 다시 불러온다
                var taConv = new DataSet1TableAdapters.K4EE_Component_Reel_SID_ConvertTableAdapter();
                PUB.Result.DTSidConvert.Clear();
                taConv.Fill(PUB.Result.DTSidConvert);
                PUB.Result.DTSidConvert.AcceptChanges();
                PUB.Result.DTSidConvertEmptyList.Clear();
                PUB.Result.DTSidConvertMultiList.Clear();
                PUB.log.Add($"SID conversion table {PUB.Result.DTSidConvert.Rows.Count} records checked");
                return true;
            }
            catch (Exception ex)
            {
                PUB.log.AddE("SID conversion information check failed\n" + ex.Message);
                return false;
            }
        }

        //public static void MakeSelectState(ref List<string> wheres, List<(bool option, bool condition, string colname)> items)
        //{
        //    foreach (var item in items)
        //    {
        //        var opt = item.option;
        //        var condition = item.condition;
        //        var column = item.colname;
        //        if (opt)
        //        {
        //            if (condition) wheres.Add($"{column}");
        //        }
        //    }
        //}
        //public static bool MakeWhereState(ref List<string> wheres, List<(bool option,bool condition, string colname, string value)> items)
        //{
        //    foreach (var item in items)
        //    {
        //        var opt = item.option;
        //        var condition = item.condition;
        //        var value = item.value;
        //        var column = item.colname;
        //        if(opt)
        //        {
        //            if (condition) wheres.Add($"{column}='{value}'");
        //            return false;
        //        }
        //    }
        //    return true;
        //}

        public static bool GetSIDInfo_And_SetData(List<string> fields,
            ref Class.VisionData vdata,
            string SQL, string SQLC)
        {

            bool NewBarcodeUpdated = false;
            PUB.log.Add($"DATABAES : SID INFORMATIION QUERY");
            PUB.log.Add($"Data={SQL}");
            if (SQLC.isEmpty() == false) PUB.log.Add($"Count={SQLC}");
            var CS = Properties.Settings.Default.CS;
            var CN = new System.Data.SqlClient.SqlConnection(CS);
            var CMD = new System.Data.SqlClient.SqlCommand(SQLC, CN);
            SqlDataReader DAR = null;
            if (CN.State == System.Data.ConnectionState.Closed) CN.Open();

            var cnt = 1;

            //수량체크쿼리가 있다면 그것을 사용한다
            if (SQLC.isEmpty() == false)
                cnt = CMD.ExecuteScalar().ToString().toInt();

            //데이터가 1건만 존재할때 사용한다
            if (cnt == 1)
            {
                CMD.CommandText = SQL;
                DAR = CMD.ExecuteReader();
                while (DAR.Read())
                {
                    //loop select columns
                    for (int i = 0; i < fields.Count; i++)
                    {
                        var colName = fields[i];
                        var v = DAR[colName];
                        if (v != null)
                        {
                            var vStr = v.ToString().RemoveNoneASCII().Trim();
                            if (vStr.isEmpty()) continue;

                            if (PUB.UpdateSIDInfoData(ref vdata, colName, vStr)) NewBarcodeUpdated = true;
                        }
                    }
                }
            }


            if (DAR != null) DAR.Close();
            if (CMD != null) CMD.Dispose();
            if (CN != null)
            {
                if (CN.State == System.Data.ConnectionState.Open) CN.Close();
                CN.Dispose();
            }
            return NewBarcodeUpdated;
        }

        /// <summary>
        /// 지정된 VisionData에 해당 값을 기록 합니다
        /// ColName 이 하드코딩되어있으니 필드명이 변경되면 값을 변경해야 함
        /// </summary>
        /// <param name="vdata"></param>
        /// <param name="colName"></param>
        /// <param name="vStr"></param>
        /// <returns></returns>
        public static bool UpdateSIDInfoData(ref Class.VisionData vdata, string colNameOrg, string vStr)
        {
            var colName = colNameOrg.ToLower().Trim();
            if (colName == "custcode" || colName == "cust_code")
            {
                PUB.log.Add($"UpdateSIDInfoData [{colNameOrg}] {vdata.CUSTCODE}=>{vStr}");
                vdata.CUSTCODE = vStr;
                return true;
            }
            else if (colName == "partno" || colName == "part_no")
            {
                PUB.log.Add($"UpdateSIDInfoData [{colNameOrg}] {vdata.PARTNO}=>{vStr}");
                vdata.PARTNO = vStr;
                vdata.PARTNO_Trust = true;
                return true;
            }
            else if (colName == "printposition" || colName == "pos")
            {
                PUB.log.Add($"UpdateSIDInfoData [{colNameOrg}] {vdata.PrintPositionData}=>{vStr}");
                vdata.PrintPositionData = vStr;
                vdata.PrintPositionCheck = true;
                return true;
            }
            else if (colName == "vname" || colName == "vendername" || colName == "vendorname" || colName == "vendor_nm")
            {
                PUB.log.Add($"UpdateSIDInfoData [{colNameOrg}] {vdata.VNAME}=>{vStr}");
                vdata.VNAME = vStr;
                vdata.VNAME_Trust = true;
                return true;
            }
            else if (colName == "venderlot" || colName == "vendorlot" || colName == "vendor_lot")
            {
                PUB.log.Add($"UpdateSIDInfoData [{colNameOrg}] {vdata.VLOT}=>{vStr}");
                vdata.VLOT = vStr;
                vdata.VLOT_Trust = true;
                return true;
            }
            else if (colName == "sid")
            {
                PUB.log.Add($"UpdateSIDInfoData [{colNameOrg}] {vdata.SID}=>{vStr}");
                vdata.SID = vStr;
                vdata.SID_Trust = vdata.SID.Length == 9;
                if (vStr.Length != 9)
                {
                    PUB.log.AddE($"DB SID LEN ERROR:{vStr},LEN={vStr.Length}");
                }
                return true;
            }
            else if (colName == "batch" || colName == "batch_no")
            {
                PUB.log.Add($"UpdateSIDInfoData [{colNameOrg}] {vdata.BATCH}=>{vStr}");
                vdata.BATCH = vStr;
                return true;
            }
            else if (colName == "qtymax")
            {
                PUB.log.Add($"UpdateSIDInfoData [{colNameOrg}] {vdata.BATCH}=>{vStr}");
                vdata.QTYMAX = vStr;
                return true;
            }
            else if (colName == "attach")
            {
                PUB.log.Add($"UpdateSIDInfoData [{colNameOrg}] {vdata.Target}=>{vStr}");
                vdata.Target = vStr;
                return true;
            }

            return false;
        }



        public static string SIDCovert(string oldsid, string src, out bool err)
        {
            err = true;
            var retval = string.Empty;

            //원본sid가 있어야 한다
            if (oldsid.isEmpty())
            {
                return $"[{src}] 원본SID값이 없습니다";
            }

            try
            {
                if (PUB.Result.DTSidConvert.Any() == false)
                {
                    GetSIDConverDB();
                    if (PUB.Result.DTSidConvert.Any())
                    {
                        PUB.log.Add($"[{src}] SID conversion table query result: {PUB.Result.DTSidConvert.Rows.Count} records");
                        VAR.BOOL[eVarBool.JOB_Empty_SIDConvertInfo] = false;
                    }
                    else
                    {
                        PUB.log.AddAT($"No data in SID conversion table");
                        VAR.BOOL[eVarBool.JOB_Empty_SIDConvertInfo] = true;
                    }

                }
            }
            catch (Exception ex)
            {
                PUB.log.AddE(ex.Message);
            }


            if (PUB.sm.Step == eSMStep.RUN)
                PUB.log.Add($"[{src}] SID conversion work started, original:{oldsid}");

            var sidconvlist = PUB.Result.DTSidConvert.Where(t => t.SIDFrom.Equals(oldsid));
            if (sidconvlist.Any() == false)
            {
                PUB.Result.DTSidConvertEmptyList.Add(oldsid);
                return $"SID변환정보없음({oldsid}) 전체 DB {PUB.Result.DTSidConvert.Rows.Count}건";
            }
            else
            {
                if (sidconvlist.Count() != 1)
                {
                    //여러개가 있다면 그 데이터 목록을 반환한다.
                    PUB.Result.DTSidConvertMultiList.Add(oldsid);
                    var sb = new System.Text.StringBuilder();
                    var tolist = sidconvlist.Select(t => t.SIDTo).ToList();
                    return string.Join("|", tolist);
                    //foreach(var dr in sidconvlist)
                    //{
                    //    sb.AppendLine($"{dr.SIDFrom}|{dr.SIDTo}");
                    //}
                    //return ($"sid변환테이블정보복수 {sidconvlist.Count()}건 있음");
                }
                else
                {
                    //1건의 변경정보가 있다.
                    //sid값의 빈값 및 동일sid값은 db쿼리시에 진행했으니 이곳의 데이터는 꺠긋하다
                    var sidconvDr = sidconvlist.First();
                    err = false;
                    if (PUB.sm.Step == eSMStep.RUN)
                        PUB.log.AddI($"[{src}] SID conversion completed {oldsid}->{sidconvDr.SIDTo}");
                    return sidconvDr.SIDTo;
                }
            }
        }

        /// <summary>
        /// 바코드값을 비젼버퍼에 기록합니다.
        /// </summary>
        /// <param name="vdata"></param>
        /// <param name="TargetPos"></param>
        /// <param name="Value"></param>
        /// <param name="trust">바코드 룰에서 신뢰 하도록 됨(amkor std 라벨이 설정되어있음)</param>
        /// <returns></returns>
        public static bool SetBCDValue(Class.VisionData vdata, string TargetPos, string Value, bool trust)
        {
            bool retval = false;
            Value = Value.Replace("\r", "").Replace("\n", "").Trim();

            //220901 - 특문있으면 추가 제거
            var r1 = (char)0x1D;
            var r2 = (char)0x1E;
            var r3 = (char)0x04;
            Value = Value.Replace(r1.ToString(), "");
            Value = Value.Replace(r2.ToString(), "");
            Value = Value.Replace(r3.ToString(), "");
            Value = Value.Replace("\r", "");
            Value = Value.Replace("\n", "");
            Value = Value.RemoveNoneASCII().Trim();

            switch (TargetPos)
            {
                case "TARGET":

                    if (vdata.Target != Value) PUB.log.Add($"update target : {vdata.Target} > {Value}");
                    vdata.Target = Value;
                    retval = true;

                    break;
                case "MCN":

                    if (vdata.MCN != Value) PUB.log.Add($"update mcn : {vdata.MCN} > {Value}");
                    vdata.MCN = Value;
                    retval = true;

                    break;
                case "SID":
                    if (vdata.SID.isEmpty())
                    {
                        vdata.SID = Value;
                        vdata.SID_Trust = trust && vdata.SID.Length == 9 && vdata.SID.StartsWith("10");
                        retval = true;
                    }
                    else
                    {
                        //이전의 값이있지만 신뢰값이 아닌경우이다
                        if (vdata.SID_Trust == false)
                        {
                            if (trust)
                            {
                                vdata.SID = Value;
                                vdata.SID_Trust = (vdata.SID.Length == 9 && vdata.SID.StartsWith("10"));
                                retval = true;
                            }
                        }
                    }
                    break;
                case "RID":
                    if (vdata.RID.isEmpty())
                    {
                        vdata.SetRID(Value, "PASER");
                        vdata.RID_Trust = trust;
                        retval = true;
                    }
                    else
                    {
                        //if value is not empty , check trust level and Apply data
                        if (vdata.RID_Trust == false)
                        {
                            if (trust)
                            {
                                vdata.SetRID(Value, "PASER");
                                vdata.RID_Trust = trust;
                                retval = true;
                            }
                        }
                        else
                        {
                            //check newreelid _ old data
                            if (vdata.RIDNew)
                            {
                                if (vdata.RID0.isEmpty())
                                {
                                    PUB.log.Add($"RID(Org) Set =>{Value}");
                                    vdata.RID0 = Value;
                                }

                            }
                        }
                    }
                    break;

                case "LOT":
                case "VLOT":
                    if (vdata.VLOT.isEmpty())
                    {
                        vdata.VLOT = Value;
                        vdata.VLOT_Trust = trust;
                        retval = true;
                    }
                    else
                    {
                        //if value is not empty , check trust level and Apply data
                        if (vdata.VLOT_Trust == false)
                        {
                            if (trust)
                            {
                                vdata.VLOT = Value;
                                vdata.VLOT_Trust = true;
                                retval = true;
                            }
                        }
                    }
                    break;
                case "VNAME":
                    if (vdata.VNAME.isEmpty())
                    {
                        vdata.VNAME = Value;
                        vdata.VNAME_Trust = trust;
                        retval = true;
                    }
                    else
                    {
                        //if value is not empty , check trust level and Apply data
                        if (vdata.VNAME_Trust == false)
                        {
                            if (trust)
                            {
                                vdata.VNAME = Value;
                                vdata.VNAME_Trust = true;
                                retval = true;
                            }
                        }
                    }
                    break;
                case "PARTNO":
                case "PART":
                    if (vdata.PARTNO.isEmpty())
                    {
                        vdata.PARTNO = Value;
                        vdata.PARTNO_Trust = trust;
                        retval = true;
                    }
                    else
                    {
                        //if value is not empty , check trust level and Apply data
                        if (vdata.PARTNO_Trust == false)
                        {
                            if (trust)
                            {
                                vdata.PARTNO = Value;
                                vdata.PARTNO_Trust = true;
                                retval = true;
                            }
                        }
                    }
                    break;
                case "MFG":
                    if (vdata.MFGDATE.isEmpty())
                    {
                        vdata.MFGDATE = Value;
                        vdata.MFGDATE_Trust = trust;
                        retval = true;
                    }
                    else
                    {
                        //if value is not empty , check trust level and Apply data
                        if (vdata.MFGDATE_Trust == false)
                        {
                            if (trust)
                            {
                                vdata.MFGDATE = Value;
                                vdata.MFGDATE_Trust = true;
                                retval = true;
                            }
                        }
                    }
                    break;
                case "QTY":
                    if (vdata.QTY.isEmpty())
                    {
                        vdata.QTY = Value;
                        vdata.QTY_Trust = trust;
                        retval = true;
                    }
                    else
                    {
                        //if value is not empty , check trust level and Apply data
                        if (vdata.QTY_Trust == false)
                        {
                            if (trust)
                            {
                                vdata.QTY = Value;
                                vdata.QTY_Trust = true;
                                retval = true;
                            }
                        }
                        else
                        {
                            //신규발행에의해 신뢰된 자료라면 원본릴아이디에 이 값을 쓴다
                            if (vdata.QTY0.Equals("NONE") || vdata.QTY0.isEmpty())
                            {
                                PUB.log.AddAT($"Reel quantity(original) value applied(new value applied state):{Value}");
                                vdata.QTY0 = Value.Trim();
                            }
                        }
                    }
                    break;
                case "QTYRQ":
                    if (vdata.QTY.isEmpty())
                    {
                        vdata.QTY = Value;
                        vdata.QTYRQ = true;
                        vdata.QTY_Trust = trust;
                        retval = true;
                    }
                    else
                    {
                        if (trust)  //if value is trust,
                        {
                            vdata.QTY = Value;
                            vdata.QTYRQ = true;
                            vdata.QTY_Trust = true;
                            retval = true;
                        }
                    }
                    break;
                default:
                    PUB.log.AddAT($"Unknown RegEx Target Name : {TargetPos}");
                    break;
            }
            return retval;
        }




        public static List<Class.RegexPattern> GetPatterns(string custname, bool ignore)
        {
            var patterns = new List<Class.RegexPattern>();
            if (custname.isEmpty()) custname = "%";

            //데이터베이스에서 해당 데이터를 가져온다
            if (AR.SETTING.Data.OnlineMode)
            {
                try
                {
                    using (var ta = new DataSet1TableAdapters.K4EE_Component_Reel_RegExRuleTableAdapter())
                    {
                        ta.ClearBeforeFill = true;
                        if (ignore) ta.FillIgnore(PUB.mdm.dataSet.K4EE_Component_Reel_RegExRule, custname);
                        else ta.Fill(PUB.mdm.dataSet.K4EE_Component_Reel_RegExRule, custname);
                        PUB.mdm.dataSet.K4EE_Component_Reel_RegExRule.AcceptChanges();
                    }
                }
                catch (Exception ex)
                {
                    PUB.log.Add(ex.Message);
                }
            }

            //data
            foreach (DataSet1.K4EE_Component_Reel_RegExRuleRow dr in PUB.mdm.dataSet.K4EE_Component_Reel_RegExRule)
            {
                if (ignore)
                {
                    if (dr.Pattern.isEmpty()) continue;
                }
                else
                {
                    if (dr.Groups.isEmpty() || dr.Pattern.isEmpty()) continue;
                }

                var groupsbuf = dr.Groups.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                var Groups = new List<Class.RegexGroupMatch>();
                foreach (var item in groupsbuf)
                {
                    var itembuf = item.Split('=');
                    if (itembuf.Length > 1)
                    {
                        int grpno = 0;
                        string targetpos = "";

                        if (int.TryParse(itembuf[1].Trim(), out grpno) == false)
                        {
                            if (int.TryParse(itembuf[0].Trim(), out grpno) == false)
                            {
                                PUB.log.AddE($"RegEX Grp Data Error = {item}");
                            }
                            else targetpos = itembuf[1].Trim();
                        }
                        else targetpos = itembuf[0].Trim();

                        Groups.Add(new Class.RegexGroupMatch
                        {
                            GroupNo = grpno,//int.Parse(itembuf[1].Trim()),
                            TargetPos = targetpos,//itembuf[0].Trim(),
                        });
                    }
                    else PUB.log.AddE($"RegEX Grp Data Error = {item}");
                }

                //add pattern data
                patterns.Add(new Class.RegexPattern
                {
                    Seq = dr.Seq,
                    Customer = dr.CustCode,
                    Description = dr.Description,
                    Symbol = dr.Symbol,
                    Pattern = dr.Pattern,
                    IsTrust = dr.IsTrust,
                    IsAmkStd = dr.IsAmkStd,
                    IsEnable = dr.IsEnable,
                    Groups = Groups.ToArray(),
                });
            }
            return patterns;
        }

        public static int RemoveCache(string basefile)
        {
            var fi = new System.IO.FileInfo(basefile);
            //해당폴더에서 해당 차수의 파일 및 다른 확장자 모두를 삭제한다.
            var fisearch = fi.Name.Replace(fi.Extension, ".*");
            var delFiles = fi.Directory.GetFiles(fisearch, System.IO.SearchOption.TopDirectoryOnly);
            if (delFiles.Count() < 1) return 0;
            else
            {
                //파일을 삭제한다.
                var cnt = 0;
                try
                {
                    foreach (var delFile in delFiles)
                    {
                        PUB.log.Add("Archive file deleted: " + delFile.FullName);
                        delFile.Delete();
                        cnt += 1;
                    }
                }
                catch (Exception ex)
                {
                    PUB.log.AddE(ex.Message);
                }
                return cnt;
            }
        }
        //public static class flag
        //{
        //    public static void set(eFlag idx, bool value, string remark)
        //    {
        //        VAR.BOOL[(int)idx]
        //    }
        //}

        public static class flag
        {
            public static bool get(eVarBool flag)
            {
                return VAR.BOOL[(int)flag];
            }
            public static void set(eVarBool flag, bool value, string remark)
            {
                VAR.BOOL.Set((int)flag, value, remark);
            }
        }

        public static void initCore()
        {
            system_mot = new System_MotParameter(UTIL.MakePath("Data", "System_mot.xml"));
            system_mot.Load();

            //setting
            SETTING.Load();
            VAR.Init(LenI32: 128, LenBool: 192);

            //log
            log = new Log();
            logDbg = new Log(); logDbg.FileNameFormat = "{yyyyMMdd}_DEBUG";
            logFlag = new Log(); logFlag.FileNameFormat = "{yyyyMMdd}_FG";
            logILock = new Log(); logILock.FileNameFormat = "{yyyyMMdd}_IL";
            logbarcode = new Log(); logbarcode.FileNameFormat = "{yyyyMMdd}_BC";
            logWS = new Log(); logWS.FileNameFormat = "{yyyyMMdd}_WS";
            logKeyence = new Log(); logKeyence.FileNameFormat = "{yyyyMMdd}_KEYENCE";
            logILStop = new Log(); logILStop.FileNameFormat = "{yyyyMMdd}_ILOCK";
            logVision = new Log(); logVision.FileNameFormat = "{yyyyMMdd}_VISION";

            //popupmessage
            popup = new MessageWindow();
            popup.WindowClose += popup_WindowClose;
            popup.WindowOpen += popup_WindowOpen;

            //zpl파일 만든다.
            var fn = Path.Combine(UTIL.CurrentPath, "Data", "zpl.txt");
            // i// File.WriteAllText(fn, Properties.Settings.Default.ZPL7, Encoding.Default);
        }

        static void popup_WindowOpen(object sender, EventArgs e)
        {
            var msgdata = sender as MessageWindow.CMessageData;
            Console.WriteLine("window open : " + msgdata.Tag);
        }

        static void popup_WindowClose(object sender, EventArgs e)
        {
            var msgdata = sender as MessageWindow.CMessageData;
            Console.WriteLine("window close : " + msgdata.Tag);
        }
        public static void LogFlush()
        {
            PUB.log.Flush();
            PUB.logbarcode.Flush();
            PUB.logDbg.Flush();
            PUB.logFlag.Flush();
            PUB.logILock.Flush();
            PUB.logKeyence.Flush();
            PUB.logILStop.Flush();
            PUB.logVision.Flush();
        }

        public static void init()
        {
            Result = new CResult();

            //state machine
            sm = new Device.CStateMachine();

            //database
            mdm = new Manager.ModelManager(
                UTIL.CurrentPath + "Model\\modelv.csv",
                UTIL.CurrentPath + "Model\\modelc.csv",
                UTIL.CurrentPath + "Model\\modele.xml",
                UTIL.CurrentPath + "Model\\modeli.xml",
                UTIL.CurrentPath + "Model\\modelo.xml");

            mdm.Load();

            //핀정보설정
            DIO.Pin = new PinList();
            DIO.Pin.SetOutputData(PUB.mdm.dataSet.OutputDescription);
            DIO.Pin.SetInputData(PUB.mdm.dataSet.InputDescription);


            //dbSQL = new Manager.DataBaseMSSQL();
            //dbmHistory = new Manager.DatabaseManagerHistory();
            dbmSidHistory = new Manager.DatabaseManagerSIDHistory();

            dbmCount = new Manager.DatabaseManagerCount();
            dbmCount.dataPath = AR.SETTING.Data.GetDataPath();   //200113

            dio = new arDev.AjinEXTEK.DIO(arDev.AjinEXTEK.ELibraryType.AXT);
            mot = new arDev.AjinEXTEK.MOT(arDev.AjinEXTEK.ELibraryType.AXT);

            // flag = new Flag();

            //모터축에대한 인터락우선추가
            var axislist = Enum.GetNames(typeof(eAxis));
            iLock = new CInterLock[axislist.Length];
            int i = 0;
            for (i = 0; i < axislist.Length; i++)
            {
                var axisname = axislist[i];
                iLock[i] = new CInterLock(64, axisname);
                iLock[i].idx = i;
            }

            //프린터관련 인터락추가
            iLockPRL = new CInterLock(64, "PRL");
            iLockPRR = new CInterLock(64, "PRR");
            iLockVS0 = new CInterLock(64, "VS0");
            iLockVS1 = new CInterLock(64, "VS1");
            iLockVS2 = new CInterLock(64, "VS2");
            iLockCVL = new CInterLock(64, "CVL");
            iLockCVR = new CInterLock(64, "CVR");

            Array.Resize<CInterLock>(ref iLock, axislist.Length + 7);
            iLock[i++] = iLockPRL;
            iLock[i++] = iLockPRR;
            iLock[i++] = iLockVS0;
            iLock[i++] = iLockVS1;
            iLock[i++] = iLockVS2;
            iLock[i++] = iLockCVL;
            iLock[i++] = iLockCVR;

            //default를 해제하면 sps에서 할당제한을 한다
            //sps도 같이 체크해야함
            for (i = 7; i < iLock.Length; i++)
            {
                //iLock[i].DefaultLock = false;
                iLock[i].idx = i;
            }

            //language - disabled (now using hardcoded English)
            // Lang.Loading(AR.SETTING.Data.Language + ".ini");

            LoadDataTable();

            //allow list
            userList = new DataSet1.UsersDataTable();
            string fn = UTIL.MakePath("Data", "users.xml");
            if (System.IO.File.Exists(fn)) userList.ReadXml(fn);
            else userList.WriteXml(fn, true);


            BuzzerTime = DateTime.Parse("1982-11-23");
            MGZRunTime = DateTime.Parse("1982-11-23");
            LoadSIDList(); //사용자sid목록 가져옴
        }

        public static string IP { get; set; }
        public static string MAC { get; set; }
        public static string HOSTNAME { get; set; }

        public static void GetIPMac()
        {
            string ip = "";
            string mac = "";
            try
            {
                var nif = NetworkInterface.GetAllNetworkInterfaces();
                var host = Dns.GetHostEntry(Dns.GetHostName());
                HOSTNAME = System.Net.Dns.GetHostEntry("").HostName;
                foreach (IPAddress r in host.AddressList)
                {
                    string str = r.ToString();

                    if (str != "" && str.Substring(0, 3) == "10.")
                    {
                        ip = str;
                        break;
                    }
                }

                string rtn = string.Empty;
                ObjectQuery oq = new System.Management.ObjectQuery("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled='TRUE'");
                ManagementObjectSearcher query1 = new ManagementObjectSearcher(oq);
                foreach (ManagementObject mo in query1.Get())
                {
                    string[] address = (string[])mo["IPAddress"];
                    if (address[0] == ip && mo["MACAddress"] != null)
                    {
                        mac = mo["MACAddress"].ToString();
                        break;
                    }
                }

            }
            catch (Exception ex)
            {
                ip = "";
                mac = "";
            }

            IP = ip;
            MAC = mac;



        }

        /// <summary>
        /// 프로그램 사용기록 추가
        /// </summary>
        /// <param name="prgmName"></param>
        /// <param name="develop"></param>
        /// <param name="prgmVersion"></param>
        public static void CheckNRegister3(string prgmName, string develop, string prgmVersion)
        {
            if (prgmName.Length > 50) prgmName = prgmName.Substring(0, 50); //길이제한
            var task = Task.Factory.StartNew(() =>
            {
                GetIPMac();
                try
                {

                    if (IP == "" || MAC == "")
                    {
                        return;
                    }


                    SqlConnection conn = new SqlConnection("Data Source=K4FASQL.kr.ds.amkor.com,50150;Initial Catalog=EE;Persist Security Info=True;User ID=eeadm;Password=uJnU8a8q&DJ+ug-D");
                    conn.Open();
                    string ProcName = "AddPrgmUser3";
                    SqlCommand cmd = new SqlCommand(ProcName, conn)
                    {
                        CommandType = CommandType.StoredProcedure
                    };

                    SqlParameter param = cmd.Parameters.Add("@mac", SqlDbType.NVarChar, 50);
                    param.Value = MAC;

                    param = cmd.Parameters.Add("@ip", SqlDbType.NVarChar, 50);
                    param.Value = IP;

                    param = cmd.Parameters.Add("@pgrm", SqlDbType.NVarChar, 50);
                    param.Value = prgmName;

                    param = cmd.Parameters.Add("@develop", SqlDbType.NVarChar, 50);
                    param.Value = develop;

                    param = cmd.Parameters.Add("@pgver", SqlDbType.NVarChar, 50);
                    param.Value = prgmVersion;

                    param = cmd.Parameters.Add("@prgmLogin", SqlDbType.VarChar, 20);
                    param.Value = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");

                    param = cmd.Parameters.Add("@account", SqlDbType.NVarChar, 50);
                    param.Value = System.Environment.UserName;

                    param = cmd.Parameters.Add("@hostname", SqlDbType.NVarChar, 100);
                    param.Value = HOSTNAME;

                    cmd.ExecuteNonQuery();
                    conn.Close();


                }
                catch (Exception ex)
                {
                    PUB.log.AddE(ex.Message);
                }

            });
        }

        /// <summary>
        /// 디버깅정보르를 포함한 시스템 로그를 넣습니다.
        /// </summary>
        /// <param name="prgmVersion"></param>
        /// <param name="Screen"></param>
        /// <param name="Message"></param>
        /// <param name="TraceInfo"></param>
        public static void AddSystemLog(string prgmVersion, string Screen, string Message,
            [CallerFilePath] string filenpath = null,
            [CallerLineNumber] int linenumer = -1,
            [CallerMemberName] string callMember = null)
        {

            var stackFrame = new System.Diagnostics.StackTrace(1).GetFrame(1);
            string fileName = stackFrame.GetFileName();
            if (fileName.isEmpty()) fileName = filenpath;

            string methodName = stackFrame.GetMethod().ToString();
            if (methodName.isEmpty()) methodName = callMember;

            int lineNumber = stackFrame.GetFileLineNumber();
            if (linenumer != -1) lineNumber = linenumer;

            var maxlen = 100;
            if (Screen.Length > maxlen) Screen = Screen.Substring(0, maxlen - 1); //길이제한
            maxlen = 255;
            if (Message.Length > maxlen) Message = Message.Substring(0, maxlen - 1); //길이제한
            maxlen = 3000;

            var TraceInfo = stackFrame.ToString();
            if (TraceInfo.Length > maxlen) TraceInfo = TraceInfo.Substring(0, maxlen - 1); //길이제한


            var task = Task.Factory.StartNew(() =>
            {
                try
                {
                    string HostName = System.Net.Dns.GetHostEntry("").HostName;

                    SqlConnection conn = new SqlConnection("Data Source=10.131.15.18;Initial Catalog=EE;Persist Security Info=True;User ID=eeuser;Password=Amkor123!");
                    conn.Open();
                    string ProcName = "insert into SystemLog_STDLabelAttach(HostName,Version,Screen,Message,TraceInfo,wdate,FileName,LineNumber) values(@p1,@p2,@p3,@p4,@p5,@p6,@p7,@p8)";
                    SqlCommand cmd = new SqlCommand(ProcName, conn);
                    cmd.CommandType = CommandType.Text;
                    var param = cmd.Parameters.Add("@p1", SqlDbType.VarChar, 50);
                    param.Value = HostName;

                    param = cmd.Parameters.Add("@p2", SqlDbType.VarChar, 20);
                    param.Value = prgmVersion;

                    param = cmd.Parameters.Add("@p3", SqlDbType.VarChar, 100);
                    param.Value = Screen;

                    param = cmd.Parameters.Add("@p4", SqlDbType.VarChar, 255);
                    param.Value = Message;

                    param = cmd.Parameters.Add("@p5", SqlDbType.VarChar);
                    param.Value = TraceInfo;

                    param = cmd.Parameters.Add("@p6", SqlDbType.DateTime);
                    param.Value = DateTime.Now;

                    param = cmd.Parameters.Add("@p7", SqlDbType.VarChar, 1000);
                    param.Value = fileName;

                    param = cmd.Parameters.Add("@p8", SqlDbType.Int);
                    param.Value = lineNumber;

                    var cnt = cmd.ExecuteNonQuery();
                    conn.Close();
                }
                catch (Exception ex)
                {
                    PUB.log.AddE(ex.Message);
                }

            });
        }
        public static Boolean PasswordCheck()
        {
            var pass = new AR.Dialog.fPassword();
            if (pass.ShowDialog() == DialogResult.OK)
            {
                var p = AR.SETTING.Data.Password_Setup;
                if (p.isEmpty()) p = DateTime.Now.ToString("ddMM");
                if (pass.tbInput.Text.Trim() != p) return false;
                else return true;
            }
            else return false;
        }
        public static void LoadDataTable()
        {
            mailForm = new DataSet1.MailFormatDataTable();
            string fn = AppDomain.CurrentDomain.BaseDirectory + "mailForm.xml";
            if (System.IO.File.Exists(fn)) mailForm.ReadXml(fn);
            else
            {
                var nr = mailForm.NewMailFormatRow();
                nr.subject = "";
                nr.content = "";
                mailForm.AddMailFormatRow(nr);
                mailForm.AcceptChanges();
                mailForm.WriteXml(fn, true);
            }
            mailList = new DataSet1.MailRecipientDataTable();
            string fn1 = AppDomain.CurrentDomain.BaseDirectory + "mailList.xml";
            if (System.IO.File.Exists(fn1)) mailList.ReadXml(fn1);
            else mailList.WriteXml(fn, true);
        }
        public static Rectangle GetVisionOrientSearchArea(
           Rectangle baserect,
            int offsetX,
            int offsetY,
            out string VisionOrientMessage)
        {
            VisionOrientMessage = "";
            var newORectW = baserect.Width + offsetX;
            var newORectH = baserect.Height + offsetY;

            var newORectX = baserect.X - ((newORectW - baserect.Width) / 2.0);
            var newORectY = baserect.Y - ((newORectH - baserect.Height) / 2.0);
            if (newORectX < 1)
            {
                newORectW += (int)newORectY;
                newORectX = 1;
            }
            if (newORectY < 1)
            {
                newORectH += (int)newORectY;
                newORectY = 1;
            }
            if (newORectW < 4) newORectW = 0;
            if (newORectH < 4) newORectH = 0;
            var newORect = new Rectangle((int)newORectX, (int)newORectY, (int)newORectW, (int)newORectH);
            if (newORect.Width < 1 || newORect.Height < 1)
            {
                VisionOrientMessage = string.Format("기준영역 크기 오류({0},{1},{2},{3})", newORect.Left, newORect.Top, newORect.Width, newORect.Height);
                return Rectangle.Empty;
            }
            else return newORect;
        }

        public static void GetJobColor(Class.JobData.ErrorCode result, Color baseBack, out Color fColor, out Color bColor)
        {
            if (result == Class.JobData.ErrorCode.BarcodeRead)
            {
                //배출됫엇다면 색상을 변경한다.
                fColor = Color.Tomato;
                bColor = baseBack;
            }
            else
            {
                fColor = Color.WhiteSmoke;
                bColor = baseBack;
            }
        }

        public static DataSet1.UserSIDDataTable DTUserSID;
        public static void LoadSIDList()
        {
            if (DTUserSID == null) DTUserSID = new DataSet1.UserSIDDataTable();
            else DTUserSID.Clear();
            var fi = new System.IO.FileInfo(UTIL.CurrentPath + "Data\\UserSID.csv");


            if (fi.Exists == true)
            {
                string[] lines = null;
                try
                {
                    lines = System.IO.File.ReadAllLines(fi.FullName, System.Text.Encoding.UTF8);
                }
                catch (Exception ex)
                {
                    UTIL.MsgE(ex.Message, true);
                    lines = new string[] { };
                }
                foreach (var line in lines)
                {
                    if (line.isEmpty()) continue;
                    if (line.StartsWith("#")) continue; //주석문
                    var buffer = line.Split(',');
                    if (buffer.Length < 2) continue;
                    var port = buffer[0];
                    var sid = buffer[1];
                    if (sid.isEmpty()) continue;
                    if (port == "0") port = "11";
                    if (port == "1") port = "12";
                    if (port == "2") port = "21";
                    if (port == "3") port = "22";
                    if (port == "4") port = "31";
                    if (port == "5") port = "32";
                    if (port == "6") port = "41";
                    if (port == "7") port = "42";

                    //중복체크
                    var Exist = DTUserSID.Where(t => t.SID == sid && t.Port == port).Count() > 0;
                    if (Exist == false)
                    {
                        var newdr = DTUserSID.NewUserSIDRow();
                        newdr.Port = port;
                        newdr.SID = sid;
                        DTUserSID.AddUserSIDRow(newdr);
                    }
                }
            }
            else if (fi.Directory.Exists == false) fi.Directory.Create();

            DTUserSID.AcceptChanges();
            PUB.log.Add("User SID list: " + DTUserSID.Count.ToString() + " records loaded");
        }
        public static void SaveSIDList()
        {
            if (DTUserSID == null) return;
            var fi = new System.IO.FileInfo(UTIL.CurrentPath + "Data\\UserSID.csv");
            if (fi.Directory.Exists == false) fi.Directory.Create();

            if (DTUserSID.Count < 1) fi.Delete();
            else
            {
                //자료를 저장한다.
                var sb = new System.Text.StringBuilder();
                sb.AppendLine("#PORT,SID");
                var orderlist = from m in DTUserSID
                                orderby m.Port
                                orderby m.SID
                                select m;

                var cnt = 0;
                foreach (DataSet1.UserSIDRow dr in orderlist)
                {
                    if (dr.SID.isEmpty() || dr.Port.isEmpty()) continue;
                    sb.AppendLine(string.Format("{0},{1}", dr.Port, dr.SID));
                    cnt += 1;
                }
                System.IO.File.WriteAllText(fi.FullName, sb.ToString(), System.Text.Encoding.UTF8);
                PUB.log.Add(string.Format("{0} user SIDs have been saved", cnt));
            }
        }

        public static double GetFreeSpace(string driveletter)
        {
            try
            {
                var di = new System.IO.DriveInfo(driveletter);
                var freespace = di.TotalFreeSpace;
                var totalspace = di.TotalSize;
                var freeSpaceRate = (freespace * 1.0 / totalspace) * 100.0;
                return freeSpaceRate;
            }
            catch
            {
                return 100.0;
            }
        }

        public static string getSavePath(out double freespace)
        {
            Boolean path1Exist = false;
            double freespace1 = 100.0;
            string savePath1 = "";

            freespace = 100.0;

            savePath1 = System.IO.Path.Combine(AR.SETTING.Data.GetDataPath(), "Images");
            if (savePath1 != "" && System.IO.Directory.Exists(savePath1))
            {
                path1Exist = true;
                //이폴더를 사용
                if (savePath1.StartsWith("\\")) return savePath1;
                //남은잔량을 체크한다.
                freespace1 = GetFreeSpace(savePath1.Substring(0, 1));
                if (freespace1 >= AR.SETTING.Data.AutoDeleteThreshold) return savePath1;
            }

            if (path1Exist)
            {
                freespace = freespace1;
                return savePath1;
            }

            //이제 문제가 좀 심각? (폴더가 없다)
            var savePath = System.IO.Path.Combine(UTIL.CurrentPath, "Images");
            if (System.IO.Directory.Exists(savePath) == false)
                System.IO.Directory.CreateDirectory(savePath);

            freespace = GetFreeSpace(savePath.Substring(0, 1));
            return savePath;
        }
        public static double ChangeValuePopup(double value, string title)
        {
            var f = new AR.Dialog.fInput(title, value.ToString());
            if (f.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                var val = double.Parse(f.tbInput.Text);
                return val;
            }
            else return value;

        }

        public static (bool success, string newid, string message) MakeNewREELID(string sid)
        {
            //WMS은 DB에서 생성하낟.
            var ta = new dsWMSTableAdapters.QueriesTableAdapter();

            string NewID = string.Empty;
            string Message = string.Empty;
            var ip = PUB.IP ?? "127.0.0.1";

            var retval = ta.X_SP_GET_UNIT_ID_LABEL(SETTING.Data.WMS_PROGRAM_ID,
                SETTING.Data.WMS_CENTER_CD, sid,
                SETTING.Data.WMS_REG_USERID,
                ip,
                ref NewID,
                ref Message);

            return ((!NewID.isEmpty() && Message == "OK"), NewID, Message);
        }

        public static void CheckFreeSpace()
        {
            //용량확인
            var DriveName = AR.SETTING.Data.GetDataPath().Substring(0, 1);
            PUB.FreeSpace = UTIL.GetFreeSpace(DriveName);

        }

        public static void splitID(string ID, out string ww, out string seq)
        {
            if (ID.Length < 3)
            {
                ww = "";
                seq = "";
            }
            else
            {
                try
                {
                    ww = ID.Substring(0, 2);// int.Parse(ID.Substring(0, 2));
                    seq = ID.Substring(2);// int.Parse(ID.Substring(2));
                }
                catch (Exception ex)
                {
                    PUB.log.AddE("slit id eerr" + ex.Message);
                    ww = "";
                    seq = "-1";
                }
            }
        }
        public static UInt16[] SIDtoUInt16(string sid)
        {
            var sidstr = sid.PadLeft(10, '0'); //총 10자리로 만들어놓는다
            var getbytes = System.Text.Encoding.Default.GetBytes(sidstr);

            var c1 = getbytes[1].ToString("X2") + getbytes[0].ToString("x2");
            var c2 = getbytes[3].ToString("X2") + getbytes[2].ToString("x2");
            var c3 = getbytes[5].ToString("X2") + getbytes[4].ToString("x2");
            var c4 = getbytes[7].ToString("X2") + getbytes[6].ToString("x2");
            var c5 = getbytes[9].ToString("X2") + getbytes[8].ToString("x2");

            var Buffer = new UInt16[5];
            var index = 0;
            Buffer[index++] = Convert.ToUInt16(c1, 16);
            Buffer[index++] = Convert.ToUInt16(c2, 16);
            Buffer[index++] = Convert.ToUInt16(c3, 16);
            Buffer[index++] = Convert.ToUInt16(c4, 16);
            Buffer[index++] = Convert.ToUInt16(c5, 16);
            return Buffer;
        }

        public static void ChangeUIPopup(System.Windows.Forms.NumericUpDown valueCtl)
        {
            var value = valueCtl.Value.ToString();
            AR.Dialog.fInput f = new AR.Dialog.fInput("Input value", value);
            if (f.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                var val = decimal.Parse(f.tbInput.Text);
                if (val < valueCtl.Minimum)
                {
                    UTIL.MsgE(string.Format("Minimum input value is {0}.", valueCtl.Minimum));
                    val = valueCtl.Minimum;
                }
                if (val > valueCtl.Maximum)
                {
                    UTIL.MsgE(string.Format("Maximum input value is {0}.", valueCtl.Maximum));
                    val = valueCtl.Maximum;
                }
                valueCtl.Value = val;
            }
        }

        #region "message description"


        public static string GetErrorMessage(eECode err, params object[] args)
        {
            string ermsg = string.Empty;
            string description = string.Empty;

            // Get error description using switch statement with hardcoded messages
            switch (err)
            {
                case eECode.EMERGENCY:
                    description = "Emergency stop activated\nPlease check the emergency button and reset";
                    break;
                case eECode.NOMODELV:
                    description = "Vision model not found\nPlease load or create a vision model";
                    break;
                case eECode.NOMODELM:
                    description = "Motion model not found\nPlease load or create a motion model";
                    break;
                case eECode.HOME_TIMEOUT:
                    description = "Home position timeout\nMotor failed to reach home position within timeout period";
                    break;
                case eECode.NOFUNCTION:
                    description = "Function not available\nThe requested function is not implemented";
                    break;
                case eECode.DOOFF:
                    description = "Digital output OFF failed\n{0}";
                    break;
                case eECode.DOON:
                    description = "Digital output ON failed\n{0}";
                    break;
                case eECode.DIOFF:
                    description = "Waiting for digital input OFF\n{0}";
                    break;
                case eECode.DION:
                    description = "Waiting for digital input ON\n{0}";
                    break;
                case eECode.MESSAGE_INFO:
                    description = "Information: {0}";
                    break;
                case eECode.MESSAGE_ERROR:
                    description = "Error: {0}";
                    break;
                case eECode.AZJINIT:
                    description = "Motion controller initialization failed\nPlease check the motion card connection";
                    break;
                case eECode.MOT_SVOFF:
                    description = "Motor servo is OFF\nPlease turn on the servo motor";
                    break;
                case eECode.MOT_CMD:
                    description = "Motion command error\n{0}";
                    break;
                case eECode.USER_STOP:
                    description = "User stop requested\nOperation stopped by user";
                    break;
                case eECode.USER_STEP:
                    description = "Step mode active\nPress continue to proceed";
                    break;
                case eECode.POSITION_ERROR:
                    description = "Position error\nAxis is not at the expected position\n{0}";
                    break;
                case eECode.MOTIONMODEL_MISSMATCH:
                    description = "Motion model mismatch\nThe loaded motion model does not match the system configuration";
                    break;
                case eECode.VISCONF:
                    description = "Vision configuration error\nPlease check vision system settings";
                    break;

                case eECode.PRINTER:
                    description = "Printer error\nPlease check the printer connection and status\n{0}";
                    break;
                case eECode.QRDATAMISSMATCHL:
                    description = "Left QR data mismatch\nThe QR code data does not match expected format\n{0}";
                    break;
                case eECode.QRDATAMISSMATCHR:
                    description = "Right QR data mismatch\nThe QR code data does not match expected format\n{0}";
                    break;
                case eECode.MOTX_SAFETY:
                    description = "Motion X-axis safety error\nSafety condition violated for X-axis movement";
                    break;

                default:
                    description = $"Unknown error code: {err}\n{{0}}";
                    break;
            }

            // Format the message with any provided arguments
            try
            {
                ermsg = string.Format(description, args);
            }
            catch
            {
                // If formatting fails, just use the description as is
                ermsg = description;
            }

            return ermsg;
        }

        public static string GetPinDescription(eDIName pin)
        {
            var pinno = (int)pin;
            string ermsg = $"[X{pinno:X2}] {pin}";
            try
            {
                var dr = PUB.mdm.dataSet.InputDescription.Where(t => t.Idx == (short)pin).FirstOrDefault();
                if (dr != null)
                {
                    if (dr.Description.isEmpty()) ermsg += $" {pin}";
                    else ermsg += $" " + dr.Description.Replace("\\n", "\n");
                }
            }
            catch (Exception ex) { ermsg += "\n설명가져오기오류\n" + ex.Message; }
            return ermsg;
        }

        public static string GetPinDescription(eDOName pin)
        {
            var pinno = (int)pin;
            string ermsg = $"[X{pinno:X2}] {pin}";
            try
            {
                var dr = PUB.mdm.dataSet.OutputDescription.Where(t => t.Idx == (short)pin).FirstOrDefault();
                if (dr != null)
                {
                    if (dr.Description.isEmpty()) ermsg += $" {pin}";
                    else ermsg += $" " + dr.Description.Replace("\\n", "\n");
                }
            }
            catch (Exception ex) { ermsg += "\n설명가져오기오류\n" + ex.Message; }
            return ermsg;
        }

        public static string GetPinName(eDIName pin)
        {
            var pinno = (int)pin;
            string ermsg = $"[X{pinno:X2}] {pin}";


            try
            {
                var dr = PUB.mdm.dataSet.InputDescription.Where(t => t.Idx == (short)pin).FirstOrDefault();
                if (dr != null)
                {
                    ermsg = dr.Title;
                }
            }
            catch (Exception ex) { ermsg += "\n이름가져오기오류\n" + ex.Message; }



            return ermsg;
        }

        public static string GetPinName(eDOName pin)
        {
            var pinno = (int)pin;
            string ermsg = $"[Y{pinno:X2}] {pin}";

            try
            {
                var dr = PUB.mdm.dataSet.OutputDescription.Where(t => t.Idx == (short)pin).FirstOrDefault();
                if (dr != null)
                {
                    ermsg = dr.Title;
                }
            }
            catch (Exception ex) { ermsg += "\n이름가져오기오류\n" + ex.Message; }


            return ermsg;
        }
        public static string GetResultCodeMessage(eResult rltCode)
        {
            //별도 메세지처리없이 그대로 노출한다
            return rltCode.ToString().ToUpper();
        }

        #endregion

    }
}
