using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using DDUtilityApp.LOGPARSER.DATA;
using DDUtilityApp.SECS;
using JWH;
using JWH.CONTROL;
using Telerik.WinControls.UI;

namespace DDUtilityApp.LOGPARSER.PARSER
{

    public class AgvParser : LogParser
    {

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

        public List<string> UndefinedParser { get; set; } = new List<string>();

        protected List<KeyValuePair<string, string>> DefaultKeyMapping { get; set; } = new List<KeyValuePair<string, string>>();

        #endregion

        #region [ AgvParser ] -------------------------------------------------

        public AgvParser()
        {
            this.Text = $"[EverOne] MIS Log Viewer";
            this.LogDTime = "[yyyy-MM-dd HH:mm:ss.fff]";
            this.DefaultKeyMapping.Add(new KeyValuePair<string, string>("LOGACTION", "Type"));
            this.DefaultKeyMapping.Add(new KeyValuePair<string, string>("EVENTNAME", "MessageName"));
            this.DefaultKeyMapping.Add(new KeyValuePair<string, string>("MESSAGENAME", "MessageName"));
            this.DefaultKeyMapping.Add(new KeyValuePair<string, string>("CEID", "Value"));
            this.DefaultKeyMapping.Add(new KeyValuePair<string, string>("EQPNAME", "EquipmentID"));
            this.DefaultKeyMapping.Add(new KeyValuePair<string, string>("VEHICLEID", "PortID"));
            this.DefaultKeyMapping.Add(new KeyValuePair<string, string>("CARRIERID", "CarrierID"));
            this.DefaultKeyMapping.Add(new KeyValuePair<string, string>("LOTID", "LotID"));
            this.DefaultKeyMapping.Add(new KeyValuePair<string, string>("SOURCEPORT", "HostPanelID"));
            this.DefaultKeyMapping.Add(new KeyValuePair<string, string>("SOURCE", "HostPanelID"));
            this.DefaultKeyMapping.Add(new KeyValuePair<string, string>("DESTPORT", "PanelID"));
            this.DefaultKeyMapping.Add(new KeyValuePair<string, string>("DEST", "PanelID"));
            this.DefaultKeyMapping.Add(new KeyValuePair<string, string>("TRANSACTIONID", "TID"));
            this.DefaultKeyMapping.Add(new KeyValuePair<string, string>("TID", "TID"));
            this.DefaultKeyMapping.Add(new KeyValuePair<string, string>("SYSTEMID", "SystemByte"));
            this.DefaultKeyMapping.Add(new KeyValuePair<string, string>("COMMANDID", "Column1"));
            this.DefaultKeyMapping.Add(new KeyValuePair<string, string>("WAYPOINT", "Column2"));
        }

        public AgvParser(params string[] files) : base(files)
        {
        }

