using System;
using Microsoft.Win32;
using System.Text.RegularExpressions;
using System.Timers;

namespace iSTP_Embedded
{
    /// <summary>
    /// Provider for communication with ISTP
    /// </summary>
    public class EmbeddedController : IDisposable
    {
        private EmbeddedWnd _View;
        /// <summary>
        /// Communication protocol
        /// </summary>
        private EmbeddedProtocol _Model;

        private Boolean TestRunning;
        private System.Timers.Timer ConfigTimer;

        private bool ReconfigureRequired;

        public enum PlatformStatus
        {
            NotConnected,
            Connected,
            FetchingConfig,
            Configured,
            Logging,
            Error,
            SRTooHigh
        }

        private PlatformStatus EmbeddedStatus = PlatformStatus.NotConnected;

        public int GetACKinMem { get { return _Model.GetPacketInACKmem; } }
        public string[] GetHealthDataHeaders { get { return _Model.GetHealthDataHeaders; } }

        public EmbeddedController() 
        {
            this._View = new EmbeddedWnd();
            this._View.setController(this);
            this._Model = new EmbeddedProtocol();
            RequestedFifoReadRate = 1000;
            this.ReconfigureRequired = false;
        }

        public Boolean Configure(Boolean TestRunning)
        {
            this.TestRunning = TestRunning;
            this._View.ShowDialog();

            return ((this.EmbeddedStatus == PlatformStatus.NotConnected) || (this.EmbeddedStatus == PlatformStatus.Error) ? false : true);
        }

        /// <summary>
        /// Configure platform while test running
        /// </summary>
        /// <returns></returns>
        public void Configure()
        {
            _Model.Reconfiguration();
        }

        public void ConnectAndConfigure()
        {
            if (this.EmbeddedStatus == PlatformStatus.NotConnected)
            {
                string configFileName = "EmbeddedConfig.txt";
                _Model.ConfigureConnection(_View.getPort,
                                           _View.getBaudrate,
                                           _View.getDatabits,
                                           _View.getStopbits,
                                           _View.getParity,
                                           _View.getFlowCtrl);
                _Model.ConfigFile = configFileName;

                if (_Model.Connect())
                {
                    this.EmbeddedStatus = PlatformStatus.Connected;
                    _Model.Initialize(configFileName);

                    if (ConfigTimer != null)
                        ConfigTimer.Dispose();
                    ConfigTimer = new System.Timers.Timer(100);
                    ConfigTimer.Elapsed += new ElapsedEventHandler(ConfigStatusUpdate);
                    ConfigTimer.Enabled = true;
                    this.EmbeddedStatus = PlatformStatus.FetchingConfig;
                    _View.UpdateStatusBar(StatusMessage);
                }
                else
                {
                    this.EmbeddedStatus = PlatformStatus.NotConnected;
                    _View.UpdateStatusBar(StatusMessage);
                }
            }
            else
            {
                if (_Model.Disconnect())
                {
                    this.EmbeddedStatus = PlatformStatus.NotConnected;
                }
                else
                {
                    this.EmbeddedStatus = PlatformStatus.Error;
                }
                _View.SetForConnect();
            }
        }
        private static ushort SampleRate4Dec = 1000;
        private void ConfigStatusUpdate(object source, ElapsedEventArgs e)
        {
            if (this._Model.EmbeddedConfiguration.ConfigurationComplete)
            {
                FifoModeEnabled = _View.FifoModeRequested;
                this._Model.SetFIFOmode(FifoModeEnabled);
                
                if (FifoModeEnabled)
                {
                    RequestedFifoReadRate = _View.getFifoReadRate;
                    this._Model.RequestFifoReadRate(RequestedFifoReadRate);
                }
                
                RequestedSampleRate = _View.getSampleRate;
                SampleRate4Dec = RequestedSampleRate;
                this.ReconfigureRequired = _View.getReconfigurationRequired;
                this._Model.RequestSampleRate(RequestedSampleRate);

                HealthDataLoggingEnabled = _View.HealthDataRequested;
                this._Model.EnableHealthDataTransmission(HealthDataLoggingEnabled);
                this.EmbeddedStatus = PlatformStatus.Configured;
                ConfigTimer.Enabled = false;
                ConfigTimer.Dispose();
                FillParameters();
                ShowFWVersion();
            }
            else if (_Model.DroppedPackets != 0 || TimeSinceLastConfComPacket > 1000)
            {
                EmbeddedStatus = PlatformStatus.Error;
                _Model.Disconnect();
                ConfigTimer.Enabled = false;
                ConfigTimer.Dispose();
            }
            else
                this.EmbeddedStatus = PlatformStatus.FetchingConfig;
        }

