//******************************************************************************//
// LogTemplate.cs
// 12/4/2023
//
// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION
// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS
// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO
// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO
// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS
// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS
// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON
// COMPANY.
//
// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT
//
// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY.
//
// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE
// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED
// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION
// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION
// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER
// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER
// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS
// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT
// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL
// PENALTIES.
//
// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 :
// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R,
// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS
// DESTROY BY ANY  METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR
// RECONSTRUCTION OF THE DOCUMENT.
// POC: Alex Kravchenko (1118268)
//******************************************************************************//
using GalaSoft.MvvmLight.Messaging;
using Raytheon.LogDashboard.Helpers;
using Raytheon.LogDashboard.ViewModel;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows;

namespace Raytheon.LogDashboard.Model
{
    public enum LogFileType
    {
        Undefined,
        Log4j,
        CSV,
        EPTS,
        ErrorLogger
    }

    public class LogTemplate
    {
        public Dictionary<ImportTemplateParameters, int> TemplateParameters { get; } = new Dictionary<ImportTemplateParameters, int>();

        public string Separator { get; set; } = ";";

        public string Encoding { get; set; } = "UTF-8";

        public LogFileType LogFileType { get; set; }

        /// <summary>
        /// trying to detect template
        /// </summary>
        /// <param name="firstMessage"></param>
        /// <returns></returns>
        public bool TryGetLogTemplateByAutoDetect(string firstMessage)
        {
            if(string.IsNullOrWhiteSpace(firstMessage))
            {
                Messenger.Default.Send("An error occurred while trying to automatically match the message template.\nFirst Message is Empty", "DisplayCustomMessage");
                return false;
            }

            if(TryDetectTemplate(firstMessage) == LogFileType.Undefined)
            {
                Messenger.Default.Send("An error occurred while trying to automatically match the message template.\nLog file type is undefined", "DisplayCustomMessage");
                return false;
            }
            return true;
        }

        /// <summary>
        /// trying to detect template
        /// </summary>
        /// <param name="log"></param>
        /// <returns></returns>
        public LogFileType TryDetectTemplate(string log)
        {
            LogFileType = LogFileType.Undefined;

            if(log.StartsWith("<log4j"))
            {
                LogFileType = LogFileType.Log4j;
            }
            else if(log.ContainsAnyOfPattern(new string[] { "^-----", "^\\d{4}-\\d{2}-\\d{2}\\s\\d{2}:\\d{2}:\\d{2},\\d{3}" }))
            {
                LogFileType = LogFileType.EPTS;
            }
            else if(log.ContainsAnyOfPattern(new string[] {"^\\d{10}\\.\\d{3}"}))
            {
                LogFileType = LogFileType.ErrorLogger;
            }
            else
            {
                string[] logSplit = log.Split(';');
                if(logSplit.Length < 4)
                {
                    logSplit = log.Split('|');
                    Separator = "|";
                    if(logSplit.Length < 3)
                    {
                        logSplit = log.Split(',');
                        Separator = ",";
                    }
                }

                ImportTemplateParameters dataParameter = ImportTemplateParameters.date;

                int dateTimeIndex = GetDateTimeIndex(logSplit, ref dataParameter);
                if(dateTimeIndex == -1)
                {
                    return LogFileType.Undefined;
                }

                var intIndexes = GetIntIndexes(logSplit);
                int logLevelIndex = GetLogLevelIndex(logSplit);
                if(dateTimeIndex == -1)
                {
                    return LogFileType.Undefined;
                }

                List<int> otherIndexes = new List<int>();

                for(int i = 0; i < logSplit.Length; i++)
                {

                    if(i == dateTimeIndex || i == logLevelIndex || intIndexes.Contains(i))
                    {
                        continue;
                    }

                    if(!string.IsNullOrEmpty(logSplit[i]))
                    {
                        otherIndexes.Add(i);
                    }
                }

                if(otherIndexes.Count > 1)
                {
                    TemplateParameters.Add(ImportTemplateParameters.logger, otherIndexes.First());
                }

                TemplateParameters.Add(dataParameter, dateTimeIndex);
                TemplateParameters.Add(ImportTemplateParameters.level, logLevelIndex);

                TemplateParameters.Add(ImportTemplateParameters.message, otherIndexes.Last());

                if(intIndexes.Count > 0)
                {
                    TemplateParameters.Add(ImportTemplateParameters.threadid, intIndexes.Last());
                }

                LogFileType = LogFileType.CSV;

            }

            return LogFileType;
        }

        private int GetDateTimeIndex(string[] logSplit, ref ImportTemplateParameters dateTemplateParameter)
        {
            int index = -1;
            for(int i = 0; i < logSplit.Length; i++)
            {
                string columnString = logSplit[i].Trim();

                if(DateTime.TryParse(columnString, out DateTime date))
                {
                    return i;
                }

                if(DateTime.TryParseExact(columnString, "MM-dd-y HH:mm:ss.ffff", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime dt))
                {
                    dateTemplateParameter = ImportTemplateParameters.eptstime;
                    return i;
                }
                // legacy Error Logger format
                if(DateTime.TryParseExact(columnString, "ddd MMM dd HH:mm:ss yyyy fff\\m\\s", null, DateTimeStyles.None, out dt))
                {
                    dateTemplateParameter = ImportTemplateParameters.errorloggertime;
                    return i;
                }

                // TODO AK
                if(long.TryParse(columnString, out long tickDateTime))
                {
                    DateTime dateFromTicks = new DateTime(tickDateTime);
                    dateTemplateParameter = ImportTemplateParameters.ticks;
                    return i;
                }
            }
            return index;
        }

        private List<int> GetIntIndexes(string[] logSplit)
        {
            List<int> indexes = new List<int>();
            for(int i = 0; i < logSplit.Length; i++)
            {               
                if(logSplit[i].IsNumeric())
                {
                    indexes.Add(i);
                }
            }
            return indexes;
        }

        private int GetLogLevelIndex(string[] logSplit)
        {
            int index = -1;
            for(int i = 0; i < logSplit.Length; i++)
            {
                string line = logSplit[i]?.Trim();
                if(LogDashboardViewModel.LogTypeArray.Contains(line))
                {
                    return i;
                }
            }
            return index;
        }
    }
}
