using System;
using System.IO;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Diagnostics;
using System.Windows.Forms;
using iSTP_DebugConsole;

namespace iSTP_Core
{
    /// <summary>
    /// Main application GUI.
    /// </summary>
    public partial class iSTP_MainWnd : Form
    {
        private TestController _Controller; ///<summary>  Application core </summary>

        private iSTP_ConsoleWnd MyConsole = new iSTP_ConsoleWnd(); ///<summary> Test logger </summary>
        private DebugConsole MyDbgConsole = new DebugConsole(); ///<summary> Debug logger </summary>

        
        public iSTP_MainWnd()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Loads basic settings
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void iSTP_MainWnd_Load(object sender, EventArgs e)
        {
            #if DEBUG
            debugLayout();
            #endif
            this.foldersAutoSetup();
        }

        /// <summary>
        /// Show debugg window only in debug mode
        /// </summary>
        [Conditional("DEBUG")]
        private void debugLayout()
        {
            this.debugWindowToolStripMenuItem.Checked = true;
            this.Text = this.Text + " - Developer version";
        }

        /// <summary>
        /// Fill data path and automaticaly loads user define test
        /// </summary>
        public void foldersAutoSetup()
        {
            String InputDataFolder = @"..\..\TestSettings\";
            String TestProcedureExtension = "*.csv";
            String OutputDataFolder = @"..\..\Data\";

            String path = Directory.GetCurrentDirectory();
            String testProcedurePath = Path.GetFullPath(Path.Combine(path, InputDataFolder));
            if (Directory.Exists(testProcedurePath))
            {
                LogFileTextBox.Text = Path.GetFullPath(Path.Combine(testProcedurePath, 
                        Directory.GetFiles(testProcedurePath, TestProcedureExtension)[0]));
                this.LogFileTextBox.Select(0, this.LogFileTextBox.Text.Length);
                this._Controller.LoadTestProcedure(LogFileTextBox.Text);
            }
            String testDataLogPath = Path.GetFullPath(Path.Combine(path, OutputDataFolder));
            if (Directory.Exists(testDataLogPath))
            {
                LogFolderTextBox.Text = testDataLogPath;
                this.LogFolderTextBox.Select(0, this.LogFolderTextBox.Text.Length);
            }

        }

        /// <summary>
        /// Set test controller
        /// </summary>
        /// <param name="cont">Test controller</param>
        public void setController(TestController cont) 
        {
            this._Controller = cont;
        }

        /// <summary>
        /// Empty handler
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="e">Agruments</param>
        private void timer1_Tick(object sender, EventArgs e)
        {

        }

        /// <summary>
        /// Close main GUI
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="e">Arguemnts</param>
        private void exitToolStripMenuItem_Click_1(object sender, EventArgs e)
        {
            this.Close();
        }
             
        /// <summary>
        /// Configuration menu
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void fTDIConfigurationToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //ftdi config menu - not implemented
        }
        
