using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using DDUtilityApp.LOGPARSER.DATA;
using DDUtilityApp.SECS;
using JWH;
using JWH.CONTROL;

namespace DDUtilityApp.LOGPARSER.PARSER
{

    public class EisParser : LogParser
    {

        #region [ Properties ] ------------------------------------------------

        #endregion

        #region [ EisParser ] -------------------------------------------------

        public EisParser() : base()
        {
            this.Text = $"[EverOne] EIS Log Viewer";
            this.LogDTimeStart = 0;
            this.LogDTime = "yyyy-MM-dd HH:mm:ss.fff";
        }

        public EisParser(params string[] files) : base(files)
        {
            //this.LineHeader = "yyyy-MM-dd HH:mm:ss.fff";
        }

        #endregion

        #region [ Method ] ----------------------------------------------------

        public override bool Parsing()
        {
            try
            {
                base.Initilize();
                foreach (string file in this.Files)
                {
                    StreamReader reader = null;
                    try
                    {
                        reader = new StreamReader(file, Encoding.Default);

                        long readerPosition = reader.BaseStream.Position;
                        string strLine = this.GetReadLine(reader);
                        while (strLine != null)
                        {
                            Parser parser = this.GetParser(strLine);
                            if (parser == null)
                            {
                                strLine = this.GetReadLine(reader);
                                continue;
                            }

                            StandardData standardData = parser(reader, ref strLine) as StandardData;
                            if (standardData != null)
                            {
                                standardData.Column5 = System.IO.Path.GetFileName(file);
                                //if (standardData.Body != null) standardData.Body.Clear();
                            }
                        }
                    }
                    catch (Exception ex01)
                    {
                        XLogger.Instance.Fatal(ex01);
                    }

                    if (reader != null) reader.Close();
                }
            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex);
                return false;
            }
            finally
            {
                this.SendStandardData.Clear();
            }

            return true;
        }

        protected Parser GetParser(string strLine)
        {
            Parser parser = null;
            try
            {
                if (string.IsNullOrWhiteSpace(strLine)) return parser;
                if (strLine.Length < this.LogDTime.Length) return parser;
                string[] strValues = this.GetHeaderValues(strLine);
                if (strValues == null) return parser;
                for (int i = 0; i < strValues.Length; i++) strValues[i] = strValues[i].ToUpper();

                if (strValues[2].Trim().StartsWith("EQP"))
                {
                    if (new string[] { "DATA" }.Contains(strValues[3])) parser = this.SECS_Parser;
                    else if (new string[] { "TIMEOUT" }.Contains(strValues[4])) parser = this.SECS_Parser;
                    else if (new string[] { "ERROR" }.Contains(strValues[3])) parser = this.ERROR0_Parser;
                    else parser = this.PLC_Parser;
                }
                else if (strValues[2].Trim() == "RMS")
                {
                    parser = this.RMS_Parser;
                }
                else if (strValues[2].Trim() == "FDC")
                {
                    parser = this.FDC_Parser;
                }
                else if (strValues[2].Trim() == "RTD")
                {
                    parser = this.RTD_Parser;
                }
                else if (strValues[2].Trim() == "MES")
                {
                    parser = this.MES_Parser;
                }
                else if (strValues[2].Trim() == "ADD" || strValues[2].Trim() == "DISPOSE")
                {
                    parser = this.TID_Parser;
                }
                else if (strValues[2].Trim() == "▶▶")
                {
                    parser = this.ERROR1_Parser;
                }
                else if (strValues[2].Trim().ToUpper().IndexOf("EXCEPTION") >= 0)
                {
                    parser = this.EXCEPTION_Parser;
                }
                else
                {
                    if (new string[] { strValues[3], strValues[4] }.Contains("TRANSACTIONID")) parser = this.TRANSACTIONID_Parser;
                    else if (new string[] { strValues[3], strValues[4] }.Contains("TID")) parser = this.TRANSACTIONID_Parser;
                    else parser = this.ETC_Parser;
                }
            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex);
                return parser;
            }

