using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using iSTP_Embedded;
using System.IO;

namespace iSTP_DataProcessing
{
    /// <summary>
    /// Loads information from Batch1 and provides calculations
    /// </summary>
    public class SensorACompBatch1 : ICompensatoryMode
    {
        [DllImport("SensorA_LUT_Batch1.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
        private static extern double SensorABiasLUT_Batch1(double axis, double senID, double temp);

        private Dictionary<string, SensorAComp_t> SensorAComp = new Dictionary<string, SensorAComp_t>();

        /// <summary>
        /// Infornmation about one sensor
        /// </summary>
        private struct SensorAComp_t
        {
            /// <summary>
            /// Sensors ID due to *Batch1*.csv
            /// </summary>
            public double ID;
            /// <summary>
            /// Represents number of axis in sensor due to ISTP configuration
            /// </summary>
            public int axis;
            /// <summary>
            /// Indexes in incoming data pakcet for each axis
            /// </summary>
            public int[] Indexes;
            /// <summary>
            /// Temperature index in incoming data packet
            /// </summary>
            public int tempIndex;
            /// <summary>
            /// Actual temperature due to data from incoming data packet
            /// </summary>
            public double temp;
            /// <summary>
            /// New data
            /// </summary>
            public double[] data;
        }

        /// <summary>
        /// Loads *Batch1*.csv and SensorA_LUT_Batch1.dll. Saves information about indexes for each member of data packet
        /// </summary>
        /// <param name="config"></param>
        public SensorACompBatch1(ISTPConfiguration config)
        {
            LoadBoschSensList();
            int i = 0;
            while (config.Sensors[i].Active)
            {
                if (this.SensorAComp.ContainsKey(config.Sensors[i].ShortName))
                {
                    SensorAComp_t _buff = new SensorAComp_t();
                    if (this.SensorAComp.TryGetValue(config.Sensors[i].ShortName, out _buff))
                    {
                        _buff.Indexes = config.Sensors[i].QuantityIndexes;

                        for (int q = 0; q < config.Sensors[i].Quantities.Length; q++)
                        {
                            if (config.Sensors[i].Quantities[q].Contains("temp"))
                            {
                                _buff.tempIndex = config.Sensors[i].QuantityIndexes[q];
                                _buff.axis = config.Sensors[i].Quantities.Length - 1;
                                int[] _mem = new int[_buff.Indexes.Length - 1];
                                int _memIndex = 0;
                                for (int p = 0; p < _buff.Indexes.Length; p++)
                                    if (_buff.Indexes[p] != _buff.tempIndex)
                                        _mem[_memIndex++] = _buff.Indexes[p];
                                _buff.Indexes = _mem;
                                break;
                            }
                        }
                        this.SensorAComp[config.Sensors[i].ShortName] = _buff;
                    }
                }
                i++;
            }
        }

        /// <summary>
        /// Adds new temperature, calculates new values and saves it in data array
        /// </summary>
        /// <param name="sensorcomp">Specific sensor</param>
        /// <param name="temp">Actual temperature</param>
        private void AddTemp(ref SensorAComp_t sensorcomp, double temp)
        {
            sensorcomp.temp = temp;
            sensorcomp.data = new double[sensorcomp.axis];
            for (int i = 0; i < sensorcomp.data.Length; i++)
                sensorcomp.data[i] = SensorABiasLUT_Batch1((double)i + 1, sensorcomp.ID, temp);
        }

        /// <summary>
        /// Loads information from *Batch1*.csv
        /// </summary>
        private void LoadBoschSensList()
        {
            const string partialName = "Batch1";

            DirectoryInfo hdDirectoryInWhichToSearch = new DirectoryInfo(Directory.GetCurrentDirectory());
            if (hdDirectoryInWhichToSearch.Exists)
            {
                FileInfo[] filesInDir = hdDirectoryInWhichToSearch.GetFiles(string.Format("*{0}*.csv", partialName));

                if (filesInDir.Length > 0)
                {
                    StreamReader _file = new StreamReader(filesInDir[0].FullName);
                    while (!_file.EndOfStream)
                    {
                        string[] _buff = _file.ReadLine().Split(',');
                        SensorAComp_t _sens = new SensorAComp_t() { ID = Convert.ToDouble(_buff[1]) };
                        this.SensorAComp.Add(_buff[0], _sens);
                    }
                }
            }
        }

        /// <summary>
        /// From incoming data packet calculates new values
        /// </summary>
        /// <param name="packet">Incoming data packet</param>
        /// <returns>Array with new values</returns>
        public float[] GetCompValues(EmbeddedPacket packet)
        {
            float[] _res = new float[packet.MsgLength / 4];

            for (int i = 0; i < _res.Length; i++)
                _res[i] = packet[i];

            for(int i = 0; i < this.SensorAComp.Count; i++)
            {
                var pair = this.SensorAComp.ElementAt(i);
                SensorAComp_t _buff = new SensorAComp_t();
                if (this.SensorAComp.TryGetValue(pair.Key, out _buff))
                {
                    if (_buff.Indexes != null)
                    {
                        AddTemp(ref _buff, packet[_buff.tempIndex]);
                        this.SensorAComp[pair.Key] = _buff;

                        for (int j = 0; j < this.SensorAComp[pair.Key].Indexes.Length; j++)
                        {
                            _res[_buff.Indexes[j]] += (float)_buff.data[j];
                        }
                    }
                }
            }
            
            return _res;
        }

        /// <summary>
        /// Compare current configuration with internal database
        /// </summary>
        /// <param name="packet">Current configuration</param>
        /// <returns>Array of results of compare</returns>
        public bool[] SensorsVerification(ISTPConfiguration packet)
        {
            bool[] _res = new bool[packet.Size];

            for (int i = 0; i < packet.Size; i++)
            {
                for (int q = 0; q < this.SensorAComp.Count; q++)
                {
                    if (this.SensorAComp.ContainsKey(packet.Sensors[i].ShortName))
                    {
                        _res[i] = true;
                        break;
                    }
                }
            }

            return _res;
        }
    }
}