        /// <summary>
        /// Show closing window
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="e">Arguments</param>
        private void MainWnd_FormClosing(object sender, FormClosingEventArgs e)
        {
            
            DialogResult result = MessageBox.Show("Do you want to terminate currently opened connections and exit application?", "iSTP User Interface", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
            if (result == DialogResult.No)
            {
                e.Cancel = true;
            }
            else
            {
                _Controller.Dispose();
            }
            
        }
        
        /// <summary>
        /// Show/Hide logger window
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="e">Arguments</param>
        private void testLogWindowToolStripMenuItem_CheckedChanged(object sender, EventArgs e)
        {
            if (this.testLogWindowToolStripMenuItem.Checked == true)
            {
                MyConsole.Show(this);
                MainWnd_LocationChanged(this, null);
            }
            else
            {
                MyConsole.Hide();
            }
        }

        /// <summary>
        /// Move debugg and logger window together with main window
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="e">Arguments</param>
        private void MainWnd_LocationChanged(object sender, EventArgs e)
        {
            MyConsole.Location = new Point(this.Location.X + this.Width, this.Location.Y);
            this.MyDbgConsole.Location = new Point(this.Location.X - this.MyDbgConsole.Width, this.Location.Y);

            this.Activate();
        }

        /// <summary>
        /// Resize main GUI
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="e">Arguments</param>
        private void MainWnd_Resize(object sender, EventArgs e)
        {
            MainWnd_LocationChanged(this, null);
        }

        /// <summary>
        /// Show/Hide debugger window
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="e">Arguments</param>
        private void debugWindowToolStripMenuItem_CheckedChanged(object sender, EventArgs e)
        {
            if (this.debugWindowToolStripMenuItem.Checked == true)
            {
                this.MyDbgConsole.Show(this);
                MainWnd_LocationChanged(this, null);
            }
            else
            {
                this.MyDbgConsole.Hide();
            }
        }

        /// <summary>
        /// Show GUI for embedded configuration
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="e">Arguments</param>
        private void istpConfig_btn_Click(object sender, EventArgs e)
        {
            _Controller.ConfigureEmbedded();
        }

        /// <summary>
        /// Show data processing GUI
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="e">Arguments</param>
        private void dataProcSetup_btn_Click(object sender, EventArgs e)
        {
            if (LogFolderTextBox.Text == "")
            {
                if (DialogResult.OK == this.LogFolderBrowseDialog.ShowDialog())
                {
                    String FolderPath = this.LogFolderBrowseDialog.SelectedPath;
                    this.LogFolderTextBox.Text = FolderPath;
                    this.LogFolderTextBox.Select(0, this.LogFolderTextBox.Text.Length);
                    this._Controller.ConfigureProcessing();
                }
            }
            else
            {
                this._Controller.ConfigureProcessing();
            }
        }

        /// <summary>
        /// Start test
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="e">Arguments</param>
        private void startStop_btn_Click(object sender, EventArgs e)
        {
            this._Controller.StartStopTest();
        }
       
        /// <summary>
        /// Change state of main GUI based on test phase
        /// </summary>
        /// <param name="testRunning">State of test</param>
        /// <param name="status">Actual status</param>
        /// <param name="error">Trigger error alert</param>
        public void SetTestExecutionLook(bool testRunning, string status, bool error = false)
        {
            if (testRunning)
            {
                this.startStop_btn.Text = "STOP";
                this.connectionStatus.Text = status;
                this.TestProcGroupBox.Enabled = false;
                this.EmbPlatformGroupBox.Enabled = false;
                this.ClimaChGroupBox.Enabled = false;
                this.PressureGenGroupBox.Enabled = false;
                this.RateTableGroupBox.Enabled = false;
                this.DataProcGroupBox.Enabled = false;
                this.testLogWindowToolStripMenuItem.Checked = true;
            }
            else
            {
                startStop_btn.Invoke(new MethodInvoker(delegate { startStop_btn.Text = "START"; }));
                TestProcGroupBox.Invoke(new MethodInvoker(delegate { TestProcGroupBox.Enabled = true; }));
                EmbPlatformGroupBox.Invoke(new MethodInvoker(delegate { EmbPlatformGroupBox.Enabled = true; }));
                ClimaChGroupBox.Invoke(new MethodInvoker(delegate { ClimaChGroupBox.Enabled = true; }));
                PressureGenGroupBox.Invoke(new MethodInvoker(delegate { PressureGenGroupBox.Enabled = true; }));
                RateTableGroupBox.Invoke(new MethodInvoker(delegate { RateTableGroupBox.Enabled = true; }));
                DataProcGroupBox.Invoke(new MethodInvoker(delegate { DataProcGroupBox.Enabled = true; }));
                connectionStatus.Text = status;
            }
            if (error)
            {
                connectionStatus.Image = iSTP_Core.Properties.Resources.button_red;
            }
            else
            {
                connectionStatus.Image = iSTP_Core.Properties.Resources.button_green;
            }

        }

        /// <summary>
        /// Enable/Disable test start
        /// </summary>
        /// <param name="enable">Enable = TRUE</param>
        public void EnableTestStart(bool enable)
        {
            this.startStop_btn.Enabled = enable;
            if (!enable)
            {
                this.connectionStatus.Text = "Select test, configure required devices and data processing";
                this.connectionStatus.Image = iSTP_Core.Properties.Resources.button_yellow;
            }
            else
            {
                this.connectionStatus.Text = "Press Start to execute the test";
                this.connectionStatus.Image = iSTP_Core.Properties.Resources.button_green;
            }
        }
        /// <summary>
        /// Load user defined test
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="e">Arguments</param>
        private void TestLoadButton_Click(object sender, EventArgs e)
        {
            if (!String.IsNullOrEmpty(LogFileTextBox.Text))
            {
                if (Directory.Exists(Path.GetDirectoryName(LogFileTextBox.Text)))
                {
                    this.TestConfigFileSelect.InitialDirectory = Path.GetDirectoryName(LogFileTextBox.Text);
                }
            }

            if (DialogResult.OK == this.TestConfigFileSelect.ShowDialog())
            {
                Cursor.Current = Cursors.WaitCursor;

                String FileName = this.TestConfigFileSelect.FileName;
                if (this._Controller.LoadTestProcedure(FileName))
                {
                    this.LogFileTextBox.Text = FileName;
                    this.LogFileTextBox.Select(0, this.LogFileTextBox.Text.Length);
                }
                else 
                {
                    this.LogFileTextBox.Text = "Error loading test procedure!";
                }

            }
        }

        /// <summary>
        /// Update device status and change 'LED' color in GUI
        /// </summary>
        /// <param name="Device">Device type</param>
        /// <param name="Status">Its status</param>
        public void UpdateDeviceStatus(TestController.Device Device, TestController.DeviceStatus Status)
        {
            System.Windows.Forms.PictureBox picture;
            System.Windows.Forms.Label label;

            if(Device == TestController.Device.iSTPembeddedPlatform)
            {
                picture = iSTPconnectionStatusImage;
                label = iSTPconnectionStatusLabel;
            }
            else if (Device == TestController.Device.ClimaChamber) 
            {
                picture = pictureBox1;
                label = label2;
            }
            else if (Device == TestController.Device.PressureGen)
            {
                picture = pictureBox2;
                label = label3;
            }
            else
            {
                picture = pictureBox3;
                label = label4;
            }
            
            if (Status == TestController.DeviceStatus.NotConnected)
            {
                picture.Image = iSTP_Core.Properties.Resources.button_red;
                label.Text = "Disconnected, Not required.";
            }
            if (Status == TestController.DeviceStatus.Required) 
            {
                picture.Image = iSTP_Core.Properties.Resources.button_yellow;
                label.Text = "Please connect";
            }
            if (Status == TestController.DeviceStatus.Connected) 
            {
                picture.Image = iSTP_Core.Properties.Resources.button_green;
                label.Text = "Connected";
            }

        }

        /// <summary>
        /// Update progress bar
        /// </summary>
        /// <param name="percent">Current progress in percent</param>
        public void UpdateProgress(int percent)
        {
            if (progressBar1.InvokeRequired)
            {
                progressBar1.Invoke(new MethodInvoker(delegate { progressBar1.Value = (percent <= 100 ? percent : 100); }));
            }

        }

        /// <summary>
        /// Stop test
        /// </summary>
        public void TestStopped()
        {
            startStop_btn.Invoke(new MethodInvoker(delegate { startStop_btn.Text = "START"; }));
            
        }

        /// <summary>
        /// Show message to USER
        /// </summary>
        /// <param name="text">Test to  show</param>
        /// <param name="caption">Caption of window</param>
        /// <param name="buttons">Buttons combination</param>
        /// <param name="icon">Icon type</param>
        public void Message(String text, String caption, MessageBoxButtons buttons, MessageBoxIcon icon) 
        {
            MessageBox.Show(text, caption, buttons, icon);
        }

        /// <summary>
        /// Set end time and date of loaded test
        /// </summary>
        /// <param name="time">End time in seconds</param>
        public void setTotalTestTime(Int32 time)
        {
            TimeSpan t = TimeSpan.FromSeconds(time);
            this.label13.Text = string.Format("{0}d {1:D2}h {2:D2}m {3:D2}s", t.Days, t.Hours, t.Minutes, t.Seconds);
        }

        /// <summary>
        /// Update remainig  time
        /// </summary>
        /// <param name="time">Current time</param>
        public void setRemainingTestTime(Int32 time)
        {
            TimeSpan t = TimeSpan.FromSeconds(time);
            DateTime finish = DateTime.Now + t;
            this.label12.Invoke(new MethodInvoker(delegate { this.label12.Text = string.Format("{0}d {1:D2}h {2:D2}m {3:D2}s",t.Days, t.Hours, t.Minutes, t.Seconds); }));
            this.CompletionTime_lbl.Invoke(new MethodInvoker(delegate { this.CompletionTime_lbl.Text = finish.ToLocalTime().ToString(); }));
        }

        /// <summary>
        /// Set current received and lost packets
        /// </summary>
        /// <param name="recPackets">Total received packet</param>
        /// <param name="lostPackets">Total lost packet</param>
        public void setLogStats(uint recPackets, uint lostPackets)
        {
            this.recvStatLabel.Invoke(new MethodInvoker(delegate { this.recvStatLabel.Text = string.Format("{0}", recPackets);}));
            this.lostStatLabel.Invoke(new MethodInvoker(delegate { this.lostStatLabel.Text = lostPackets.ToString(); }));
        }

        /// <summary>
        /// Change current temperature and humidity from climatic chamber
        /// </summary>
        /// <param name="text">String with values</param>
        public void ChangeWeatherInfo(string text)
        {
            this.ClimaWeatherLbl.Invoke(new MethodInvoker(delegate { this.ClimaWeatherLbl.Text = text; }));
        }

        /// <summary>
        /// Change current temperature and humidity from climatic chamber
        /// </summary>
        /// <param name="temperature">Current temperature [Celsius]</param>
        /// <param name="humidity">Current humidity [%]</param>
        public void ChangeWeatherInfo(float temperature, float humidity)
        {
            string text = String.Format("Temp: {0:00.00}°C Humidity {1:00.00}%", temperature, humidity);
            this.ClimaWeatherLbl.Invoke(new MethodInvoker(delegate { this.ClimaWeatherLbl.Text = text; }));
        }

        /// <summary>
        /// Show climatic chamber configure window
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="e">Arguments</param>
        private void climaChConfig_btn_Click(object sender, EventArgs e)
        {
            _Controller.ConfigureClimaChamber();
        }

        /// <summary>
        /// Show pressure generator GUI
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="e">Arguments</param>
        private void pressureGenConfig_btn_Click(object sender, EventArgs e)
        {
            _Controller.ConfigurePressureGen();
        }

        /// <summary>
        /// Show rate table GUI
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="e">Arguments</param>
        private void rateTableConfig_btn_Click(object sender, EventArgs e)
        {
            _Controller.ConfigureRateTable();
        }

        /// <summary>
        /// Show dialog to find location for data
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="e">Arguments</param>
        private void LgoFolderBrowseButton_Click(object sender, EventArgs e)
        {
            if (!String.IsNullOrEmpty(LogFolderTextBox.Text))
            {
                if (Directory.Exists(Path.GetDirectoryName(LogFolderTextBox.Text)))
                {
                    this.LogFolderBrowseDialog.SelectedPath = Path.GetDirectoryName(LogFolderTextBox.Text);
                }
            }

            if (DialogResult.OK == this.LogFolderBrowseDialog.ShowDialog())
            {
                String FolderPath = this.LogFolderBrowseDialog.SelectedPath;
                if (FolderPath.Contains(' '))
                {
                    MessageBox.Show("Path contains space!!", "PATH ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }

                this.LogFolderTextBox.Text = FolderPath;
                this.LogFolderTextBox.Select(0, this.LogFolderTextBox.Text.Length);
                this._Controller.ConfigureProcessing();
            }
        }

        /// <summary>
        /// Gets destination for log data
        /// </summary>
        public string LogDestination
        { get { return LogFolderTextBox.Text; } }

        /// <summary>
        /// Gets Test controller
        /// </summary>
        /// <returns>Gets test controller</returns>
        public iSTP_ConsoleWnd GetConsole()
        {
 	       return MyConsole;
        }

        /// <summary>
        /// Gets debug logger
        /// </summary>
        /// <returns>Gets debug logger</returns>
        public DebugConsole GetDebugConsole()
        {
            return MyDbgConsole;
        }

        /// <summary>
        /// Show dialog window
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="e">Arguments</param>
        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AboutDlg aboutDlg = new AboutDlg();
            aboutDlg.ShowDialog();
        }

        /// <summary>
        /// Show window for control power supply
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="e">Arguments</param>
        private void powerSupplyToolStripMenuItem_Click(object sender, EventArgs e)
        {
            _Controller.ShowPowerSupplyControls();
        }

        /// <summary>
        /// Generates header for user defined test
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="e">Arguments</param>
        private void testProfileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            List<string> mem = new List<string>();
            foreach (string s in _Controller.GetCurrentModel.GetHeader_Platform())
                if (!mem.Contains(s))
                    mem.Add(s);

            DialogResult result = MessageBox.Show("Do you want headers for climatic chamber?", "Climatic chamber", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
            if(result == System.Windows.Forms.DialogResult.Yes)
                foreach (string s in _Controller.GetCurrentModel.GetHeader_ClimChamber())
                    if (!mem.Contains(s))
                        mem.Add(s);

            result = MessageBox.Show("Do you want headers for rate-table?", "Rate-table", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
            if (result == System.Windows.Forms.DialogResult.Yes)
                foreach (string s in _Controller.GetCurrentModel.GetHeader_RateTable())
                    if (!mem.Contains(s))
                        mem.Add(s);

            result = MessageBox.Show("Do you want headers for pressure generator?", "pressure generator", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
            if (result == System.Windows.Forms.DialogResult.Yes)
                foreach (string s in _Controller.GetCurrentModel.GetHeader_PressGen())
                    if (!mem.Contains(s))
                        mem.Add(s);

            string filename = Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + "TestProfile.csv";
            int i = 0;
            while (File.Exists(filename))
            {
                string[] parts = filename.Split('.');
                if (i == 0)
                {
                    parts[0] += ++i;
                    filename = string.Format("{0}.{1}", parts[0], parts[1]);
                }
                else
                {
                    char[] elements = parts[0].ToCharArray();
                    parts[0] = string.Empty;
                    for (int n = 0; n < elements.Length - 1; n++)
                        parts[0] += elements[n];
                    filename = string.Format("{0}{1}.{2}", parts[0], ++i, parts[1]);
                }     
            }

            iSTP_DataProcessing.CSVwriter wfile = new iSTP_DataProcessing.CSVwriter(File.Create(filename));
            wfile.WriteValue(string.Join(",", mem.ToArray()));
            wfile.BaseStream.Close();
            wfile.BaseStream = null;
            wfile = null;
        }

        /// <summary>
        /// Show Bug gialog window
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="e">Arguments</param>
        private void knownIssuesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            BugDlg bugDlg = new BugDlg();
            bugDlg.ShowDialog();
        }

        /// <summary>
        /// Show current pressure static and pitot
        /// </summary>
        /// <param name="p1">Current static pressure</param>
        /// <param name="p2">Current pitot pressure</param>
        internal void ChangePressureGeneratorInfo(float p1, float p2)
        {
            string text = String.Format("Act Static: {0:00.00} Act Pitot {1:00.00}", p1, p2);
            this.PressureInfoLbl.Invoke(new MethodInvoker(delegate { this.PressureInfoLbl.Text = text; }));
        }
    }
}
