using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Timers;

namespace RateTableGUI
{
    public class RateTableController
    {
        private RateTableWnd _View = new RateTableWnd();
        private IRateTable _Model;
        private System.Timers.Timer ConfigTimer;
        private DeviceStatus RateTableStatus;

        public enum DeviceStatus
        {
            NotConnected,
            Connecting,
            Connected
        }

        public RateTableController()
        {
            this._View = new RateTableWnd();
            this._View.setController(this);
            RateTableStatus = DeviceStatus.NotConnected;
        }

        public Boolean Configure()
        {
            if (ConfigTimer != null)
                ConfigTimer.Start();
            this._View.ShowDialog();
            if (ConfigTimer != null)
                ConfigTimer.Stop();

            return (RateTableStatus == DeviceStatus.Connected);
        }

        public void SendCommandProvider(string cmd)
        {
            _Model.SendCommandProvider(cmd);
        }

        public string ReadCommandProvider()
        {
            return _Model.ReadCommandProvider();
        }

        public void SetAxis1(int deg)
        {
            _Model.SetAxis1(deg);
        }

        public void SetAxis1(int deg, int vel)
        {
            _Model.SetAxis1(deg, vel);
        }

        public void SetAxis2(int deg)
        { 
            _Model.SetAxis2(deg);
        }

        public void SetAxis2(int deg, int vel)
        {
            _Model.SetAxis2(deg, vel);
        }

        public void Connect()
        { 
            bool RateTableConnected = false;

            if (RateTableStatus == DeviceStatus.NotConnected)
            {
                switch (this._View.SelectedRateTable)
                { 
                    case 0:
                        _Model = new AERO4000driver();
                        break;
                }
                RateTableStatus = DeviceStatus.Connecting;
                _View.UpdateConnectionControls();
                if (_View.IsEthernetSelected)
                {
                    System.Net.IPAddress address;
                    if (System.Net.IPAddress.TryParse(_View.IpAddress, out address))
                    {
                        if (_View.TcpPort >= 0)
                            RateTableConnected = _Model.Connect(address, _View.TcpPort);
                        else
                        {
                            MessageBox.Show("Incorrect TCP Port", "Climatic Chamber connection", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                            RateTableConnected = false;
                        }
                    }
                    else
                    {
                        MessageBox.Show("Incorrect IP address format", "Climatic Chamber connection", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        RateTableConnected = false;
                    }
                }
                else // Serial line
                {
                    RateTableConnected = _Model.Connect(_View.ComPort,
                                   _View.ComBaudrate,
                                   _View.ComDatabits,
                                   _View.ComStopbits,
                                   _View.ComParity);
                }
            }
            else // Disconnect
            {
                _Model.Stop();                               // stop chamber
                _Model.Disconnect();                         // disconnect chamber
                RateTableStatus = DeviceStatus.NotConnected;
                if (ConfigTimer != null)
                {
                    ConfigTimer.Stop();
                    ConfigTimer.Dispose();
                    ConfigTimer = null;
                }
            }

            if (RateTableConnected)
            {
                bool result = false;
                result = _Model.Run();                                  // start chamber
                if (result)
                {
                    RateTableStatus = DeviceStatus.Connected;
                    ConfigTimer = new System.Timers.Timer(1000);
                    ConfigTimer.Elapsed += new ElapsedEventHandler(ClimaWeatherUpdate);
                    ConfigTimer.Enabled = true;
                }
                else
                {
                    _Model.Disconnect();
                    RateTableStatus = DeviceStatus.NotConnected;
                }
            }
            else
            {
                RateTableStatus = DeviceStatus.NotConnected;
            }
            _View.UpdateConnectionControls();
        }

        private void ClimaWeatherUpdate(object source, ElapsedEventArgs e)
        {
            _Model.ManualUpdate();
            _View.UpdateValues(_Model.GetInnerZeroPos(), _Model.GetInnerVel(), _Model.GetInnerStatus(), _Model.GetInnerRefPos(), _Model.GetInnerActPoc(), _Model.GetInnerActAcc(),
                               _Model.GetOuterZeroPos(), _Model.GetOuterVel(), _Model.GetOuterStatus(), _Model.GetOuterRefPos(), _Model.GetOuterActPoc(), _Model.GetOuterActAcc());

        }

        public void ProvidesCommands(bool rateTable, bool climaChamber, bool axisInner, bool axisInnerRotate, int axisInnerPos, int axisInnerVel, bool axisOuter, bool axisOuterRotate, int axisOuterPos, int axisOuterVel)
        {
            _Model.ProvidesCommands(rateTable, climaChamber, axisInner, axisInnerRotate ,axisInnerPos, axisInnerVel, axisOuter, axisOuterRotate , axisOuterPos, axisOuterVel);
        }

        public void Dispose()
        {
            if (_Model != null)
            {
                //_Model.UpdaterStop();
                _Model.Disconnect();
                _Model = null;
            }
            if (ConfigTimer != null)
                ConfigTimer.Dispose();
        }

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

        public DeviceStatus Status { get { return RateTableStatus; } }

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

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

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

        public float ActInnerVelocity { get { return _Model.GetInnerVel(); } }
        public float ActInnerRefPosition { get { return _Model.GetInnerRefPos(); } }
        public float ActInnerPosition { get { return _Model.GetInnerActPoc(); } }
        public float ActInnerAcceleration { get { return _Model.GetInnerActAcc(); } }

        public float ActOuterVelocity { get { return _Model.GetOuterVel(); } }
        public float ActOuterRefPosition { get { return _Model.GetOuterRefPos(); } }
        public float ActOuterPosition { get { return _Model.GetOuterActPoc(); } }
        public float ActOuterAcceleration { get { return _Model.GetOuterActAcc(); } } 

        public string Name { get { return (_Model.ChamberName); } }
    }
}