        private void ShowFWVersion()
        {
            _View.ChangeFWInfo(_Model.EmbeddedConfiguration.FWVersion, _Model.EmbeddedConfiguration.FWInfo);
        }

        private void FillParameters()
        {
            _View.ResetSensorView();
            for (uint i = 0; i < ISTPConfiguration.MaxAxes; i++)
            {
                _View.AddAxis((i == 3? "Platform" : "Axis " + ISTPConfiguration.GetAxisStr(i)));
                for (int j = 0; j < ISTPConfiguration.MaxBoardsPerAxis; j++)
                {
                    _View.AddBoard((int)i, _Model.EmbeddedConfiguration.Boards[i, j].Name);
                    if (_Model.EmbeddedConfiguration.Boards[i, j].Parameters != null)
                        foreach (ISTPConfiguration.Parameter_t par in _Model.EmbeddedConfiguration.Boards[i, j].Parameters)
                        {
                            _View.AddParameter((int)i, j, par.Name, par.CurrentOption);
                        }
                }
            }
        }

        public void ConfigureBoardParameter(int axis, int board, int paramIndex, int optionIndex)
        {
            _Model.ConfigureBoardParameter(axis, board, paramIndex, optionIndex);
        }

        public bool isConfigured
        {
            get { return (this.EmbeddedStatus == PlatformStatus.Configured); }
        }

        public PlatformStatus Status
        {
            get { return (this.EmbeddedStatus);}
        }

        public bool getReconfiguredState
        {
            get { return this.ReconfigureRequired; }
        }

        public string StatusMessage
        {
            get
            {
                string retVal = "";
                switch (this.EmbeddedStatus)
                {
                    case PlatformStatus.Connected:
                        retVal = "Platform is connected";
                        break;
                    case EmbeddedController.PlatformStatus.FetchingConfig:
                        retVal = "Fetching configuration";
                        break;
                    case EmbeddedController.PlatformStatus.Configured:
                        retVal = "Platform is configured";
                        break;
                    case EmbeddedController.PlatformStatus.Logging:
                        retVal = "Platform is logging data";
                        break;
                    case EmbeddedController.PlatformStatus.NotConnected:
                        retVal = "Platform is not connected";
                        break;
                    case EmbeddedController.PlatformStatus.Error:
                    default:
                        retVal = "An error has occured!";
                        break;
                }
                return retVal;
            }
        }

        public uint LostPackets
        { get { return (_Model.LostPackets); } }

        public uint ReceivedPackets
        { get { return (_Model.ReceivedPackets); } }
        
        public String[] getAvailableCOMs()
        {
            return System.IO.Ports.SerialPort.GetPortNames();
        }

        public String getISTPport()
        {
            String comport = "";

            String VID = "03EB";        //VID of Atmel corp.
            String PID = "2410";        //PID manually assigned to Inertial Sensors Test Unit (or IMU)

            String pattern = String.Format("^VID_{0}.PID_{1}", VID, PID);
            Regex _rx = new Regex(pattern, RegexOptions.IgnoreCase);

            RegistryKey rk1 = Registry.LocalMachine;
            RegistryKey rk2 = rk1.OpenSubKey("SYSTEM\\CurrentControlSet\\Enum");

            foreach (String s3 in rk2.GetSubKeyNames())
            {

                RegistryKey rk3 = rk2.OpenSubKey(s3);
                foreach (String s in rk3.GetSubKeyNames())
                {
                    if (_rx.Match(s).Success)
                    {
                        RegistryKey rk4 = rk3.OpenSubKey(s);
                        foreach (String s2 in rk4.GetSubKeyNames())
                        {
                            RegistryKey rk5 = rk4.OpenSubKey(s2);
                            RegistryKey rk6 = rk5.OpenSubKey("Device Parameters");
                            string port = (rk6 != null ? ((string)rk6.GetValue("PortName")) : null);
                            if (port != null)
                                comport = port.Trim();
                        }
                    }
                }
            }
            return comport;
        }

