using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.IO;
using iSTP_Embedded;

namespace iSTP_DataProcessing
{
    /// <summary>
    /// Controller for data processing module
    /// </summary>
    public class DataProcessing : IDisposable
    {
        private ISTPConfiguration _Config;
        private iSTP_DataProcessingWnd _View;
        private bool CSVReqested;
        private bool HoneyxRequested;
        private bool PerSensorLogging;
        private bool SPSrequested;
        private bool CompensationRequested;
        private bool FiltrationRequested;
        private bool DecimationRequested;
        private bool KeepAliveRequested;
        /// <summary>
        /// Sets for each SPS mods
        /// </summary>
        private List<SPSscripts.Sets_t> ActiveSet;
        private bool PressureModeRequested;
        private bool VirtualSensRequested;
        private iSTP_CompensatoryModWnd _ComWnd;
        private TempStabTimeWnd _TempStabTimeWnd;
        private Decimation MyDecimation;
        private Filtration MyFiltration;
        /// <summary>
        /// Database of virtual sensors
        /// </summary>
        private List<VirtualSensors> MyVirtual;
        static private int FIFOfreq = 1000;
        private int FilterFreq = 0;

        private CSVLogger MyCSVLogger;
        private HoneyxLogger MyHxLogger;
        private List<SPSLogger> MySpsLogger;
        private Object LoggerLock;
        private Object CompenModLogger;
        private string TopDestinationDirectory;
        private PressureMode MyPressureMode;
        private bool ReconfigureRequested = false;

        private Thread KeepAliveTh = null;
        private volatile bool KeepAliveEnabled;
        private FileStream KeepAliveFile;
        private byte KeepAliveCharacter = 0;

        private int DeciScaleUP;
        private int DeciScaleDOWN;

        private bool FirstPacketsTime = false; 

        private string TestDestination;

        private UInt32 fifoModeSimulatedPacketNumber = 0;

        private Dictionary<string, SPSLogger.ActiveAccGyroStruct> SPS_parameters;

        private UInt32 badFIFOpackets = 0;

        private List<string> VirtualSensPath = new List<string>();

        public string GetTestDestination
        {
            get { return TestDestination; }
        }

        public bool GetCSVreguested { get { return CSVReqested; } }
        public bool GetHXreguested { get { return this.HoneyxRequested; } }
        public bool GetPerSensorLogging { get { return this.PerSensorLogging; } }
        public bool GetSPSrequested { get { return SPSrequested; } }
        public bool GetCompensationRequested { get { return this.CompensationRequested; } }
        public bool GetFiltrationRequested { get { return this.FiltrationRequested; } }
        public bool GetDecimationRequested { get { return this.DecimationRequested; } }
        public bool GetKeepAliveRequested { get { return this.KeepAliveRequested; } }
        public int GetFiltrationCutOffFreq { get { return this.FilterFreq; } }
        public Dictionary<string, SPSLogger.ActiveAccGyroStruct> GetSPSsensorsSettings { get { return this.SPS_parameters; } }
        public bool GetVirtualSensRequested { get { return this.VirtualSensRequested; } }
        public List<string> GetVirtualSensPath { get { return this.VirtualSensPath; } }
        public int GetDeciScaleUP { get { return DeciScaleUP; } }
        public int GetDeciScaleDOWN { get { return DeciScaleDOWN; } }

        public uint GetBadFIFOpckCounter { get { return this.badFIFOpackets; } }

        /// <summary>
        /// Initialize components
        /// </summary>
        public DataProcessing()
        { 
            this._View = new iSTP_DataProcessingWnd();
            this._View.setController(this);
            LoggerLock = new Object();
            this.SPS_parameters = new Dictionary<string, SPSLogger.ActiveAccGyroStruct>();
            this.MySpsLogger = new List<SPSLogger>();
            this.ActiveSet = new List<SPSscripts.Sets_t>();
        }

        /// <summary>
        /// Dispose all allocated components
        /// </summary>
        ~DataProcessing()
        {
            Dispose();
        }