        #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);
                                standardData.Column4 = parser.Method.Name;
                                if (standardData.Body != null) standardData.Body.Clear();
                            }
                        }
                    }
                    catch (Exception ex01)
                    {
                        XLogger.Instance.Fatal(ex01);
                    }

                    if (reader != null) reader.Close();
                }

                foreach (string undefinedParser in this.UndefinedParser)
                    XLogger.Instance.Warn(undefinedParser);
            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex);
                return false;
            }

            return true;
        }

        public DataTable AgvHeader = null;

        protected Parser GetParser(string strLine)
        {
            Parser parser = null;
            try
            {
                if (string.IsNullOrWhiteSpace(strLine)) return parser;
                if (strLine.Length < this.LogDTime.Length) return parser;

                DateTime dtime = DateTime.MinValue;
                string strDTime = strLine.Substring(0, this.LogDTime.Length);
                if (DateTime.TryParse(strDTime.Substring(1, this.LogDTime.Length - 2), out dtime) == false) return parser;

                string[] strValues = strLine.ToUpper().Substring(this.LogDTime.Length).Split(new string[] { ":", "|", " ", "[", "]", "(", ")" }, StringSplitOptions.RemoveEmptyEntries);
                if (strValues.Length < 3) return parser;

                if(strValues[2].Trim().StartsWith("C.T.W.M")) parser = this.InLine_Parser;
                if (parser != null) return parser;

                switch (strValues[2].Trim())
                {
                    case "C.T.E.C.S.SECSCHANNEL":
                        parser = this.SECSChannel_Parser; break;
                    case "C.T.E.C.A.L.ACSLISTENER":
                    case "C.T.E.C.A.S.ACSWRITER":
                    case "C.T.E.C.L.L.LCSLISTENER":
                    case "C.T.E.C.L.S.LCSWRITER":
                    case "C.T.E.C.S.S.SCSWRITER":
                        parser = this.AcsLcsScs_Parser; break;
                    case "C.T.E.H.M.L.MCS2ACSLISTENER":
                    case "C.T.E.H.M.L.MCS2LCSLISTENER":
                    case "C.T.E.H.M.L.MCS2SCSLISTENER":
                        parser = this.MCS2_Parser; break;
                    case "C.T.E.H.M.L.SERVICEMESSAGELISTENERMCS2MIS":
                    case "C.T.M.R.PRODUCER":
                    case "C.T.S.C.W.SERVICEWORKERBASE":
                    case "C.T.S.C.M.SERVICEMESSAGELISTENER4MIS":
                    case "C.T.S.C.M.SERVICEMESSAGELISTENER4UI":
                    case "C.T.S.M.SERVICEMESSAGEFACTORY":
                    case "C.T.S.W.SERVICEWORKERFACTORY":
                    case "C.T.S.W.SERVICEWORKERWITHOUTEVENTLOGWRITER":
                        parser = this.Service_Parser; break;
                    case "C.T.S.C.M.SERVICEMESSAGELISTENER4RTD":
                    case "C.T.S.M.F.I.STATESERVICEFACTORYIMPL":
                    case "C.T.S.M.F.I.EQUIPMENTSERVICEFACTORYIMPL":
                    case "C.T.S.M.F.I.CARRIERSERVICEFACTORYIMPL":
                    case "C.T.S.M.F.I.ROUTESERVICEFACTORYIMPL":
                    case "C.T.S.M.F.I.TRANSPORTSERVICEFACTORYIMPL":
                    case "C.T.S.M.I.TMSCUSTOMSERVICEIMPL":
                    case "C.T.W.M.A.VEHICLEMOVING":
                    case "C.T.W.M.S.CARRIERREMOVED":
                        parser = this.InLine_Parser; break;
                    case "K.F.H.HSMSMANAGER":
                    case "K.F.S.J.TIMERTEMPLATE":
                    case "K.F.U.ASSERT":
                    case "O.S.W.S.C.WEBSOCKETMESSAGEBROKERSTATS":
                        parser = this.Header_Parser; break;
                    default:
                        if (this.UndefinedParser.Contains(strValues[2].Trim()) == false)
                            this.UndefinedParser.Add(strValues[2].Trim());
                        parser = this.Header_Parser; break;
                }
            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex);
                return parser;
            }

            return parser;
        }

        private bool IsEnd(string strLine)
        {
            try
            {
                string strDTime = string.Empty;
                DateTime dtime = DateTime.Now;
                if (strLine.Length > this.LogDTime.Length)
                {
                    strDTime = strLine.Substring(0, this.LogDTime.Length);
                    if (DateTime.TryParse(strDTime.Substring(1, this.LogDTime.Length - 2), out dtime) == true) return true;
                }
            }
            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);

                SECSLib.ItemType valueType = SECSLib.ItemType.None;
                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;
                        valueType = SECSLib.ItemType.None;
                    }
                    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;

                        strValue = this.GetString(reader, ' ');
                        if (SECSLib.ItemFormat.Keys.Contains(strValue))
                        {
                            item.Format = strValue;
                            strValue = string.Empty;
                            if (SECSLib.ItemFormat[item.Format] == typeof(IList)) parent = item;

                            valueType = SECSLib.ItemType.Length;    // Next Item is Length
                        }
                    }
                    else if (chValue == '[')
                    {
                        strValue = this.GetString(reader, ']').Replace("V", "");
                        item.Length = Convert.ToInt16(strValue);

                        strValue = string.Empty;
                        valueType = SECSLib.ItemType.None;
                    }
                    else if (chValue == '\'')
                    {
                        strValue = this.GetString(reader, '\'');
                        item.Value = strValue;

                        strValue = string.Empty;
                        valueType = SECSLib.ItemType.None;
                    }
                    else
                    {
                        switch (valueType)
                        {
                            case SECSLib.ItemType.Length:
                                {
                                    strValue = chValue + this.GetString(reader, new char[] { ' ', '>' }).Replace("V", "");
                                    item.Length = Convert.ToInt16(strValue);
                                    strValue = string.Empty;
                                    valueType = SECSLib.ItemType.Name;
                                }
                                break;
                            case SECSLib.ItemType.Name:
                                {
                                    strValue = chValue + this.GetString(reader, new char[] { ' ', '>' });
                                    item.Name = strValue;
                                    strValue = string.Empty;
                                    valueType = SECSLib.ItemType.None;
                                }
                                break;
                            default:
                                break;
                        }
                    }
                }

                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(ex);
                return null;
            }
        }

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

            return sbValue.ToString();
        }

        public override void SetGridHeader(GridViewEx grid)
        {
            Dictionary<string, string> dicColumns = new Dictionary<string, string>();
            dicColumns.Add("DateTime", "");
            dicColumns.Add("Level", "");
            dicColumns.Add("Server", "");
            dicColumns.Add("Service", "");
            dicColumns.Add("Type", "");
            dicColumns.Add("MessageName", "");
            dicColumns.Add("Return", "");
            dicColumns.Add("Value", "");
            dicColumns.Add("EquipmentID", "");
            dicColumns.Add("PortID", "VEHICLEID");
            dicColumns.Add("CarrierID", "");
            dicColumns.Add("LotID", "");
            dicColumns.Add("HostPanelID", "SourcePort");
            dicColumns.Add("PanelID", "DestPort");
            dicColumns.Add("PanelQty", "");
            dicColumns.Add("TID", "");
            dicColumns.Add("SystemByte", "");
            dicColumns.Add("Column1", "CommandID");
            dicColumns.Add("Column2", "WayPoint");
            dicColumns.Add("Column3", "");
            dicColumns.Add("Column4", "");
            dicColumns.Add("Column5", "");

            string columnNames = GlobalVariable.Instance.AgvParser_GridHeader;
            if (string.IsNullOrEmpty(columnNames))
            {
                StringBuilder sb = new StringBuilder();
                foreach (KeyValuePair<string, string> pair in dicColumns)
                    if (new string[] { "" }.Contains(pair.Key) == false) sb.Append($"{pair.Key};");
                columnNames = sb.ToString();
            }

            string columnText = string.Empty;
            foreach (string columnName in columnNames.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries))
            {
                columnText = columnName;
                if (dicColumns.ContainsKey(columnName))
                {
                    if (string.IsNullOrEmpty(dicColumns[columnName]) == false) columnText = dicColumns[columnName];
                    dicColumns.Remove(columnName);
                }
                grid.AddColumn(columnName, columnText);
            }

            foreach (string columnName in dicColumns.Keys)
            {
                columnText = columnName;
                if (string.IsNullOrEmpty(dicColumns[columnName]) == false) columnText = dicColumns[columnName];
                grid.AddColumn(columnName, columnText).IsVisible = false;
            }
        }

        public override void SaveGridHeader(GridViewEx grid)
        {
            StringBuilder sb = new StringBuilder();
            foreach (GridViewColumn column in grid.Columns.OrderBy(x => x.Index))
                if (column.IsVisible) sb.AppendFormat($"{column.Name};");
            GlobalVariable.Instance.AgvParser_GridHeader = sb.ToString();
            GlobalVariable.Instance.SaveSetting();
        }

        #endregion


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

        protected object SECSChannel_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;

                DateTime dtime = DateTime.MinValue;
                string strDTime = strLine.Substring(0, this.LogDTime.Length);
                if (DateTime.TryParse(strDTime.Substring(1, this.LogDTime.Length - 2), out dtime) == false) return standardData;

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

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

                string[] strValues = strLine.ToUpper().Substring(this.LogDTime.Length).Split(new string[] { ":", "|", " ", "[", "]", "(", ")" }, StringSplitOptions.RemoveEmptyEntries);
                int indexSystemByte = strValues.Length - 2;
                for (int index = 0; index < strValues.Length; index++)
                {
                    string strValue = strValues[index];
                    if (index == 0) { standardData.Level = strValue; continue; }
                    if (index == 1) { standardData.Server = strValue; continue; }
                    if (index == 2) { standardData.Service = strValue; continue; }
                    if (index == 3) { standardData.Type = strValue; continue; }
                    if (index == 7) { standardData.Value = strValue; continue; }
                    if (index == 8) { standardData.MessageName = strValue; continue; }
                    if (index == 14) standardData.Column1 = "LINKTEST";
                    if (index == indexSystemByte) { standardData.SystemByte = $"SystemByte[{strValue}]"; continue; }
                }

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

                #region [ SECS 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 ----------------------------------------------------

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

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

                SECSItem secsItem = null;
                SECSItem[] secsItems = null;

                if (rootSECS != null)
                {

                    #region [ SetItemValue : SVID ]

                    // EQPNAME = EquipmentID
                    secsItem = rootSECS.GetItemByName("EQPNAME").FirstOrDefault();
                    if (secsItem != null) standardData.EquipmentID = secsItem.Value;

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

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

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

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

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

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

                    #endregion

                    #region [ SetItemValue : SxFx ]

                    // GetData S5F1
                    if (rootSECS.Stream == "5" && rootSECS.Function == "1")
                    {
                        // ALTX
                        secsItem = rootSECS.GetItemByName("ALTX").FirstOrDefault();
                        if (secsItem != null) standardData.Value += $"='{secsItem.Value}'";
                    }

                    // GetData S6F11
                    if (rootSECS.Stream == "6" && rootSECS.Function == "11")
                    {
                        // CEID
                        secsItem = rootSECS.GetItemByName("CEID").FirstOrDefault();
                        if (secsItem == null) secsItem = rootSECS[1];
                        standardData.Value = $"CEID: {secsItem.Value} " + standardData.Value;
                    }

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

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

                    // 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;
                    }

                    // GetData S7F25
                    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}";
                    }

                    #endregion

                }

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

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

            return standardData;
        }

        protected object AcsLcsScs_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;

                DateTime dtime = DateTime.MinValue;
                string strDTime = strLine.Substring(0, this.LogDTime.Length);
                if (DateTime.TryParse(strDTime.Substring(1, this.LogDTime.Length - 2), out dtime) == false) return standardData;

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

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

                string[] strValues = strLine.ToUpper().Substring(this.LogDTime.Length).Split(new string[] { ":", "|", " ", "[", "]", "(", ")" }, StringSplitOptions.RemoveEmptyEntries);
                int indexSystemByte = strValues.Length - 2;
                for (int index = 0; index < strValues.Length; index++)
                {
                    string strValue = strValues[index];
                    if (index == 0) { standardData.Level = strValue; continue; }
                    if (index == 1) { standardData.Server = strValue; continue; }
                    if (index == 2) { standardData.Service = strValue; continue; }
                    if (index == 3) { standardData.Type = strValue; continue; }
                    if (index == 6) { standardData.MessageName = strValue; continue; }
                    if (index == 9) { standardData.Value = strValue; continue; }
                    if (index == 14) standardData.Column1 = "LINKTEST";
                    if (index == indexSystemByte) { standardData.SystemByte = $"SystemByte[{strValue}]"; continue; }
                }

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

                #region [ SECS 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 ----------------------------------------------------

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

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

                SECSItem secsItem = null;
                SECSItem[] secsItems = null;
                if (rootSECS != null)
                {

                    #region [ SetItemValue : SVID ]

                    // EQPNAME = EquipmentID
                    secsItem = rootSECS.GetItemByName("EQPNAME").FirstOrDefault();
                    if (secsItem != null) standardData.EquipmentID = secsItem.Value;

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

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

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

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

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

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

                    #endregion

                    #region [ SetItemValue : SxFx ]

                    // GetData S5F1
                    if (rootSECS.Stream == "5" && rootSECS.Function == "1")
                    {
                        // ALTX
                        secsItem = rootSECS.GetItemByName("ALTX").FirstOrDefault();
                        if (secsItem != null) standardData.Value += $"='{secsItem.Value}'";
                    }

                    // GetData S6F11
                    if (rootSECS.Stream == "6" && rootSECS.Function == "11")
                    {
                        // CEID
                        secsItem = rootSECS.GetItemByName("CEID").FirstOrDefault();
                        if (secsItem == null) secsItem = rootSECS[1];
                        standardData.Value = $"CEID: {secsItem.Value} " + standardData.Value;
                    }

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

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

                    // 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;
                    }

                    // GetData S7F25
                    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}";
                    }

                    #endregion

                }

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

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

            return standardData;
        }

        protected object Service_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;

                DateTime dtime = DateTime.MinValue;
                string strDTime = strLine.Substring(0, this.LogDTime.Length);
                if (DateTime.TryParse(strDTime.Substring(1, this.LogDTime.Length - 2), 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 ] ---------------------------------------

                string[] strValues = strLine.ToUpper().Substring(this.LogDTime.Length).Split(new string[] { ":", "|", " ", "[", "]", "(", ")" }, StringSplitOptions.RemoveEmptyEntries);
                for (int index = 0; index < strValues.Length; index++)
                {
                    string strValue = strValues[index];
                    if (index == 0) { standardData.Level = strValue; continue; }
                    if (index == 1) { standardData.Server = strValue; continue; }
                    if (index == 2) { standardData.Service = strValue; continue; }
                }

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

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

                Dictionary<string, string> dicBody = new Dictionary<string, string>();

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

                    string[] arrBody = strLine.Split(new string[] { "=" }, StringSplitOptions.RemoveEmptyEntries);
                    if (arrBody.Length == 2) dicBody.Add(arrBody[0].Trim().ToUpper(), arrBody[1].Trim());

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

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

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

                string strMessageKey = string.Empty;
                foreach (string key in new string[] { "MESSAGETEXT", "MESSAGESTRING" })
                    if (dicBody.ContainsKey(key)) { strMessageKey = key; break; }

                if (dicBody.ContainsKey(strMessageKey))
                {
                    string strMessage = dicBody[strMessageKey];
                    int startIndex = 0;
                    startIndex = strMessage.IndexOf("\":\"", startIndex);
                    while (startIndex >= 0)
                    {
                        int beginIndex = strMessage.Substring(0, startIndex).LastIndexOf("\"");
                        int endIndex = strMessage.IndexOf("\"", startIndex + 3);
                        string strKeyValue = strMessage.Substring(beginIndex, endIndex - beginIndex + 1);
                        string[] arrKeyValue = strKeyValue.Replace("\"", "").Split(':');
                        if (arrKeyValue.Length == 2)
                        {
                            string strKey = arrKeyValue[0].Trim().ToUpper();
                            if (dicBody.ContainsKey(strKey) == false) dicBody.Add(strKey, arrKeyValue[1].Trim());
                        }

                        startIndex = strMessage.IndexOf("\":\"", endIndex);
                    }
                }

                //foreach (KeyValuePair<string, string> pair in dicBody)
                //    XLogger.Instance.Debug(pair);

                List<KeyValuePair<string, string>> keyMapping = new List<KeyValuePair<string, string>>();
                keyMapping.AddRange(this.DefaultKeyMapping);

                foreach (KeyValuePair<string, string> pair in keyMapping)
                {
                    if (dicBody.ContainsKey(pair.Key) == false) continue;

                    PropertyInfo property = type.GetProperty(pair.Value);
                    if (property != null) property.SetValue(standardData, dicBody[pair.Key]);
                }

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

            }
            catch (Exception ex)

            {
                XLogger.Instance.Fatal(ex);
            }

            return standardData;
        }

        protected object MCS2_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;

                DateTime dtime = DateTime.MinValue;
                string strDTime = strLine.Substring(0, this.LogDTime.Length);
                if (DateTime.TryParse(strDTime.Substring(1, this.LogDTime.Length - 2), 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 ] ---------------------------------------

                string[] strValues = strLine.ToUpper().Substring(this.LogDTime.Length).Split(new string[] { ":", "|", " ", "[", "]", "(", ")" }, StringSplitOptions.RemoveEmptyEntries);
                for (int index = 0; index < strValues.Length; index++)
                {
                    string strValue = strValues[index];
                    if (index == 0) { standardData.Level = strValue; continue; }
                    if (index == 1) { standardData.Server = strValue; continue; }
                    if (index == 2) { standardData.Service = strValue; continue; }
                }

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

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

                Dictionary<string, string> dicBody = new Dictionary<string, string>();

                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 ----------------------------------------------------

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

                string strMessage = standardData.Body.ToString();
                int startIndex = 0;
                startIndex = strMessage.IndexOf("\" : \"", startIndex);
                while (startIndex >= 0)
                {
                    int beginIndex = strMessage.Substring(0, startIndex).LastIndexOf("\"");
                    int endIndex = strMessage.IndexOf("\"", startIndex + 5);
                    string strKeyValue = strMessage.Substring(beginIndex, endIndex - beginIndex + 1);
                    string[] arrKeyValue = strKeyValue.Replace("\"", "").Split(':');
                    if (arrKeyValue.Length == 2)
                    {
                        string strKey = arrKeyValue[0].Trim().ToUpper();
                        if (dicBody.ContainsKey(strKey) == false) dicBody.Add(strKey, arrKeyValue[1].Trim());
                    }

                    startIndex = strMessage.IndexOf("\" : \"", endIndex);
                }

                //foreach (KeyValuePair<string, string> pair in dicBody)
                //    XLogger.Instance.Debug(pair);

                List<KeyValuePair<string, string>> keyMapping = new List<KeyValuePair<string, string>>();
                keyMapping.AddRange(this.DefaultKeyMapping);

                foreach (KeyValuePair<string, string> pair in keyMapping)
                {
                    if (dicBody.ContainsKey(pair.Key) == false) continue;

                    PropertyInfo property = type.GetProperty(pair.Value);
                    if (property != null) property.SetValue(standardData, dicBody[pair.Key]);
                }

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

            }
            catch (Exception ex)

            {
                XLogger.Instance.Fatal(ex);
            }

            return standardData;
        }

        protected object InLine_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;

                DateTime dtime = DateTime.MinValue;
                string strDTime = strLine.Substring(0, this.LogDTime.Length);
                if (DateTime.TryParse(strDTime.Substring(1, this.LogDTime.Length - 2), 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 ] ---------------------------------------

                string[] strValues = strLine.ToUpper().Substring(this.LogDTime.Length).Split(new string[] { ":", "|", " ", "[", "]", "(", ")" }, StringSplitOptions.RemoveEmptyEntries);
                for (int index = 0; index < strValues.Length; index++)
                {
                    string strValue = strValues[index];
                    if (index == 0) { standardData.Level = strValue; continue; }
                    if (index == 1) { standardData.Server = strValue; continue; }
                    if (index == 2) { standardData.Service = strValue; continue; }
                }

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

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

                Dictionary<string, string> dicBody = new Dictionary<string, string>();

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

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

                for (int i = 3; i < strValues.Length; i++)
                {
                    string[] arrKeyValue = strValues[i].Split(new string[] { "=" }, StringSplitOptions.RemoveEmptyEntries);
                    if (arrKeyValue.Length != 2) continue;

                    string strKey = arrKeyValue[0].Trim().ToUpper();
                    if (dicBody.ContainsKey(strKey) == false) dicBody.Add(strKey, arrKeyValue[1].Trim());
                }

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

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

                //foreach (KeyValuePair<string, string> pair in dicBody)
                //    XLogger.Instance.Debug(pair);

                List<KeyValuePair<string, string>> keyMapping = new List<KeyValuePair<string, string>>();
                keyMapping.AddRange(this.DefaultKeyMapping);

                foreach (KeyValuePair<string, string> pair in keyMapping)
                {
                    if (dicBody.ContainsKey(pair.Key) == false) continue;

                    PropertyInfo property = type.GetProperty(pair.Value);
                    if (property != null) property.SetValue(standardData, dicBody[pair.Key]);
                }

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

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

            return standardData;
        }

        protected object Header_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;

                DateTime dtime = DateTime.MinValue;
                string strDTime = strLine.Substring(0, this.LogDTime.Length);
                if (DateTime.TryParse(strDTime.Substring(1, this.LogDTime.Length - 2), out dtime) == false) return standardData;

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

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

                string[] strValues = strLine.ToUpper().Substring(this.LogDTime.Length).Split(new string[] { ":", "|", " ", "[", "]", "(", ")" }, StringSplitOptions.RemoveEmptyEntries);
                for (int index = 0; index < strValues.Length; index++)
                {
                    string strValue = strValues[index];
                    if (index == 0) { standardData.Level = strValue; continue; }
                    if (index == 1) { standardData.Server = strValue; continue; }
                    if (index == 2) { standardData.Service = strValue; continue; }
                }

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

                #region [ 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

    }

}