        static public ushort GetSampleRate4FIFO()
        {
            return SampleRate4Dec;
        }

        public ISTPConfiguration getISTPConfiguration { get { return _Model.EmbeddedConfiguration; } }
        
        public EmbeddedHealthData Health { get { return _Model.EmbeddedHealth; } }

        public bool SampleRateOK
        { get { return (_Model.SampleRateOK); } }

        public double TimeSinceLastDataPacket
        { get { return ((DateTime.Now - _Model.LastDataPacketTime).TotalMilliseconds);} }

        public double TimeSinceLastConfComPacket
        { get { return ((DateTime.Now - _Model.LastConfComPacketTime).TotalMilliseconds); } }

        public double EmbeddedTime { get { return _Model.EmbeddedTime; } }

        public bool HealthDataLoggingEnabled { get; private set; }

        public bool FifoModeEnabled { get; private set; }

        public ushort RequestedSampleRate { get; private set; }

        public ushort RequestedFifoReadRate { get; private set; }

        public void SetDataProcesing(EmbeddedProtocol.ProcessingDelegate pd)
        {
            _Model.SetDataLogger(pd);
        }

        public void ResetRxStats()
        {
            _Model.ResetRxStats();
        }

        public bool PowerSensors(bool powered)
        {
            return _Model.Initialization(powered ? EmbeddedProtocol.ID_INIT_3V3 : 0);
        }

        public bool StopLogging()
        {
            return _Model.StopLogging();
        }

        public bool StartLogging()
        {
            return _Model.StartLogging();
        }

        public bool SetFIFOmode(bool isEnabled)
        {
            return _Model.SetFIFOmode(isEnabled);
        }

        public void EnableDataProcessing(bool enable)
        {
            _Model.EnableDataProcessing(enable);
        }

        public void Dispose()
        {
            if (_View != null)
                _View.Dispose();
            if (_Model != null)
                _Model.Dispose();
            if (ConfigTimer != null)
                ConfigTimer.Dispose();
        }

        public string[] GetParamList(int axis, int board, int par)
        {
            return _Model.EmbeddedConfiguration.Boards[axis, board].Parameters[par].Options;
        }

        public int GetSelectedOption(int axis, int board, int par)
        {
            return _Model.EmbeddedConfiguration.Boards[axis, board].Parameters[par].CurrentOption;
        }

        public void SetSimSensorCount(int count)
        {
            string configFileName = "EmbeddedConfig.txt";
            _Model.SetSimSensorCount(count);
            this.EmbeddedStatus = PlatformStatus.Connected;
            _Model.Initialize(configFileName);

            if (ConfigTimer != null)
                ConfigTimer.Dispose();
            ConfigTimer = new System.Timers.Timer(100);
            ConfigTimer.Elapsed += new ElapsedEventHandler(ConfigStatusUpdate);
            ConfigTimer.Enabled = true;
            this.EmbeddedStatus = PlatformStatus.FetchingConfig;
            _View.UpdateStatusBar(StatusMessage);
        }

        public void ResendMSG_ACK()
        {
            _Model.ResendMSG_ACK();
        }

        public bool CheckTime_ACK()
        {
            return _Model.CheckTime_ACK();
        }

        public void ClearMemory()
        {
            _Model.ClearMemory();
        }

        public void ClearStreamBuffer()
        {
            _Model.ClearStreamBuffer();
        }
    }
}
