using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;

namespace WheelchairControl
{
    /// <summary>
    /// Form used to set up MCU options.
    /// </summary>
    public partial class FormSettings : Form
    {
        #region Delegates

        /// <summary>
        /// Delegate of UART send method of parent form.
        /// </summary>
        /// <param name="data">Data array to be sent.</param>
        public delegate void UARTSend_Delegate(uint[] data); 

        #endregion

        #region Constants

        /// <summary>
        /// Stop command repeats.
        /// </summary>
        private const Byte STOP_REQUEST_REPEATS = 3;
        
        /// <summary>
        /// Command buffer data length.
        /// </summary>
        private const Byte RX_DATA_LENGTH = FormMain.RX_DATA_LENGTH;

        #endregion

        #region Private variables

        /// <summary>
        /// Singleton instance.
        /// </summary>
        private static FormSettings instance = null;

        /// <summary>
        /// Singleton instance access lock.
        /// </summary>
        private static Object singeltonLock = new Object();

        /// <summary>
        /// Parent form serial port.
        /// </summary>
        private SerialPort serialPort_formMain;

        /// <summary>
        /// Parent form UART send method deldegate. 
        /// </summary>
        private UARTSend_Delegate UARTSendMethod;

        #endregion

        /// <summary>
        /// Singleton constructor.
        /// </summary>
        /// <param name="formMainCOMPort">Com port reference.</param>
        /// <param name="SendMethod">UART send method reference.</param>
        private FormSettings(SerialPort formMainCOMPort, UARTSend_Delegate SendMethod)
        {
            serialPort_formMain = formMainCOMPort;
            UARTSendMethod = SendMethod;

            //Register handler
            FormMain.COMStatusChanged += delegate()
            {
                if (this.InvokeRequired)
                {
                    this.Invoke((MethodInvoker)delegate
                    {
                        FormSettings_Activated(this, null);
                    });
                }
                else
                {
                    FormSettings_Activated(this, null);
                }
            };

            InitializeComponent();
        }

        /// <summary>
        /// Singleton instance getter.
        /// </summary>
        /// <param name="formMainCOMPort">Com port reference.</param>
        /// <param name="sendMethod">UART send method reference.</param>
        /// <returns>Instance of form.</returns>
        public static FormSettings GetInstance(SerialPort formMainCOMPort, UARTSend_Delegate sendMethod)
        {
            //Prevent possible thread race
            lock (singeltonLock)
            {
                if (instance == null || instance.IsDisposed)   //Create new singleton instance
                    instance = new FormSettings(formMainCOMPort, sendMethod);
            }

            return instance;
        }