        /// <summary>
        /// Dispose all allocated components
        /// </summary>
        public void Dispose()
        {
            if (_Config != null)
                _Config = null;
            if (_View != null)
                _View.Dispose();
            if (_ComWnd != null)
                _ComWnd.Dispose();
            if (_TempStabTimeWnd != null)
                _TempStabTimeWnd.Dispose();
            if (MyDecimation != null)
                MyDecimation = null;
            if (MyFiltration != null)
                MyFiltration = null;
            if (KeepAliveFile != null)
                KeepAliveFile.Dispose();
        }

        /// <summary>
        /// Starts thread, creates and overwrites 1 byte file in specific destination
        /// </summary>
        /// <param name="destination">Destination path</param>
        /// <returns>TRUE - success</returns>
        public bool StartKeepAlive(string destination)
        {
            if (KeepAliveTh == null || !KeepAliveTh.IsAlive)
            {
                KeepAliveFile = new FileStream(destination + "//KeepAlive.hdd", FileMode.Create, FileAccess.ReadWrite);
                KeepAliveFile.WriteByte(0);
                KeepAliveEnabled = true;
                KeepAliveTh = new Thread(this.DriveKeepAliveThread) { Name = "Drive Keep Alive Thread", IsBackground = true };
                KeepAliveTh.Start();
            }
            return KeepAliveTh.IsAlive;
        }
        
        /// <summary>
        /// Stops thread 
        /// </summary>
        public void StopKeepAlive()
        {
            if (KeepAliveRequested)
            {
                if (KeepAliveTh != null)
                {
                    KeepAliveTh.Abort();
                    if (KeepAliveTh.IsAlive)
                        KeepAliveEnabled = false;
                    KeepAliveTh.Join();
                    KeepAliveTh = null;
                    string keepAliveFileName = KeepAliveFile.Name;
                    KeepAliveFile.Close();
                    KeepAliveFile.Dispose();
                    File.Delete(keepAliveFileName);
                }
            }
        }

        /// <summary>
        /// Overwrite byte in file every 5 sec
        /// </summary>
        public void DriveKeepAliveThread()
        {
            try
            {
                while (KeepAliveEnabled)
                {
                    KeepAliveFile.Seek(0, 0);
                    KeepAliveFile.WriteByte(KeepAliveCharacter++);
                    KeepAliveFile.Flush();
                    Thread.Sleep(5000);
                }
            }

            catch (ThreadAbortException)
            {
                Thread.ResetAbort();
            }
        }

        /// <summary>
        /// Initialize values in this class
        /// </summary>
        /// <param name="logDestination">Destination path</param>
        public void Configure(string logDestination)
        {
            TopDestinationDirectory = logDestination;
            this._View.ShowDialog();
            UpdateSettings();
            if (KeepAliveRequested)
            {
                StartKeepAlive(logDestination);
            }
        }

        /// <summary>
        /// Reads all mandatory parameters from data processing GUI
        /// </summary>
        private void UpdateSettings()
        {
            CSVReqested = this._View.RawCSVRequested;
            HoneyxRequested = this._View.RawHxRequested;
            PerSensorLogging = this._View.PerSensorLogRequested;
            SPSrequested = this._View.SPSrequested;
            CompensationRequested = this._View.CompensatoryRequested;
            FiltrationRequested = this._View.FiltrationRequested;
            DecimationRequested = this._View.DecimationRequested;
            FilterFreq = this._View.FilterFreqRequested;
            KeepAliveRequested = this._View.KeepAliveRequested;
            if (this._View.GetSPStaskWaittime > 0)
                SPSscripts.TaskWaitTime = this._View.GetSPStaskWaittime;
            VirtualSensRequested = this._View.VirtualSensRequested;
            VirtualSensPath = this._View.VirtualSensPath;
            DeciScaleUP = this._View.GetDeciScaleUP;
            DeciScaleDOWN = this._View.GetDeciScaleDOWN;

            ActiveSet.Clear();
            foreach(SPSscripts.Sets_t oneSet in this._View.SPSset)
            {
                ActiveSet.Add(oneSet);
            }
        }

