//******************************************************************************//
// Receiver.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;
using Raytheon.LogDashboard.Helpers;
using Raytheon.LogDashboard.Parsers;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.Serialization;
using System.Windows.Media;
using System.Xml.Serialization;

namespace Raytheon.LogDashboard.Model
{
    public enum ReceiverType
    {
        [Description("UDP")]
        UDP,
        [Description("WCF Named Pipes")]
        WCF,
        [Description("Error Logger")]
        ErrorLogger,
        [Description("Windows Debug")]
        WinDebug
    }

    public enum ErrorLoggerType
    {
        [Description("32 Bit Logger")]
        BIT_32,
        [Description("64 Bit Logger")]
        BIT_64
    }

    [Serializable]
    [DataContract]
    public class Receiver : ViewModelBase, ICloneable, IDisposable
    {
        [NonSerialized]
        private SolidColorBrush color = new SolidColorBrush(Colors.White);
        [DataMember(Name = "ColorString")]
        private string colorString;
        private int port = 0;
        private bool isActive = true;
        private string encoding = "UTF-8";
        private IEnumerable<string> receiverNames { get; set; }
        
        public PacketsParser Parser { get; set; }

        public Receiver(string name, string address, ReceiverType type, IEnumerable<string> receiverNames)
        {
            Parser = null;
            this.receiverNames = receiverNames;
            Name = GetUniqueName(name, 0);
            Address = address;
            ReceiverType = type;
            ColorString = "#FFFFFFFF";
        }

        public Receiver(ReceiverSetting receiverSetting)
        {
            Name = receiverSetting.Name;
            ReceiverType = receiverSetting.ReceiverType;
            Address = receiverSetting.Address;
            Parser = null;
            Port = receiverSetting.Port;
            IsActive = receiverSetting.IsActive;
            Encoding = receiverSetting.Encoding;
            ColorString = receiverSetting.ColorString;
            IsAddressVisible = receiverSetting.IsAddressVisible;
            IsPortVisible = receiverSetting.IsPortVisible;
            IsHidden = receiverSetting.IsHidden;
            IsAutoSave = receiverSetting.IsAutoSave;
        }

        /// <summary>
        /// sets the parser type plus sets port number for UDP parser
        /// </summary>
        /// <param name="parser"></param>
        /// <returns></returns>
        private ReceiverType DeriveTypeFromParser(PacketsParser parser)
        {
            switch(parser)
            {
                case UDPPacketsParser udp:
                    Port = udp.Port;
                    return ReceiverType.UDP;
                case WCFPacketsParser _:
                    return ReceiverType.WCF;
                case ErrorLoggerPacketsParser _:
                    return ReceiverType.ErrorLogger;
                case DebugMonitorParser _:
                    return ReceiverType.WinDebug;
                default:
                    return ReceiverType.UDP;
            }
        }

        public bool IsHidden { get; set; }

        private string name;
        public string Name
        {
            get => name;
            set { Set(() => Name, ref name, value); }
        }

        private ErrorLoggerType errorLoggerType;
        public ErrorLoggerType ErrorLoggerType 
        { 
            get => errorLoggerType;
            set 
            {
                Set(() => ErrorLoggerType, ref errorLoggerType, value); 
                if(ReceiverType == ReceiverType.ErrorLogger)
                {
                    if(errorLoggerType == ErrorLoggerType.BIT_64)
                    {
                        Address = "TsdcSystemSwErrorMailSlot64";
                    }
                    else
                    {
                        Address = "TsdcSystemSwErrorMailSlot";
                    }
                }

            }
        }