        private void buttonSaveSRFAddress_Click(object sender, EventArgs e)
        {
            UInt16 tempFront, tempRear;
            uint[] outputBuffer = new uint[RX_DATA_LENGTH - 1];

            tempFront = UInt16.Parse(textBoxSRF08_Front.Text, System.Globalization.NumberStyles.HexNumber);
            tempRear = UInt16.Parse(textBoxSRF08_Rear.Text, System.Globalization.NumberStyles.HexNumber);

            //Confirmation required
            if (MessageBox.Show("Set SRF08 addresses to 0x" + tempFront.ToString("X2") + " (front) and 0x" + tempRear.ToString("X2") + " (rear)?",
                                "Confirmation required!", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question) != DialogResult.Yes)
            {
                tsslInfo.Text = "Addresses not set.";
                    
                return;
            }

            if (tempFront < 0xE0 || tempFront > 0xE8 || tempRear < 0xE0 || tempRear > 0xE8) //Address out of range
            {
                MessageBox.Show("Only addresses 0xE0 - 0xE8 allowed!", "Warning!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            else
            {
                outputBuffer[0] = 0xE9;
                outputBuffer[1] = tempFront;
                outputBuffer[2] = tempRear;
                UARTSendMethod(outputBuffer);
            }

            tsslInfo.Text = "Front SRF08 address set to: 0x" + tempFront.ToString("X2") + " , rear SRF08 address set to: 0x" + tempRear.ToString("X2");
        }

        private void button1_Click_1(object sender, EventArgs e)
        {
            UInt16 tempRight, tempLeft;
            uint[] outputBuffer = new uint[RX_DATA_LENGTH - 1];

            tempRight = Convert.ToUInt16(textBoxIPMS_Right.Text);
            tempLeft = Convert.ToUInt16(textBoxIMPS_Left.Text);

            if (tempRight < 0 || tempRight > 510 || tempLeft < 0 || tempLeft > 510) //Address out of range
            {
                MessageBox.Show("Only values 0 - 510 allowed!", "Warning!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            else
            {
                //Transmit data (divided by 2 before transmission to keep 8-bit resolution)
                outputBuffer[0] = 0xE3;
                outputBuffer[1] = (byte)(tempRight / 2);
                outputBuffer[2] = (byte)(tempLeft / 2);
                UARTSendMethod(outputBuffer);
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            UInt16 temp;
            uint[] outputBuffer = new uint[RX_DATA_LENGTH - 1];

            temp = Convert.ToUInt16(textBoxValueToSet.Text);

            if (temp < 0 || temp > 10) //out of range
            {
                MessageBox.Show("Only values 0 - 10 allowed!", "Warning!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            else
            {
                outputBuffer[0] = 0xE5;
                outputBuffer[1] = 0x00;
                outputBuffer[2] = temp;
                UARTSendMethod(outputBuffer);
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {
            UInt16 temp;
            uint[] outputBuffer = new uint[RX_DATA_LENGTH - 1];

            temp = Convert.ToUInt16(textBoxValueToSet.Text);

            if (temp < 0 || temp > 255) //out of range
            {
                MessageBox.Show("Only values 0 - 255 allowed!", "Warning!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            else
            {
                outputBuffer[0] = 0xE6;
                outputBuffer[1] = 0x00;
                outputBuffer[2] = temp;
                UARTSendMethod(outputBuffer);
            }
        }

        private void button4_Click(object sender, EventArgs e)
        {
            UInt16 temp;
            uint[] outputBuffer = new uint[RX_DATA_LENGTH - 1];

            temp = Convert.ToUInt16(textBoxValueToSet.Text);

            if (temp < 0 || temp > 255) //out of range
            {
                MessageBox.Show("Only values 0 - 255 allowed!", "Warning!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            else
            {
                outputBuffer[0] = 0xE7;
                outputBuffer[1] = 0x00;
                outputBuffer[2] = temp;
                UARTSendMethod(outputBuffer);
            }
        }

        private void button5_Click(object sender, EventArgs e)
        {
            UInt16 temp;
            uint[] outputBuffer = new uint[RX_DATA_LENGTH - 1];

            temp = Convert.ToUInt16(textBoxValueToSet.Text);

            if (temp < 0 || temp > 255) //out of range
            {
                MessageBox.Show("Only values 0 - 255 allowed!", "Warning!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            else
            {
                outputBuffer[0] = 0xE8;
                outputBuffer[1] = 0x00;
                outputBuffer[2] = temp;
                UARTSendMethod(outputBuffer);
            }
        }

        private void button6_Click(object sender, EventArgs e)
        {
            UInt16 temp;
            uint[] outputBuffer = new uint[RX_DATA_LENGTH - 1];

            temp = Convert.ToUInt16(textBoxValueToSet.Text);

            if (temp < 0 || temp > 255) //out of range
            {
                MessageBox.Show("Only values 0 - 255 allowed!", "Warning!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            else
            {
                outputBuffer[0] = 0xEA;
                outputBuffer[1] = 0x00;
                outputBuffer[2] = temp;
                UARTSendMethod(outputBuffer);
            }
        }

        private void button7_Click(object sender, EventArgs e)
        {
            UInt16 temp;
            uint[] outputBuffer = new uint[RX_DATA_LENGTH - 1];

            temp = Convert.ToUInt16(textBoxValueToSet.Text);

            if (temp < 0 || temp > 255) //out of range
            {
                MessageBox.Show("Only values 0 - 255 allowed!", "Warning!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            else
            {
                outputBuffer[0] = 0xEB;
                outputBuffer[1] = 0x00;
                outputBuffer[2] = temp;
                UARTSendMethod(outputBuffer);
            }
        }

        private void button9_Click(object sender, EventArgs e)
        {
            UInt16 temp;
            uint[] outputBuffer = new uint[RX_DATA_LENGTH - 1];

            temp = Convert.ToUInt16(textBoxValueToSet.Text);

            if (temp < 0 || temp > 255) //out of range
            {
                MessageBox.Show("Only values 0 - 255 allowed!", "Warning!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            else
            {
                outputBuffer[0] = 0xEC;
                outputBuffer[1] = 0x00;
                outputBuffer[2] = temp;
                UARTSendMethod(outputBuffer);
            }
        }

        private void button10_Click(object sender, EventArgs e)
        {
            UInt16 temp;
            uint[] outputBuffer = new uint[RX_DATA_LENGTH - 1];

            temp = Convert.ToUInt16(textBoxValueToSet.Text);

            if (temp < 0 || temp > 255) //out of range
            {
                MessageBox.Show("Only values 0 - 255 allowed!", "Warning!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            else
            {
                outputBuffer[0] = 0xED;
                outputBuffer[1] = 0x00;
                outputBuffer[2] = temp;
                UARTSendMethod(outputBuffer);
            }
        }

        private void button14_Click(object sender, EventArgs e)
        {
            UInt16 temp;
            uint[] outputBuffer = new uint[RX_DATA_LENGTH - 1];

            temp = Convert.ToUInt16(textBoxValueToSet.Text);

            if (temp < 0 || temp > 255) //out of range
            {
                MessageBox.Show("Only values 0 - 255 allowed!", "Warning!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            else
            {
                outputBuffer[0] = 0xE2;
                outputBuffer[1] = 0x00;
                outputBuffer[2] = temp;
                UARTSendMethod(outputBuffer);
            }
        }

        private void button13_Click(object sender, EventArgs e)
        {
            UInt16 temp;
            uint[] outputBuffer = new uint[RX_DATA_LENGTH - 1];

            temp = Convert.ToUInt16(textBoxValueToSet.Text);

            if (temp < 0 || temp > 65535) //out of range
            {
                MessageBox.Show("Only values 0 - 65535 allowed!", "Warning!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            else
            {
                outputBuffer[0] = 0xE1;
                outputBuffer[1] = (uint)temp >> 8;
                outputBuffer[2] = (uint)temp % 256;
                UARTSendMethod(outputBuffer);
            }
        }

        private void button12_Click(object sender, EventArgs e)
        {
            UInt16 temp;
            uint[] outputBuffer = new uint[RX_DATA_LENGTH - 1];

            temp = Convert.ToUInt16(textBoxValueToSet.Text);

            if (temp < 0 || temp > 65535) //out of range
            {
                MessageBox.Show("Only values 0 - 65535 allowed!", "Warning!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            else
            {
                outputBuffer[0] = 0xE0;
                outputBuffer[1] = (uint)temp >> 8;
                outputBuffer[2] = (uint)temp % 256;
                UARTSendMethod(outputBuffer);
            }
        }

        private void button15_Click(object sender, EventArgs e)
        {
            UInt16 temp;
            uint[] outputBuffer = new uint[RX_DATA_LENGTH - 1];

            temp = Convert.ToUInt16(textBoxValueToSet.Text);

            if (temp < 0 || temp > 255) //out of range
            {
                MessageBox.Show("Only values 0 - 255 allowed!", "Warning!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            else
            {
                outputBuffer[0] = 0xEE;
                outputBuffer[1] = 0x00;
                outputBuffer[2] = temp;
                UARTSendMethod(outputBuffer);
            }
        }

        private void button16_Click(object sender, EventArgs e)
        {
            Int16 temp;
            uint[] outputBuffer = new uint[RX_DATA_LENGTH - 1];

            temp = Convert.ToInt16(textBoxValueToSet.Text);

            if (temp < -128 || temp > 127) //out of range
            {
                MessageBox.Show("Only values 0 - 255 allowed!", "Warning!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            else
            {
                outputBuffer[0] = 0xEF;
                outputBuffer[1] = 0x00;
                outputBuffer[2] = (byte)(temp + 128);
                UARTSendMethod(outputBuffer);
            }
        }

        private void buttonSTOP_Click(object sender, EventArgs e)
        {
            uint[] outputBuffer = new uint[RX_DATA_LENGTH - 1];

            for (int i = 0; i < STOP_REQUEST_REPEATS; i++)    //Send multiple times, just for sure
            {
                outputBuffer[0] = 0xC4;   //Send stop (128 = zero moment)
                outputBuffer[1] = 128;
                outputBuffer[2] = 128;
                UARTSendMethod(outputBuffer);
            }

            tsslInfo.Text = "STOP signal has been sent.";
        }

        private void FormSettings_Activated(object sender, EventArgs e)
        {
            //Com port status info & controls enable
            if (serialPort_formMain.IsOpen)
            {
                tssLabelComPortState.Text = "COM Port Status: OPEN";

                //Enable buttons
                foreach (Control controlItem in this.Controls)
                    controlItem.Enabled = true;
            }
            else
            {
                tssLabelComPortState.Text = "COM Port Status: CLOSED";
                tsslInfo.Text = "Port closed, controls are disabled!";

                //Disable buttons (leave status strip enabled)
                foreach (Control controlItem in this.Controls)
                    if (controlItem.GetType() != typeof(StatusStrip))
                        controlItem.Enabled = false;
            }
        }

        private void buttonGamma_Click(object sender, EventArgs e)
        {
            UInt16 temp;
            uint[] outputBuffer = new uint[RX_DATA_LENGTH - 1];

            temp = Convert.ToUInt16(textBoxValueToSet.Text);

            if (temp < 0 || temp > 255) //out of range
            {
                MessageBox.Show("Only values 0 - 255 allowed!", "Warning!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            else
            {
                outputBuffer[0] = 0xD2;
                outputBuffer[1] = 0x00;
                outputBuffer[2] = temp;
                UARTSendMethod(outputBuffer);
            }
        }

        private void buttonEpsilon_Click(object sender, EventArgs e)
        {
            UInt16 temp;
            uint[] outputBuffer = new uint[RX_DATA_LENGTH - 1];

            temp = Convert.ToUInt16(textBoxValueToSet.Text);

            if (temp < 0 || temp > 255) //out of range
            {
                MessageBox.Show("Only values 0 - 255 allowed!", "Warning!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            else
            {
                outputBuffer[0] = 0xD3;
                outputBuffer[1] = 0x00;
                outputBuffer[2] = temp;
                UARTSendMethod(outputBuffer);
            }
        }

        private void buttonAngleGain_Click(object sender, EventArgs e)
        {
            UInt16 temp;
            uint[] outputBuffer = new uint[RX_DATA_LENGTH - 1];

            temp = Convert.ToUInt16(textBoxValueToSet.Text);

            if (temp < 0 || temp > 255) //out of range
            {
                MessageBox.Show("Only values 0 - 255 allowed!", "Warning!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            else
            {
                outputBuffer[0] = 0xD4;
                outputBuffer[1] = 0x00;
                outputBuffer[2] = temp;
                UARTSendMethod(outputBuffer);
            }
        }

        private void buttonPositionGain_Click(object sender, EventArgs e)
        {
            UInt16 temp;
            uint[] outputBuffer = new uint[RX_DATA_LENGTH - 1];

            temp = Convert.ToUInt16(textBoxValueToSet.Text);

            if (temp < 0 || temp > 255) //out of range
            {
                MessageBox.Show("Only values 0 - 255 allowed!", "Warning!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            else
            {
                outputBuffer[0] = 0xD5;
                outputBuffer[1] = 0x00;
                outputBuffer[2] = temp;
                UARTSendMethod(outputBuffer);
            }
        }

        private void buttonRegSpeed_Click(object sender, EventArgs e)
        {
            UInt16 temp;
            uint[] outputBuffer = new uint[RX_DATA_LENGTH - 1];

            temp = Convert.ToUInt16(textBoxValueToSet.Text);

            if (temp < 0 || temp > 255) //out of range
            {
                MessageBox.Show("Only values 0 - 255 allowed!", "Warning!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            else
            {
                outputBuffer[0] = 0xD6;
                outputBuffer[1] = 0x00;
                outputBuffer[2] = temp;
                UARTSendMethod(outputBuffer);
            }
        }

        private void buttonSaveSRF08SafetyAddr_Click(object sender, EventArgs e)
        {
            UInt16 tempFront, tempRear;
            uint[] outputBuffer = new uint[RX_DATA_LENGTH - 1];

            tempFront = UInt16.Parse(textBoxSRF08_Front.Text, System.Globalization.NumberStyles.HexNumber);
            tempRear = UInt16.Parse(textBoxSRF08_Rear.Text, System.Globalization.NumberStyles.HexNumber);

            //Confirmation required
            if (MessageBox.Show("Set SRF08 safety addresses to 0x" + tempFront.ToString("X2") + " (safety 1) and 0x" + tempRear.ToString("X2") + " (safety 2)?",
                                "Confirmation required!", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question) != DialogResult.Yes)
            {
                tsslInfo.Text = "Addresses not set.";

                return;
            }

            if (tempFront < 0x00 || tempFront > 0xFF || tempRear < 0x00 || tempRear > 0xFF) //Address out of range
            {
                MessageBox.Show("Only addresses 0x00 - 0xFF allowed!", "Warning!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            else
            {
                outputBuffer[0] = 0xE4;
                outputBuffer[1] = tempFront;
                outputBuffer[2] = tempRear;
                UARTSendMethod(outputBuffer);
            }

            tsslInfo.Text = "Safety 1 SRF08 address set to: 0x" + tempFront.ToString("X2") + " , safety 2 SRF08 address set to: 0x" + tempRear.ToString("X2");
        }
    }
}