        /// <summary>
        /// reinilitialize values and loggers with new configuration packet
        /// </summary>
        /// <param name="embConfig">Current configuration</param>
        /// <returns>TRUE - success</returns>
        public bool reInitializeLoggers(ISTPConfiguration embConfig)
        {
            try
            {
                if (VirtualSensRequested)
                {
                    MyVirtual = new List<VirtualSensors>();
                    foreach (string s in VirtualSensPath)
                    {
                        MyVirtual.Add(new VirtualSensors(s, ref embConfig));
                    }
                }

                this.ReconfigureRequested = true;

                FIFOfreq = EmbeddedController.GetSampleRate4FIFO();
                _Config = embConfig;

                if (SPSrequested)
                {
                    foreach (SPSLogger element in MySpsLogger)
                    {
                        element.UpdateSPSconfig(_TempStabTimeWnd.ReturnAndModifySPSconfig(element.Reconfigure(embConfig)));
                    }
                }

                if (!CompensationRequested)
                {
                    if (CSVReqested)
                        MyCSVLogger = new CSVLogger(DestinationDirectory, embConfig, PerSensorLogging);
                    if (HoneyxRequested)
                        MyHxLogger = new HoneyxLogger(DestinationDirectory, embConfig, PerSensorLogging);
                }
                else
                {
                    CompensatoryMode.ChangeSelected(_View.CompensationSelected);
                    bool[] _sensVer = CompensatoryMode.LoadFile(embConfig);
                    this._ComWnd = new iSTP_CompensatoryModWnd(_sensVer, embConfig);
                    this._ComWnd.ShowDialog();
                    if (!this._ComWnd.GetResult)
                    {
                        return false;
                    }

                    if (CSVReqested)
                    {
                        MyCSVLogger = new CSVLogger(DestinationDirectory, embConfig, PerSensorLogging);
                        this.CompenModLogger = new CSVLogger(DestinationDirectory, embConfig, PerSensorLogging);
                    }
                    if (HoneyxRequested)
                    {
                        MyHxLogger = new HoneyxLogger(DestinationDirectory, embConfig, PerSensorLogging);
                        this.CompenModLogger = new HoneyxLogger(DestinationDirectory, embConfig, PerSensorLogging);
                    }
                }
            }
            catch (Exception ex)
            {
                DataProcessingError.Add("reInitializeLoggers", "Unexpected exception", ex.ToString());
            }

            if (PressureModeRequested)
            {
                MyHxLogger = new HoneyxLogger(DestinationDirectory, embConfig, PerSensorLogging);
                MyPressureMode = new PressureMode();
            }

            return true;
        }

        /// <summary>
        /// Initialize alll required loggers
        /// </summary>
        /// <param name="embConfig">Current configuration</param>
        /// <returns>TRUE - success</returns>
        public bool InitializeLoggers(ISTPConfiguration embConfig)
        {
            try
            {
                if (VirtualSensRequested)
                {
                    MyVirtual = new List<VirtualSensors>();
                    foreach(string s in VirtualSensPath)
                    {
                        MyVirtual.Add(new VirtualSensors(s, ref embConfig));
                    }
                }

                FIFOfreq = EmbeddedController.GetSampleRate4FIFO();
                _Config = embConfig;
                DestinationDirectory = string.Format("{0}\\Data_from_{1}_{2:D2}_{3:D2}_{4:D2}h_{5:D2}m_{6:D2}s",
                                                       TopDestinationDirectory, DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day,
                                                       DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second);

                TestDestination = DestinationDirectory;
                if (FiltrationRequested)
                    MyFiltration = new Filtration(Convert.ToDouble(FilterFreq));
                if (DecimationRequested)
                    MyDecimation = new Decimation(FIFOfreq, DeciScaleUP, DeciScaleDOWN);

                //_Config = embConfig;

                if (SPSrequested)
                {
                    foreach (SPSscripts.Sets_t element in ActiveSet)
                    {
                        string newdest = SPSscripts.CreateNewDestination(DestinationDirectory, element);
                        if (newdest != string.Empty)
                        {
                            MySpsLogger.Add(new SPSLogger(newdest, embConfig, element));   
                        }
                    }

                    _TempStabTimeWnd = new TempStabTimeWnd(MySpsLogger[0].GetConfigSPS);
                    _TempStabTimeWnd.ShowDialog();
                    this.SPS_parameters = _TempStabTimeWnd.GetModifySPSconfig;
                     
                }

                if (!CompensationRequested)
                {
                    if (CSVReqested)
                        MyCSVLogger = new CSVLogger(DestinationDirectory, embConfig, PerSensorLogging);
                    if (HoneyxRequested)
                        MyHxLogger = new HoneyxLogger(DestinationDirectory, embConfig, PerSensorLogging);
                }
                else
                {
                    CompensatoryMode.ChangeSelected(_View.CompensationSelected);
                    bool[] _sensVer = CompensatoryMode.LoadFile(embConfig);
                    this._ComWnd = new iSTP_CompensatoryModWnd(_sensVer, embConfig);
                    this._ComWnd.ShowDialog();
                    if (!this._ComWnd.GetResult)
                    {
                        return false;
                    }

                    if (CSVReqested)
                    {
                        MyCSVLogger = new CSVLogger(DestinationDirectory, embConfig, PerSensorLogging);
                        this.CompenModLogger = new CSVLogger(DestinationDirectory, embConfig, PerSensorLogging);
                    }
                    if (HoneyxRequested)
                    {
                        MyHxLogger = new HoneyxLogger(DestinationDirectory, embConfig, PerSensorLogging);
                        this.CompenModLogger = new HoneyxLogger(DestinationDirectory, embConfig, PerSensorLogging);
                    }
                }
            }
            catch (Exception ex)
            {
                DataProcessingError.Add("DataProcessing.cs", "Exception during initialization loggers", ex.ToString());
            }

            return true;
        }

