//******************************************************************************//
// WCFPacketsParser.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 Raytheon.LogDashboard.Model;
using System;
using System.Net.Sockets;
using Raytheon.LogDashboard.Service;
using GalaSoft.MvvmLight.Messaging;
using System.Collections.Generic;
using NLog;
using System.Linq;

namespace Raytheon.LogDashboard.Parsers
{
    public class WCFPacketsParser : PacketsParser
    {
        private ITRSInfoServiceHost _serviceHost;
        private readonly Queue<LogMessage> _messages = new Queue<LogMessage>();

        public WCFPacketsParser(string name, bool isAutoSave)
            : base(name, isAutoSave)
        {
        }
        public WCFPacketsParser(string name, string address, bool isAutoSave)
            : this(name, isAutoSave)
        {
            Address = address;
        }

        /// <summary>
        /// initialize WCF packet receiver / parser
        /// </summary>
        /// <returns></returns>
        public override bool Init()
        {
            try
            {
                base.Init();

                if(!string.IsNullOrEmpty(Address))
                {
                    _serviceHost = new TRSInfoServiceHost();
                    _serviceHost.StartHost(Address);
                }

                Messenger.Default.Register<NotificationMessage<LogMessage>>(this, "WCFMessage", MessageReceivedHandler);
                Messenger.Default.Register<LogEventInfo>(this, "AddProcessingText", AddProcessingTextHandler);

                IsInitialized = true;
                return IsInitialized;
            }
            catch(SocketException socketException)
            {
                Logger.Warn(socketException, "An error occurred in WCFPacketsParser initializer.");
                IsInitialized = false;
                return IsInitialized;
            }
            catch(Exception e)
            {
                Logger.Warn(e, "An error occurred in WCFPacketsParser initializer.");
                IsInitialized = false;
                return IsInitialized;
            }
        }

        private void AddProcessingTextHandler(LogEventInfo info)
        {
            var threadIdProperty = info.Properties.FirstOrDefault(p => p.Key.ToString() == "ThreadId");
            int threadId = threadIdProperty.Key != null ? (int)threadIdProperty.Value : 0;

            LogMessage logMessage = new LogMessage
            {
                Logger = info.LoggerName,
                ThreadName = info.LoggerName,
                Address = string.IsNullOrEmpty(Address) ? Environment.MachineName : Address,
                Message = info.Message,
                Time = info.TimeStamp,
                Thread = threadId,
                Level = FromNLogLevelToDashboardLevel(info.Level.ToString()),
                ExecutableName = "LogDashboard"
            };
            _messages.Enqueue(logMessage);
        }

        public static DashboardLogLevel FromNLogLevelToDashboardLevel(string level)
        {
            switch(level.ToUpper())
            {
                case "INFOPOPUP":
                case "INFO":
                    return Model.DashboardLogLevel.Info;
                case "DEBUGPOPUP":
                case "DEBUG":
                    return Model.DashboardLogLevel.Debug;
                case "TRACE":
                    return Model.DashboardLogLevel.Trace;
                case "ERROR":
                    return Model.DashboardLogLevel.Error;
                case "WARN":
                    return Model.DashboardLogLevel.Warn;
                case "FATAL":
                case "CRITICAL":
                    return Model.DashboardLogLevel.Fatal;
                default:
                    return Model.DashboardLogLevel.Error;
            }
        }

        private void MessageReceivedHandler(NotificationMessage<LogMessage> message)
        {
            LogMessage logMessage = message?.Content;
            if(logMessage == null)
            {
                return;
            }
            logMessage.Address = Address;
            _messages.Enqueue(logMessage);
        }

        public override LogMessage GetLog()
        {
            var log = _messages.Count > 0 ? _messages.Dequeue() : null;

            if(IsAutoSave && log != null)
            {
                Messenger.Default.Send(log, "PersistLogMessage");
            }

            return log;
        }

        public override void Dispose()
        {
            base.Dispose();
            _serviceHost?.StopHost();

            Messenger.Default.Unregister<NotificationMessage<LogMessage>>(this, "WCFMessage", MessageReceivedHandler);
            Messenger.Default.Unregister<LogEventInfo>(this, "AddProcessingText", AddProcessingTextHandler);
        }

    }
}