        private ReceiverType receiverType;
        public ReceiverType ReceiverType
        {
            get => receiverType;
            set
            {
                Set(() => ReceiverType, ref receiverType, value);
                IsAddressVisible = ReceiverType == ReceiverType.WCF || ReceiverType == ReceiverType.ErrorLogger;

                if(ReceiverType == ReceiverType.WinDebug)
                {
                    if(string.IsNullOrEmpty(Name))
                    {
                        Name = GetUniqueName("Windows Debug", 0);
                    }
                    Address = string.Empty;
                    Port = 0;
                    IsPortVisible = false;
                    IsAddressVisible = false;
                    IsErrorLogger = false;
                    IsAutoSave = false;
                }
                else if(ReceiverType == ReceiverType.UDP)
                {
                    if(string.IsNullOrEmpty(Name))
                    {
                        Name = GetUniqueName("UDP", 0);
                    }
                    Address = string.Empty;
                    IsPortVisible = true;
                    IsAddressVisible = false;
                    IsErrorLogger = false;
                    IsAutoSave = false;
                }
                else
                {
                    Port = 0;
                    IsPortVisible = false;
                    IsAddressVisible = true;
                    IsErrorLogger = false;
                    IsAutoSave = false;
                }

                if(ReceiverType == ReceiverType.WCF)
                {
                    if(string.IsNullOrEmpty(Name))
                    {
                        Name = GetUniqueName("EPTS", 0);
                    }
                    IsErrorLogger = false;
                    Address = "net.pipe://localhost/EPServer";
                    IsAutoSave = false;
                }

                if(ReceiverType == ReceiverType.ErrorLogger)
                {
                    if(string.IsNullOrEmpty(Name))
                    {
                        Name = GetUniqueName("Error Logger", 0);
                    }
                    IsErrorLogger = true;
                    Address = "TsdcSystemSwErrorMailSlot";
                    IsAutoSave = true;
                }
            }
        }

        /// <summary>
        /// returns a unique suggestion for the receiver name
        /// </summary>
        /// <param name="baseName"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        private string GetUniqueName(string baseName, int index)
        {
            if(receiverNames == null)
            {
                return baseName;
            }
            string rollingName = index > 1 ? $"{baseName} {index}" : baseName;
            while(receiverNames.ToList().Contains(rollingName))
            {
                return GetUniqueName(baseName, ++index);
            }
            return rollingName;
        }

        private bool isPortVisible;
        public bool IsPortVisible
        {
            get => isPortVisible;
            set { Set(() => IsPortVisible, ref isPortVisible, value); }
        }
        private bool isErrorLogger;
        public bool IsErrorLogger
        {
            get => isErrorLogger;
            set { Set(() => IsErrorLogger, ref isErrorLogger, value); }
        }

        public int Port
        {
            get => port;
            set { Set(() => Port, ref port, value); }
        }

        [XmlIgnore]
        public SolidColorBrush Color
        {
            get => color;
            set
            {
                colorString = value.ToARGB();
                Set(() => Color, ref color, value);
            }
        }

        public string ColorString
        {
            get => colorString;
            set
            {
                if(string.IsNullOrEmpty(value))
                {
                    value = "#FFFFFFFF";
                }

                color = color.FromARGB(value);
                Set(() => ColorString, ref colorString, value);
            }
        }

        public bool IsActive
        {
            get => isActive;
            set { Set(() => IsActive, ref isActive, value); }
        }

        public string Encoding
        {
            get => encoding;
            set { Set(() => Encoding, ref encoding, value); }
        }

        private string address;
        public string Address
        {
            get => address;
            set { Set(() => Address, ref address, value); }
        }

        private bool isAddressVisible;
        public bool IsAddressVisible
        {
            get => isAddressVisible;
            set { Set(() => IsAddressVisible, ref isAddressVisible, value); }
        }

        private bool isAutoSave;
        public bool IsAutoSave
        {
            get => isAutoSave && Settings.Instance.IsAutoSave;
            set 
            { 
                Set(() => IsAutoSave, ref isAutoSave, value);
                
                if(Parser != null)
                {
                    Parser.IsAutoSave = isAutoSave;
                }
            }
        }

        [OnDeserialized]
        private void SetValuesOnDeserialized(StreamingContext context)
        {
            color = color.FromARGB(colorString);
        }

        public object Clone()
        {
            return new Receiver(Name, Address, ReceiverType, receiverNames)
            {
                ColorString = ColorString,
                IsActive = IsActive,
                Color = Color,
                Port = Port,
                Encoding = Encoding,
                IsAddressVisible = IsAddressVisible,
                IsAutoSave = IsAutoSave,
            };
        }

        /// <summary>
        /// clear the parser
        /// </summary>
        public void Dispose()
        {
            Parser?.Dispose();
        }
    }
}