        /// <summary>
        /// Starts loggers. Creates all files and waiting for data packets.
        /// </summary>
        /// <param name="seconds">Seconds when this method was call</param>
        /// <param name="temperature">Nominal temperature form climatic chamber</param>
        public void StartLogs(int seconds, float temperature)
        {
            try
            {
                lock (LoggerLock)
                {
                    fifoModeSimulatedPacketNumber = 0;
                    FirstPacketsTime = false;

                    if (!SPSrequested)
                    {
                        CurrentLogDestination = string.Format("{0}\\{1}", DestinationDirectory, seconds);
                        if (!Directory.Exists(CurrentLogDestination))
                            Directory.CreateDirectory(CurrentLogDestination);
                    }

                    if (SPSrequested)
                    {
                        if (_TempStabTimeWnd != null && !this.ReconfigureRequested)
                        {
                            foreach (SPSLogger element in MySpsLogger)
                            {
                                element.UpdateSPSconfig(_TempStabTimeWnd.GetModifySPSconfig);
                            }
                        }
   
                        foreach (SPSLogger element in MySpsLogger)
                        {
                            element.LogStart(temperature, CompensationRequested);                           
                        }

                        if (MySpsLogger.Count > 0)
                            CurrentLogDestination = MySpsLogger[0].CyclePathActual;
                    }

                    if (!CompensationRequested)
                    {
                        if (CSVReqested)
                            MyCSVLogger.LogStart(CurrentLogDestination);
                        if (HoneyxRequested)
                            MyHxLogger.LogStart(CurrentLogDestination);
                    }
                    else
                    {
                        if (!SPSrequested)
                        {
                            string _path = string.Format("{0}{1}Raw", CurrentLogDestination, Path.DirectorySeparatorChar);
                            if (!Directory.Exists(_path))
                                Directory.CreateDirectory(_path);
                            string _pathCompLog = string.Format("{0}{1}Compensated", CurrentLogDestination, Path.DirectorySeparatorChar);
                            if (!Directory.Exists(_pathCompLog))
                                Directory.CreateDirectory(_pathCompLog);
                            if (CSVReqested)
                            {
                                MyCSVLogger.LogStart(_path);
                                ((CSVLogger)CompenModLogger).LogStart(_pathCompLog);
                            }
                            if (HoneyxRequested)
                            {
                                MyHxLogger.LogStart(_path);
                                ((HoneyxLogger)CompenModLogger).LogStart(_pathCompLog);
                            }
                        }
                    }

                }
            }
            catch (Exception ex)
            {
                DataProcessingError.Add("DataProcessing.cs", "Exception during starts new logs", ex.ToString());
            }
        }