            return parser;
        }

        private string[] GetHeaderValues(string strLine)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(strLine)) return null;
                if (strLine.Length < this.LogDTimeStart + this.LogDTime.Length) return null;

                DateTime dtime = DateTime.MinValue;
                string strDTime = strLine.Substring(this.LogDTimeStart, this.LogDTime.Length);
                if (DateTime.TryParseExact(strDTime, this.LogDTime, null, System.Globalization.DateTimeStyles.None, out dtime) == false) return null;

                List<string> lstValues = new List<string>();
                lstValues.Add(dtime.ToString("yyyy-MM-dd HH:mm:ss.fff"));
                lstValues.AddRange(strLine.Substring(this.LogDTimeStart + this.LogDTime.Length).Split(new string[] { ":", "|", " " }, StringSplitOptions.RemoveEmptyEntries));

                return lstValues.ToArray();
            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex);
                return null;
            }
        }

        private bool IsEnd(string strLine)
        {
            try
            {
                string strDTime = string.Empty;
                DateTime dtime = DateTime.Now;
                if (strLine.Length > this.LogDTimeStart + this.LogDTime.Length)
                {
                    strDTime = strLine.Substring(this.LogDTimeStart, this.LogDTime.Length);
                    return DateTime.TryParseExact(strDTime, this.LogDTime, null, System.Globalization.DateTimeStyles.None, out dtime);
                }
            }
            catch (Exception ex)
            {
                //XLogger.Instance.Fatal(ex);
            }

            return false;
        }

        private SECSItem GetSECSItem(string message, string text)
        {
            if (string.IsNullOrEmpty(text)) return null;
            SECSItem root = null;

            try
            {
                MemoryStream stream = new MemoryStream(text.ConvertBytes());
                StreamReader reader = new StreamReader(stream);

                SECSItem parent = null;
                SECSItem item = null;
                char chValue;
                string strValue = string.Empty;
                while (!reader.EndOfStream)
                {
                    chValue = (char)reader.Read();

                    if (new char[] { ' ', '>', (char)0x0D, (char)0x0A, (char)0x09 }.Contains(chValue))
                    {
                        strValue = string.Empty;
                    }
                    else if (chValue == '<')
                    {
                        item = new SECSItem();
                        if (parent != null)
                        {
                            while (parent.Length <= parent.Count)
                                parent = parent.Parent;
                            parent.Add(item);
                        }
                        if (root == null) root = item;
                    }
                    else if (chValue == '[')
                    {
                        strValue = this.GetString(reader, ']').Replace("V", "");
                        item.Length = Convert.ToInt16(strValue);
                        strValue = string.Empty;
                    }
                    else if (chValue == '\'')
                    {
                        strValue = this.GetString(reader, '\'');
                        item.Value = strValue;
                        strValue = string.Empty;
                    }
                    else if (string.IsNullOrEmpty(item.Format))
                    {
                        strValue += chValue.ToString();
                        if (SECSLib.ItemFormat.Keys.Contains(strValue))
                        {
                            item.Format = strValue;
                            strValue = string.Empty;
                            if (SECSLib.ItemFormat[item.Format] == typeof(IList)) parent = item;
                        }
                    }
                    else
                    {
                        strValue += chValue.ToString();
                        item.Name = strValue;
                    }
                }

                root.Stream = message.ToUpper().Substring(1, message.IndexOf('F') - 1);
                root.Function = message.ToUpper().Substring(message.IndexOf('F') + 1);
                return root;
            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(message, ex);
                return null;
            }
        }

        private string GetString(StreamReader reader, params char[] chLast)
        {
            char chValue;
            StringBuilder sbValue = new StringBuilder();
            while (!reader.EndOfStream)
            {
                chValue = (char)reader.Read();  //.Read();
                if (chLast.Contains(chValue)) return sbValue.ToString();
                sbValue.Append(chValue);
            }

            return sbValue.ToString();
        }

        public override void SetGridHeader(GridViewEx grid)
        {
            grid.AddColumn("DateTime");
            grid.AddColumn("Level");
            grid.AddColumn("Server");
            grid.AddColumn("Service");
            grid.AddColumn("Type");
            grid.AddColumn("MessageName");
            grid.AddColumn("Return");
            grid.AddColumn("Value");
            grid.AddColumn("LotID");
            grid.AddColumn("CarrierID");
            grid.AddColumn("EquipmentID");
            grid.AddColumn("PortID");
            grid.AddColumn("SystemByte");
            grid.AddColumn("HostPanelID");
            grid.AddColumn("PanelID");
            grid.AddColumn("PanelQty");
            grid.AddColumn("TID");
            grid.AddColumn("Column1");
            grid.AddColumn("Column2");
            grid.AddColumn("Column3");
            grid.AddColumn("Column4");
            grid.AddColumn("Column5");
        }

        public override LogFile[] FileSelector(FrmLogParser sender, params LogFile[] args)
        {
            FrmEqSelector dlg = null;
            try
            {
                List<LogFile> logFiles = new List<LogFile>();
                logFiles.AddRange(args);

                dlg = new FrmEqSelector();
                dlg.Owner = sender;
                dlg.Size = sender.Size;
                dlg.StartPosition = FormStartPosition.CenterParent;
                dlg.Equipment = sender.Equipment;
                dlg.SelectedLogFiles = logFiles.ToArray();
                DialogResult dlgResult = dlg.ShowDialog();
                if (dlgResult != DialogResult.OK) return null;

                EisEquipment equipment = dlg.Equipment as EisEquipment;
                if (equipment == null) return null;

                sender.Equipment = equipment;
                sender.SECSDefine = dlg.SECSDefine;

                return dlg.SelectedLogFiles;
            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex, true);
                return null;
            }
            finally
            {
                if (dlg != null) dlg.Dispose();
            }
        }

        #endregion


        #region [ Method : delegate object Parser() ] -------------------------

        protected Dictionary<string, StandardData> SendStandardData { get; set; } = new Dictionary<string, StandardData>();

        protected object SECS_Parser(StreamReader reader, ref string startLine)
        {
            string strLine = startLine;
            StandardData standardData = null;

            try
            {
                if (string.IsNullOrWhiteSpace(strLine)) return standardData;
                if (strLine.Length < this.LogDTime.Length) return standardData;
                string[] strValues = this.GetHeaderValues(strLine);
                if (strValues == null) return standardData;

                DateTime dtime = DateTime.MinValue;
                if (DateTime.TryParse(strValues[0], out dtime) == false) return standardData;

                standardData = new StandardData();
                standardData.LineNumber = this.LineNumber;
                standardData.DateTime = dtime;
                this.StandardCollection.Add(standardData);

                #region [ Header Line ] ---------------------------------------

                for (int index = 0; index < strValues.Length; index++)
                {
                    string strValue = strValues[index];
                    if (index == 0) { continue; }
                    if (index == 1) { standardData.Level = strValue; continue; }
                    if (index == 2) { standardData.Server = strValue; continue; }
                    if (index == 4)
                    { 
                        standardData.Type = strValue;
                        if (strValue == "TIMEOUT")
                        {
                            standardData.MessageName = $"{strValues[3]} {strValue}";
                            standardData.Return = "1";
                        }
                        continue;
                    }
                    if (index == 10) { standardData.SystemByte = $"SystemByte[{strValue}]"; continue; }
                    if (index == 11) { standardData.MessageName = strValue; continue; }
                }

                #endregion ----------------------------------------------------

                #region [ SECS Body ] -----------------------------------------

                strLine = this.GetReadLine(reader, false);
                while (string.IsNullOrWhiteSpace(strLine) == false)
                {
                    if (this.IsEnd(strLine)) break;

                    standardData.Body.AppendLine(strLine);
                    strLine = this.GetReadLine(reader, false);
                }
                startLine = strLine;

                #endregion ----------------------------------------------------

                #region [ Get SECS Data ] -------------------------------------

                SECSItem rootSECS = this.GetSECSItem(standardData.MessageName, standardData.Body.ToString());
                standardData.SECSItem = rootSECS;

                if (rootSECS == null || $"S{rootSECS.Stream}F{rootSECS.Function}" != "S6F11")
                    this.LogString_Append(standardData.Body.ToString());

                SECSItem secsItem = null;
                SECSItem[] secsItems = null;
                if (rootSECS != null)
                {
                    // GetData S2F23
                    if (rootSECS.Stream == "2" && rootSECS.Function == "23")
                    {
                        // TRID
                        secsItem = rootSECS.GetItemByName("TRID").FirstOrDefault();
                        if (secsItem != null) standardData.Value = $"TRID: {secsItem.Value}";

                        // DSPER
                        //secsItem = rootSECS.GetItemByName("DSPER").FirstOrDefault();
                        //if (secsItem != null) standardData.Value += $", DSPER: {secsItem.Value}";

                        // TOTSMP
                        secsItem = rootSECS.GetItemByName("TOTSMP").FirstOrDefault();
                        if (secsItem != null) standardData.Value += $", TOTSMP: {secsItem.Value}";
                    }

                    // GetData S2F41
                    if (rootSECS.Stream == "2" && rootSECS.Function == "41")
                    {
                        // RCMD
                        secsItem = rootSECS.GetItemByName("RCMD").FirstOrDefault();
                        if (secsItem == null) secsItem = rootSECS[0];
                        if (secsItem != null) standardData.Value = $"RCMD: {secsItem.Value}";

                        // LOTID
                        secsItems = rootSECS.GetItemCPValue("LOTID", "LOT_ID", "LEFT_LOTID", "RIGHT_LOTID");
                        foreach (SECSItem item in secsItems)
                        {
                            if (!string.IsNullOrEmpty(standardData.LotID))
                                if (standardData.LotID.IndexOf(item.Value) >= 0) continue;
                                else standardData.LotID += ", ";
                            standardData.LotID += item.Value;
                        }

                        // EQUIPMENT_ID
                        secsItems = rootSECS.GetItemCPValue("EQUIPMENT_ID", "EquipmentID", "Equipment ID");
                        foreach (SECSItem item in secsItems)
                        {
                            if (!string.IsNullOrEmpty(standardData.EquipmentID)) break; // standardData.EquipmentID += ", ";
                            standardData.EquipmentID += item.Value;
                        }

                        // CARRIER_ID
                        secsItems = rootSECS.GetItemCPValue("CARRIER_ID", "LEFT_CARRIER_ID", "RIGHT_CARRIER_ID");
                        foreach (SECSItem item in secsItems)
                        {
                            if (!string.IsNullOrEmpty(standardData.CarrierID))
                                if (standardData.CarrierID.IndexOf(item.Value) >= 0) continue;
                                else standardData.CarrierID += ", ";
                            standardData.CarrierID += item.Value;
                        }

                        // PORT_ID
                        secsItems = rootSECS.GetItemCPValue("PORT_ID");
                        foreach (SECSItem item in secsItems)
                        {
                            if (!string.IsNullOrEmpty(standardData.PortID)) break; // standardData.PortID += ", ";
                            standardData.PortID += item.Value;
                        }

                        this.SendStandardData.Add(standardData.SystemByte, standardData);
                    }

                    // GetData S2F42
                    if (rootSECS.Stream == "2" && rootSECS.Function == "42")
                    {
                        // RCMD
                        secsItem = rootSECS.GetItemByName("HCACK").FirstOrDefault();
                        if (secsItem == null) secsItem = rootSECS[0];
                        if (secsItem != null) standardData.Value = secsItem.Value;

                        if (new string[] { "0", "4" }.Contains(secsItem.Value.Substring(0, 1)) == false) standardData.Return = secsItem.Value;
                        if (standardData?.SystemByte != null && this.SendStandardData.ContainsKey(standardData.SystemByte))
                        {
                            StandardData sendData = this.SendStandardData[standardData.SystemByte];
                            sendData.PropertiesCopy(standardData, false);
                            if (string.IsNullOrEmpty(standardData.Return)) standardData.Value = $"{standardData.Value}";
                            else standardData.Value = $"RCMD: {sendData.SECSItem[0].Value} is {standardData.Value}";
                            this.SendStandardData.Remove(standardData.SystemByte);
                        }
                    }

                    // GetData S6F1
                    if (rootSECS.Stream == "6" && rootSECS.Function == "1")
                    {
                        // RCMD
                        secsItem = rootSECS.GetItemByName("TRID").FirstOrDefault();
                        if (secsItem == null) secsItem = rootSECS[0];
                        if (secsItem != null) standardData.Value = $"TRID: {secsItem.Value}, SMPLN: {rootSECS.ChildItems[1].Value}";
                    }

                    // GetData S6F11
                    if (rootSECS.Stream == "6" && rootSECS.Function == "11")
                    {
                        if (this.SECSDefine != null) this.SECSDefine.SetInformation(rootSECS);
                        this.LogString_Append(rootSECS.ToFullString());

                        // CEID
                        secsItem = rootSECS.GetItemByName("CEID").FirstOrDefault();
                        if (secsItem == null && rootSECS.ChildItems.Count == 3) secsItem = rootSECS[1];
                        standardData.Value = $"CEID: {secsItem.Value}" + (string.IsNullOrEmpty(secsItem.Description) ? "" : $" {secsItem.Description}");

                        // LOTID
                        secsItems = rootSECS.GetItemByName("LOT_ID", "LOTID", "LotID", "LEFT_LOTID", "RIGHT_LOTID");
                        foreach (SECSItem item in secsItems)
                        {
                            if (!string.IsNullOrEmpty(standardData.LotID))
                                if (standardData.LotID.IndexOf(item.Value) >= 0) continue;
                                else standardData.LotID += ", ";
                            standardData.LotID += item.Value;
                        }

                        // EQUIPMENT_ID
                        secsItems = rootSECS.GetItemByName("EQUIPMENT_ID", "EquipmentID", "Equipment ID");
                        foreach (SECSItem item in secsItems)
                        {
                            if (!string.IsNullOrEmpty(standardData.EquipmentID)) break; // standardData.EquipmentID += ", ";
                            standardData.EquipmentID += item.Value;
                        }

                        // CARRIER_ID
                        secsItems = rootSECS.GetItemByName("CARRIER_ID", "LEFT_CARRIER_ID", "RIGHT_CARRIER_ID");
                        foreach (SECSItem item in secsItems)
                        {
                            if (!string.IsNullOrEmpty(standardData.CarrierID))
                                if (standardData.CarrierID.IndexOf(item.Value) >= 0) continue;
                                else standardData.CarrierID += ", ";
                            standardData.CarrierID += item.Value;
                        }

                        // PORT_ID
                        secsItems = rootSECS.GetItemByName("PORT_ID");
                        foreach (SECSItem item in secsItems)
                        { 
                            if (!string.IsNullOrEmpty(standardData.PortID)) break; // standardData.PortID += ", ";
                            standardData.PortID += item.Value;
                        }

                        // SUBSTRATE_ID
                        secsItems = rootSECS.GetItemByName("SUBSTRATE_ID", "SUBSTRATEID");
                        foreach (SECSItem item in secsItems)
                        {
                            if (!string.IsNullOrEmpty(standardData.PanelID)) break; // standardData.PanelID += ", ";
                            standardData.PanelID += item.Value;
                        }

                        // HOST_SUBSTRATE_ID
                        secsItems = rootSECS.GetItemByName("HOST_SUBSTRATE_ID", "HOSTSUBSTRATEID");
                        foreach (SECSItem item in secsItems)
                        {
                            if (!string.IsNullOrEmpty(standardData.HostPanelID)) break; // standardData.HostPanelID += ", ";
                            standardData.HostPanelID += item.Value;
                        }

                        // MODULE_ID
                        secsItems = rootSECS.GetItemByName("MODULE_ID", "MODULEID");
                        foreach (SECSItem item in secsItems)
                        {
                            if (!string.IsNullOrEmpty(standardData.Column1)) break; // standardData.HostPanelID += ", ";
                            standardData.Column1 += item.Value;
                        }

                        this.SendStandardData.Add(standardData.SystemByte, standardData);
                    }

                    // GetData S6F12
                    if (rootSECS.Stream == "6" && rootSECS.Function == "12")
                    {
                        // RCMD
                        secsItem = rootSECS.GetItemByName("ACKC6").FirstOrDefault();
                        if (secsItem == null) secsItem = rootSECS;
                        if (secsItem != null) standardData.Value = secsItem.Value;

                        if (new string[] { "0" }.Contains(secsItem.Value.Substring(0, 1)) == false) standardData.Return = secsItem.Value;
                        if (standardData?.SystemByte != null && this.SendStandardData.ContainsKey(standardData.SystemByte))
                        {
                            StandardData sendData = this.SendStandardData[standardData.SystemByte];
                            sendData.PropertiesCopy(standardData, false);
                            if (string.IsNullOrEmpty(standardData.Return)) standardData.Value = $"{standardData.Value}";
                            else standardData.Value = $"CEID: {sendData.SECSItem[1].Value} is {standardData.Value}";
                            this.SendStandardData.Remove(standardData.SystemByte);
                        }
                    }

                    // GetData S7F23 : Formatted Process Program Send
                    if (rootSECS.Stream == "7" && rootSECS.Function == "23")
                    {
                        // PPID
                        secsItem = rootSECS.GetItemByName("PPID").FirstOrDefault();
                        if (secsItem == null) secsItem = rootSECS[0];
                        if (secsItem != null) standardData.Value = $"PPID: {secsItem.Value}";

                        this.SendStandardData.Add(standardData.SystemByte, standardData);
                    }

                    // GetData S7F24
                    if (rootSECS.Stream == "7" && rootSECS.Function == "24")
                    {
                        // ACKC7
                        secsItem = rootSECS.GetItemByName("ACKC7").FirstOrDefault();
                        if (secsItem == null)
                        {
                            if (rootSECS.ChildItems != null && rootSECS.ChildItems.Count > 0) secsItem = rootSECS[0];
                            else secsItem = rootSECS;
                        }
                        if (secsItem != null) standardData.Value = secsItem.Value;

                        if (new string[] { "0" }.Contains(secsItem.Value.Substring(0, 1)) == false) standardData.Return = secsItem.Value;
                        if (standardData?.SystemByte != null && this.SendStandardData.ContainsKey(standardData.SystemByte))
                        {
                            StandardData sendData = this.SendStandardData[standardData.SystemByte];
                            sendData.PropertiesCopy(standardData, false);
                            if (string.IsNullOrEmpty(standardData.Return)) standardData.Value = $"{standardData.Value}";
                            else standardData.Value = $"FPPS: {sendData.SECSItem[0].Value} is {standardData.Value}";
                            this.SendStandardData.Remove(standardData.SystemByte);
                        }
                    }

                    // GetData S7F25 : Formatted Process Program Request
                    if (rootSECS.Stream == "7" && rootSECS.Function == "25")
                    {
                        // PPID
                        secsItem = rootSECS.GetItemByName("PPID").FirstOrDefault();
                        if (secsItem == null) secsItem = rootSECS[0];
                        if (secsItem != null) standardData.Value = $"PPID: {secsItem.Value}";

                        this.SendStandardData.Add(standardData.SystemByte, standardData);
                    }

                    // GetData S7F26
                    if (rootSECS.Stream == "7" && rootSECS.Function == "26")
                    {
                        if (standardData?.SystemByte != null && this.SendStandardData.ContainsKey(standardData.SystemByte))
                        {
                            StandardData sendData = this.SendStandardData[standardData.SystemByte];
                            sendData.PropertiesCopy(standardData, false);
                            if (string.IsNullOrEmpty(standardData.Return)) standardData.Value = $"{standardData.Value}";
                            else standardData.Value = $"FPPD: {sendData.SECSItem[0].Value} is {standardData.Value}";
                            this.SendStandardData.Remove(standardData.SystemByte);
                        }
                    }

                }

                #endregion ----------------------------------------------------

            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex);
                if (standardData != null) XLogger.Instance.Error($"{standardData.DateTime} {standardData.SystemByte}");
            }

            return standardData;
        }

        protected object PLC_Parser(StreamReader reader, ref string startLine)
        {
            string strLine = startLine;
            StandardData standardData = null;

            try
            {
                if (string.IsNullOrWhiteSpace(strLine)) return standardData;
                if (strLine.Length < this.LogDTime.Length) return standardData;
                string[] strValues = this.GetHeaderValues(strLine);
                if (strValues == null) return standardData;

                DateTime dtime = DateTime.MinValue;
                if (DateTime.TryParse(strValues[0], out dtime) == false) return standardData;

                standardData = new StandardData();
                standardData.LineNumber = this.LineNumber;
                standardData.DateTime = dtime;
                this.StandardCollection.Add(standardData);

                #region [ Header Line ] ---------------------------------------

                standardData.MessageName = strValues[strValues.Length - 1].Replace("(", "").Replace(")", "");
                for (int index = 0; index < strValues.Length; index++)
                {
                    string strValue = strValues[index];
                    if (index == 0) { continue; }
                    if (index == 1) { standardData.Level = strValue; continue; }
                    if (index == 2) { standardData.Server = strValue; continue; }
                    if (index == 3) { standardData.Type = strValue; continue; }
                    if (index == 6) { standardData.MessageName = strValue; continue; }
                    if (index == 8) { standardData.Value = strValue; continue; }
                }

                #endregion ----------------------------------------------------

                #region [ PLC Body ] ------------------------------------------

                strLine = this.GetReadLine(reader);
                while (string.IsNullOrWhiteSpace(strLine) == false)
                {
                    if (this.IsEnd(strLine)) break;

                    standardData.Body.AppendLine(strLine);
                    strLine = this.GetReadLine(reader);
                }
                startLine = strLine;

                #endregion ----------------------------------------------------

            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex);
            }

            return standardData;
        }


        protected object MES_Parser(StreamReader reader, ref string startLine)
        {
            try
            {
                return this.Message_Parser(reader, ref startLine);
            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex);
            }

            return null;
        }

        protected object RMS_Parser(StreamReader reader, ref string startLine)
        {
            try
            {
                return this.Message_Parser(reader, ref startLine);
            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex);
            }

            return null;
        }

        protected object FDC_Parser(StreamReader reader, ref string startLine)
        {
            try
            {
                return this.Message_Parser(reader, ref startLine);
            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex);
            }

            return null;
        }

        protected object RTD_Parser(StreamReader reader, ref string startLine)
        {
            try
            {
                return this.Message_Parser(reader, ref startLine);
            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex);
            }

            return null;
        }

        protected object Message_Parser(StreamReader reader, ref string startLine)
        {
            string strLine = startLine;
            StandardData standardData = null;

            try
            {
                if (string.IsNullOrWhiteSpace(strLine)) return standardData;
                if (strLine.Length < this.LogDTime.Length) return standardData;
                string[] strValues = this.GetHeaderValues(strLine);
                if (strValues == null) return standardData;

                DateTime dtime = DateTime.MinValue;
                if (DateTime.TryParse(strValues[0], out dtime) == false) return standardData;

                Type type = typeof(StandardData);
                standardData = new StandardData();
                standardData.LineNumber = this.LineNumber;
                standardData.DateTime = dtime;
                this.StandardCollection.Add(standardData);

                #region [ Header Line ] ---------------------------------------

                int columnIndex = 1;
                for (int index = 0; index < strValues.Length; index++)
                {
                    string strValue = strValues[index];
                    if (index == 0) { continue; }
                    if (index == 1) { standardData.Level = strValue; continue; }
                    if (index == 2) { standardData.Server = strValue; continue; }
                    if (index == 3) { standardData.Service = strValue; continue; }
                    if (index == 4) { standardData.Type = strValue; continue; }
                    if (index == 5 && strValue.ToUpper().StartsWith("SYSTEMBYTE")) { standardData.SystemByte = strValue; continue; }

                    string propertyName = $"Column{columnIndex}";
                    PropertyInfo property = typeof(StandardData).GetProperty(propertyName);
                    if (property != null) { property.SetValue(standardData, strValue); columnIndex++; continue; }
                }

                #endregion ----------------------------------------------------

                #region [ Message Body ] --------------------------------------

                strLine = this.GetReadLine(reader);
                while (strLine != null)
                {
                    if (this.IsEnd(strLine)) break;

                    standardData.Body.AppendLine(strLine);
                    strLine = this.GetReadLine(reader);
                }
                startLine = strLine;

                XmlDocument document = new XmlDocument();
                if (standardData.Body.Length > 4) document.LoadXml(standardData.Body.ToString());

                #endregion ----------------------------------------------------

                #region [ Get Message Data ] ----------------------------------

                if (document != null && document.ChildNodes.Count > 0)
                {
                    List<KeyValuePair<string, string>> keyValueList = new List<KeyValuePair<string, string>>();
                    keyValueList.Add(new KeyValuePair<string, string>("messagename", "MessageName"));
                    keyValueList.Add(new KeyValuePair<string, string>("transactionid", "TID"));
                    keyValueList.Add(new KeyValuePair<string, string>("returncode", "Return"));
                    keyValueList.Add(new KeyValuePair<string, string>("EQUIPMENTID", "EquipmentID"));
                    keyValueList.Add(new KeyValuePair<string, string>("PORTID", "PortID"));
                    keyValueList.Add(new KeyValuePair<string, string>("CARRIERID", "CarrierID"));
                    keyValueList.Add(new KeyValuePair<string, string>("LEFTCARRIERID", "CarrierID"));
                    keyValueList.Add(new KeyValuePair<string, string>("RIGHTCARRIERID", "CarrierID"));
                    keyValueList.Add(new KeyValuePair<string, string>("LOTID", "LotID"));
                    keyValueList.Add(new KeyValuePair<string, string>("HOSTPANELID", "HostPanelID"));
                    keyValueList.Add(new KeyValuePair<string, string>("MARKINGID", "HostPanelID"));
                    keyValueList.Add(new KeyValuePair<string, string>("PANELID", "PanelID"));
                    keyValueList.Add(new KeyValuePair<string, string>("PANELQTY", "PanelQty"));
                    keyValueList.Add(new KeyValuePair<string, string>("MODULEID", "Column1"));
                    keyValueList.Add(new KeyValuePair<string, string>("TRACEID", "Value"));
                    keyValueList.Add(new KeyValuePair<string, string>("SMPLN", "Value"));

                    foreach (KeyValuePair<string, string> pair in keyValueList)
                    {
                        XmlNode node = document.SelectSingleNode($"//{pair.Key}");
                        if (node == null) continue;

                        PropertyInfo property = type.GetProperty(pair.Value);
                        if (property != null)
                        {
                            string orgValue = (string)property.GetValue(standardData);
                            if(!string.IsNullOrEmpty(orgValue))
                            {
                                if (orgValue.IndexOf(node.InnerText) >= 0) continue;
                                if (!string.IsNullOrEmpty(orgValue)) orgValue = $"{orgValue}, {node.InnerText}";
                                else orgValue = node.InnerText;

                            }
                            else
                            {
                                orgValue = node.InnerText;
                            }

                            property.SetValue(standardData, orgValue);
                        }
                    }

                    if (string.Compare(standardData.Server, "MES") == 0)
                    {
                        if(string.Compare(standardData.MessageName, "ChangeEqpStatusReport") == 0)
                        {
                            XmlNode node = document.SelectSingleNode($"//CONTROLMODE");
                            if (node != null) standardData.Value += $"{node.InnerText} - ";
                            node = document.SelectSingleNode($"//CURRENTEQPSTATUS");
                            if (node != null) standardData.Value += $"{node.InnerText}";
                        }
                    }
                }

                #endregion ----------------------------------------------------

            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex);
            }

            return standardData;
        }


        protected object TID_Parser(StreamReader reader, ref string startLine)
        {
            string strLine = startLine;
            StandardData standardData = null;

            try
            {
                if (string.IsNullOrWhiteSpace(strLine)) return standardData;
                if (strLine.Length < this.LogDTime.Length) return standardData;
                string[] strValues = this.GetHeaderValues(strLine);
                if (strValues == null) return standardData;

                DateTime dtime = DateTime.MinValue;
                if (DateTime.TryParse(strValues[0], out dtime) == false) return standardData;

                standardData = new StandardData();
                standardData.LineNumber = this.LineNumber;
                standardData.DateTime = dtime;
                this.StandardCollection.Add(standardData);

                #region [ Header Line ] ---------------------------------------

                standardData.Server = $"TID";
                for (int index = 0; index < strValues.Length; index++)
                {
                    string strValue = strValues[index];
                    if (index == 0) { continue; }
                    if (index == 1) { standardData.Level = strValue; continue; }
                    if (index == 2) { standardData.Type = strValue; continue; }
                    if (index == 4) { standardData.TID = strValue; continue; }
                }

                #endregion ----------------------------------------------------

                #region [ Message Body ] --------------------------------------

                strLine = this.GetReadLine(reader);
                while (string.IsNullOrWhiteSpace(strLine) == false)
                {
                    if (this.IsEnd(strLine)) break;

                    standardData.Body.AppendLine(strLine);
                    strLine = this.GetReadLine(reader);
                }
                startLine = strLine;

                #endregion ----------------------------------------------------

            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex);
            }

            return standardData;
        }

        protected object TRANSACTIONID_Parser(StreamReader reader, ref string startLine)
        {
            string strLine = startLine;
            StandardData standardData = null;

            try
            {
                if (string.IsNullOrWhiteSpace(strLine)) return standardData;
                if (strLine.Length < this.LogDTime.Length) return standardData;
                string[] strValues = this.GetHeaderValues(strLine);
                if (strValues == null) return standardData;

                DateTime dtime = DateTime.MinValue;
                if (DateTime.TryParse(strValues[0], out dtime) == false) return standardData;

                standardData = new StandardData();
                standardData.LineNumber = this.LineNumber;
                standardData.DateTime = dtime;
                this.StandardCollection.Add(standardData);

                #region [ Header Line ] ---------------------------------------

                standardData.Level = $"INFO";
                standardData.Server = $"TID";
                standardData.Type = strValues[1];
                int nTID = strValues.Length - 1;
                standardData.TID = strValues[nTID];

                #endregion ----------------------------------------------------

                #region [ Message Body ] --------------------------------------

                strLine = this.GetReadLine(reader);
                while (string.IsNullOrWhiteSpace(strLine) == false)
                {
                    if (this.IsEnd(strLine)) break;

                    standardData.Body.AppendLine(strLine);
                    strLine = this.GetReadLine(reader);
                }
                startLine = strLine;

                #endregion ----------------------------------------------------

            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex);
            }

            return standardData;
        }

        protected object ERROR0_Parser(StreamReader reader, ref string startLine)
        {
            string strLine = startLine;
            StandardData standardData = null;

            try
            {
                if (string.IsNullOrWhiteSpace(strLine)) return standardData;
                if (strLine.Length < this.LogDTime.Length) return standardData;
                string[] strValues = this.GetHeaderValues(strLine);
                if (strValues == null) return standardData;

                DateTime dtime = DateTime.MinValue;
                if (DateTime.TryParse(strValues[0], out dtime) == false) return standardData;

                standardData = new StandardData();
                standardData.LineNumber = this.LineNumber;
                standardData.DateTime = dtime;
                this.StandardCollection.Add(standardData);

                #region [ Header Line ] ---------------------------------------

                int columnIndex = 1;
                for (int index = 0; index < strValues.Length; index++)
                {
                    string strValue = strValues[index];
                    if (index == 0) { continue; }
                    if (index == 1) { continue; }
                    if (index == 2) { standardData.Server = strValue; continue; }
                    if (index == 3) { standardData.Level = strValue; continue; }
                    if (index == 4) { standardData.Type += strValue; continue; }
                    if (index == 5) { standardData.Type += strValue; continue; }
                    if (index == 6) { standardData.Type += strValue; continue; }
                    if (index == 7) { continue; }
                    if (index == 8) { continue; }
                    if (index == 9) { continue; }
                    if (index == 10) { continue; }
                    if (index == 11) { continue; }
                    if (index == 12) { standardData.SystemByte = $"SystemByte[{strValue}]"; continue; }
                    if (index == 13) { standardData.MessageName = $"{strValue} {standardData.SystemByte}"; continue; }

                    string propertyName = $"Column{columnIndex}";
                    PropertyInfo property = typeof(StandardData).GetProperty(propertyName);
                    if (property != null) { property.SetValue(standardData, strValue); columnIndex++; continue; }
                }

                #endregion ----------------------------------------------------

                #region [ Message Body ] --------------------------------------

                strLine = this.GetReadLine(reader);
                while (string.IsNullOrWhiteSpace(strLine) == false)
                {
                    if (this.IsEnd(strLine)) break;

                    standardData.Body.AppendLine(strLine);
                    strLine = this.GetReadLine(reader);
                }
                startLine = strLine;

                #endregion ----------------------------------------------------

            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex);
            }

            return standardData;
        }

        protected object ERROR1_Parser(StreamReader reader, ref string startLine)
        {
            string strLine = startLine;
            StandardData standardData = null;

            try
            {
                if (string.IsNullOrWhiteSpace(strLine)) return standardData;
                if (strLine.Length < this.LogDTime.Length) return standardData;
                string[] strValues = this.GetHeaderValues(strLine);
                if (strValues == null) return standardData;

                DateTime dtime = DateTime.MinValue;
                if (DateTime.TryParse(strValues[0], out dtime) == false) return standardData;

                standardData = new StandardData();
                standardData.LineNumber = this.LineNumber;
                standardData.DateTime = dtime;
                this.StandardCollection.Add(standardData);

                #region [ Header Line ] ---------------------------------------

                int columnIndex = 1;
                standardData.Server = $"TID";
                for (int index = 0; index < strValues.Length; index++)
                {
                    string strValue = strValues[index];
                    if (index == 0) { continue; }
                    if (index == 1) { standardData.Level = strValue; continue; }
                    if (index == 2) { continue; }
                    if (index == 3) { standardData.Type = strValue; continue; }
                    if (index == 4) { continue; }
                    if (index == 5) { standardData.MessageName = strValue; continue; }
                    if (index == 6) { continue; }
                    if (index == 7) { standardData.TID = strValue.Replace("◀", ""); continue; }

                    string propertyName = $"Column{columnIndex}";
                    PropertyInfo property = typeof(StandardData).GetProperty(propertyName);
                    if (property != null) { property.SetValue(standardData, strValue); columnIndex++; continue; }
                }

                #endregion ----------------------------------------------------

                #region [ Message Body ] --------------------------------------

                strLine = this.GetReadLine(reader);
                while (string.IsNullOrWhiteSpace(strLine) == false)
                {
                    if (this.IsEnd(strLine)) break;

                    standardData.Body.AppendLine(strLine);
                    strLine = this.GetReadLine(reader);
                }
                startLine = strLine;

                #endregion ----------------------------------------------------

            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex);
            }

            return standardData;
        }

        protected object EXCEPTION_Parser(StreamReader reader, ref string startLine)
        {
            string strLine = startLine;
            StandardData standardData = null;

            try
            {
                if (string.IsNullOrWhiteSpace(strLine)) return standardData;
                if (strLine.Length < this.LogDTime.Length) return standardData;
                string[] strValues = this.GetHeaderValues(strLine);
                if (strValues == null) return standardData;

                DateTime dtime = DateTime.MinValue;
                if (DateTime.TryParse(strValues[0], out dtime) == false) return standardData;

                standardData = new StandardData();
                standardData.LineNumber = this.LineNumber;
                standardData.DateTime = dtime;
                standardData.Return = "1";
                this.StandardCollection.Add(standardData);

                #region [ Header Line ] ---------------------------------------

                for (int index = 0; index < strValues.Length; index++)
                {
                    string strValue = strValues[index];
                    if (index == 0) { continue; }
                    if (index == 1) { standardData.Level = strValue; continue; }
                    if (index == 2) { standardData.MessageName = strValue; continue; }
                }

                #endregion ----------------------------------------------------

                #region [ Message Body ] --------------------------------------

                strLine = this.GetReadLine(reader);
                while (string.IsNullOrWhiteSpace(strLine) == false)
                {
                    if (this.IsEnd(strLine)) break;

                    standardData.Body.AppendLine(strLine);
                    strLine = this.GetReadLine(reader);
                }
                startLine = strLine;

                #endregion ----------------------------------------------------

            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex);
            }

            return standardData;
        }

        protected object ETC_Parser(StreamReader reader, ref string startLine)
        {
            string strLine = startLine;
            StandardData standardData = null;

            try
            {
                if (string.IsNullOrWhiteSpace(strLine)) return standardData;
                if (strLine.Length < this.LogDTime.Length) return standardData;
                string[] strValues = this.GetHeaderValues(strLine);
                if (strValues == null) return standardData;

                DateTime dtime = DateTime.MinValue;
                if (DateTime.TryParse(strValues[0], out dtime) == false) return standardData;

                standardData = new StandardData();
                standardData.LineNumber = this.LineNumber;
                standardData.DateTime = dtime;
                this.StandardCollection.Add(standardData);

                #region [ Header Line ] ---------------------------------------

                int columnIndex = 1;
                for (int index = 0; index < strValues.Length; index++)
                {
                    string strValue = strValues[index];
                    if (index == 0) { continue; }
                    if (index == 1) { standardData.Level = strValue; continue; }
                    if (index == 2) { standardData.Server = strValue; continue; }
                    if (index == 3) { standardData.Service = strValue; continue; }
                    if (index == 4) { standardData.Type = strValue; continue; }

                    string propertyName = $"Column{columnIndex}";
                    PropertyInfo property = typeof(StandardData).GetProperty(propertyName);
                    if (property != null) { property.SetValue(standardData, strValue); columnIndex++; continue; }
                }

                #endregion ----------------------------------------------------

                #region [ Message Body ] --------------------------------------

                strLine = this.GetReadLine(reader);
                while (string.IsNullOrWhiteSpace(strLine) == false)
                {
                    if (this.IsEnd(strLine)) break;

                    standardData.Body.AppendLine(strLine);
                    strLine = this.GetReadLine(reader);
                }
                startLine = strLine;

                #endregion ----------------------------------------------------

            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex);
            }

            return standardData;
        }

        #endregion

    }

}