        /// <summary>
        /// Close all required loggers
        /// </summary>
        public void CloseLoggers()
        {
            try
            {
                lock (LoggerLock)
                {
                    foreach (SPSLogger element in MySpsLogger)
                    {
                        CopyEmbeddedConfFile(element.CyclePathActual);
                    }


                    if (SPSrequested)
                    {
                        foreach (SPSLogger element in MySpsLogger)
                        {
                            element.Terminate();
                        }
                    }

                    if (!CompensationRequested)
                    {
                        if (CSVReqested)
                            MyCSVLogger.Terminate();
                        if (HoneyxRequested)
                            MyHxLogger.Terminate();
                    }
                    else
                    {
                        if (CSVReqested)
                        {
                            MyCSVLogger.Terminate();
                            ((CSVLogger)this.CompenModLogger).Terminate();
                        }
                        if (HoneyxRequested)
                        {
                            MyHxLogger.Terminate();
                            ((HoneyxLogger)this.CompenModLogger).Terminate();
                        }
                    }

                    if (DecimationRequested)
                    {
                        if (MyDecimation != null)
                        {
                            MyDecimation.ClearInernalBuffer();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                DataProcessingError.Add("DataProcessing.cs", "Can't close loggers", ex.ToString());
            }
        }

        /// <summary>
        /// Copy embedded configuration information
        /// </summary>
        /// <param name="path">Path to copying embedded configuration file</param>
        private void CopyEmbeddedConfFile(string path)
        {
            if (path.ToCharArray()[path.ToCharArray().Length - 1] == Path.DirectorySeparatorChar)
                path = string.Format("{0}{1}", path, "EmbeddedConfig.txt");
            else
                path = string.Format("{0}{1}{2}", path, Path.DirectorySeparatorChar, "EmbeddedConfig.txt");
            try
            {
                StreamWriter wfile = new StreamWriter(path, false);
                wfile.Write(ISTPConfiguration.GetEmbConfFileContent);
                wfile.Flush();
                wfile.Close();
            }
            catch (UnauthorizedAccessException)
            {
                DataProcessingError.Add("DataProcessing.CopyEmbeddedConfFile", "Unauthorized access", string.Format("[Path: {0}] Exception during coping embedded cofinguration file", path));
            }
            catch (DirectoryNotFoundException)
            {
                DataProcessingError.Add("DataProcessing.CopyEmbeddedConfFile", "Directory not found", string.Format("[Path: {0}] Exception during coping embedded cofinguration file", path));
            }
            catch (FileNotFoundException)
            {
                DataProcessingError.Add("DataProcessing.CopyEmbeddedConfFile", "File not found", string.Format("[Path: {0}] Exception during coping embedded cofinguration file", path));
            }
            catch (NotSupportedException ex)
            {
                DataProcessingError.Add("DataProcessing.CopyEmbeddedConfFile", "Not supported exception", string.Format("[Path: {0}] Exception during coping embedded cofinguration file", path) + ex.ToString());
            }
            catch (Exception ex)
            {
                DataProcessingError.Add("DataProcessing.CopyEmbeddedConfFile", string.Format("[Path: {0}] Exception during coping embedded cofinguration file {1}", path), ex.ToString());
            }
        }

        /// <summary>
        /// Root path
        /// </summary>
        public string DestinationDirectory { get; set; }

        /// <summary>
        /// Path to current logging destination
        /// </summary>
        public string CurrentLogDestination { get; set; }

        /// <summary>
        /// Initialize data packet for FIFO function
        /// </summary>
        /// <param name="packet"></param>
        private void initTemporaryDataPacket(ref EmbeddedPacket packet) 
        {
            packet = new EmbeddedPacket();
            packet.MsgType = EmbeddedProtocol.TYPE_DATA;
            packet.MsgNumber = fifoModeSimulatedPacketNumber++;
        }

        private object OnlyMe = new object();
        /// <summary>
        /// Parse FIFO packet into normal data packet
        /// </summary>
        /// <param name="packet">FIFO packet</param>
        public void ProcessFIFOpacket(EmbeddedPacket packet)
        {
            try
            {
                lock (OnlyMe)
                {
                    int dataIndex = 0;
                    bool correct = true;

                    Int32 temporaryPacketsDataSize = 0;
                    Int32 packetMaxTimeDepth = (Int32)packet.getInt(0) & 0xFFFF; 
                    for (int sensorIndex = 0; sensorIndex < this._Config.Size; sensorIndex++) 
                    {
                        temporaryPacketsDataSize += (this._Config[sensorIndex].QuantityIndexes.Length) * sizeof(Single);
                    }
                    EmbeddedPacket[] temporarySimplePackets = new EmbeddedPacket[packetMaxTimeDepth];

                    UInt32 fifoRecordsCount = 0;

                    //----- check packet
                    fifoRecordsCount = packet.getInt(dataIndex) & 0xFFFF;
                    int i = dataIndex + (int)fifoRecordsCount * sizeof(float) * this._Config[0].QuantityIndexes.Length + sizeof(float);
                    int j = 1;

                    while (i < packet.MsgLength && j < this._Config.Size)
                    {
                        uint val = BitConverter.ToUInt32(new byte[]
                            {
                                packet.MsgData[i + 3],
                                packet.MsgData[i + 2],
                                packet.MsgData[i + 1],
                                packet.MsgData[i]
                            }, 0);
                        val = val & 0xFFFF;

                        if (val != fifoRecordsCount || (i+1) > packet.MsgLength)
                            correct = false;
                        i += (int)val * sizeof(float) * this._Config[j++].QuantityIndexes.Length + sizeof(float);
                    }
                    //----- end check

                    if (correct)
                    {
                        for (int sensorIndex = 0; sensorIndex < this._Config.Size; sensorIndex++) 
                        {
                            if (dataIndex >= (packet.MsgLength / sizeof(UInt32)))
                                continue;

                            fifoRecordsCount = packet.getInt(dataIndex) & 0xFFFF;
                            dataIndex++;


                            for (UInt32 fifoTimeIndex = 0; fifoTimeIndex < fifoRecordsCount; fifoTimeIndex++)
                            {
                                if (temporarySimplePackets[fifoTimeIndex] == null)
                                {
                                    temporarySimplePackets[fifoTimeIndex] = new EmbeddedPacket();
                                    temporarySimplePackets[fifoTimeIndex].MsgType = EmbeddedProtocol.TYPE_DATA;
                                    temporarySimplePackets[fifoTimeIndex].MsgNumber = fifoModeSimulatedPacketNumber++;

                                    temporarySimplePackets[fifoTimeIndex].MsgLength = temporaryPacketsDataSize;

                                    temporarySimplePackets[fifoTimeIndex].PrepareBuffer();
                                    if (fifoTimeIndex == 0)
                                    {
                                        temporarySimplePackets[fifoTimeIndex].MsgTimeStamp = packet.MsgTimeStamp;
                                    }
                                    else
                                    {
                                        temporarySimplePackets[fifoTimeIndex].MsgTimeStamp = temporarySimplePackets[fifoTimeIndex - 1].MsgTimeStamp + (1.0 / SampleRate);
                                    }
                                    temporarySimplePackets[fifoTimeIndex].CalcCRC32();
                                }

                                foreach (int quantityIndex in this._Config[sensorIndex].QuantityIndexes) 
                                {
                                    (temporarySimplePackets[fifoTimeIndex]).SetData(quantityIndex, packet.GetData(dataIndex));
                                    dataIndex++;
                                }

                                temporarySimplePackets[fifoTimeIndex].MsgLength = temporarySimplePackets[fifoTimeIndex].MsgData.Length;
                            }

                        }
                        foreach (EmbeddedPacket simplePacket in temporarySimplePackets)
                        {
                            this.ProcessDataPacket(simplePacket);
                        }
                    }
                    else
                    {
                        this.badFIFOpackets++;
                        DataProcessingError.Add("ProcessFIFOpacket", "Not valid FIFO format - Check error", string.Format("i = {0} | j = {1} | pck.len = {2} | config.size = {3} | FIFOcount = {4}"
                            , i, j, packet.MsgLength, this._Config.Size, fifoRecordsCount));
                    }
                }
            }
            catch (Exception ex)
            {
                DataProcessingError.Add("ProcessFIFOpacket", "Exception during parsing FIFO packet", ex.ToString());
            }
        }

        /// <summary>
        /// Provides data packet to all required loggers
        /// </summary>
        /// <param name="packet">Data packet</param>
        public void ProcessDataPacket(EmbeddedPacket incomePacket)
        {
            EmbeddedPacket[] packet;
            lock (LoggerLock)
            {
                if (VirtualSensRequested)
                {
                    foreach (VirtualSensors vs in MyVirtual)
                    {
                        vs.CalculateAverage(ref incomePacket);
                    }
                }

                if (!FirstPacketsTime)
                {
                    if (incomePacket.MsgTimeStamp > 1800)
                        return;
                    else
                        FirstPacketsTime = true;
                }

                //Filtration NOTE: MUST BE BEFORE decimation
                if (FiltrationRequested)
                    MyFiltration.CalcFiltration(ref incomePacket);
                             
                if (DecimationRequested)
                {
                    if (!MyDecimation.CalcDecimation(incomePacket, out packet))
                    {
                        return;
                    }

                    if (packet.Length == 0)
                    {
                        return;
                    }
                }
                else
                {
                    packet = new EmbeddedPacket[] { incomePacket };
                }

                foreach (EmbeddedPacket element in packet)
                {
                    

                    if (SPSrequested)
                    {
                        foreach (SPSLogger drelementos in MySpsLogger)
                        {
                            drelementos.LogData(element, CompensationRequested);
                        }
                    }

                    if (!CompensationRequested)
                    {
                        if (CSVReqested)
                            MyCSVLogger.LogData(element);
                        if (HoneyxRequested)
                            MyHxLogger.LogData(element);
                    }
                    else
                    {
                        if (CSVReqested)
                        {
                            MyCSVLogger.LogData(element);
                            ((CSVLogger)this.CompenModLogger).LogData(CompensatoryMode.Recalculate(element));
                        }
                        if (HoneyxRequested)
                        {
                            MyHxLogger.LogData(element);
                            ((HoneyxLogger)this.CompenModLogger).LogData(CompensatoryMode.Recalculate(element));
                        }
                    }

                    if (PressureModeRequested)
                    {
                        MyHxLogger.LogData(element);
                    }
                }     
            }
        }

        private ushort SampleRate;

        /// <summary>
        /// Saves input sample rate
        /// </summary>
        /// <param name="sampleRate">Sample rate [Hz]</param>
        public void SetSampleRate(ushort sampleRate)
        {
            SampleRate = sampleRate;
        }
    }

    /// <summary>
    /// Provider for error message to main controller
    /// </summary>
    public static class DataProcessingError
    {
        private static List<string> Fulltext = new List<string>();
        private static List<string> ShortText = new List<string>();
        private static List<string> Source = new List<string>();
        private static State_e State;

        public enum State_e
        {
            Normal,
            Critical
        }

        public static bool isActive { get; private set; }

        /// <summary>
        /// Fill class with new exception
        /// </summary>
        /// <param name="source">Exception source</param>
        /// <param name="shortText">This text will apear in test log</param>
        /// <param name="fullText">This text will apear in debug log </param>
        public static void Add(string source, string shortText, string fullText, bool iscritical = false)
        {
            Fulltext.Add(fullText);
            ShortText.Add(shortText);
            Source.Add(source);
            isActive = true;

            if (iscritical)
                State = State_e.Critical;
            else
                State = State_e.Normal;
        }

        /// <summary>
        /// Reads axception and clear memory.
        /// </summary>
        /// <param name="errors">Allocates with 2 members</param>
        public static State_e GetMsg(out List<string[]> errors)
        {
            isActive = false;
            errors = new List<string[]>();
            for (int i = 0; i < Fulltext.Count; i++)
                    errors.Add(new string[]
                {
                    string.Format("DataProcessing: Source[{0}] -> ShortText = {1}", Source[i], ShortText[i]),
                    string.Format("DataProcessing: Source[{0}] -> ShortText = {1} -> FullText = {2}", Source[i], ShortText[i], Fulltext[i])
                });

            Source.Clear();
            ShortText.Clear();
            Fulltext.Clear();

            return State;
        }
    }
}
