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.Collections;
using System.Text.RegularExpressions;

namespace UZVAS
{
    public delegate void StringDelegate(string s);

    public partial class MainForm : Form
    {
        private FT2232 device;
        private string selectedText;
        private string InputBuffer;
        private double[] velocities = new double[6];
        private int[] offset = new int[12];
        private int[] actualData = new int[12];
        private FormDataSet frm = null;

        public MainForm()
        {
            InitializeComponent();
        }

        private string Now()
        {
            return DateTime.Now.ToLongTimeString();
        }

        private void Log(string s)
        {
            listBoxLog.Items.Add(Now() + " " + s);
            listBoxLog.SelectedIndex = listBoxLog.Items.Count - 1;
        } 

        private void MainForm_Load(object sender, EventArgs e)
        {
            this.OnResize(null);
            Log("Application started");
        }

        private void buttonConnect_Click(object sender, EventArgs e)
        {
            if(selectedText[0] != '_')
                return;
            int index = listBoxLog.SelectedIndices[0] - 2;
            try
            {
                device = new FT2232(index);
                device.OnRead += new OnReadHandler(device_OnRead);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Connection error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private bool CheckCS(string input, byte pchsum)
        {
            byte chsum = 0;
            for(int i = 0; i < input.Length; i++)
            {
                byte c = (byte)input[i];
                chsum += (byte)input[i];
            }
            return (chsum == pchsum);
        }

        private void newData(int[] times)
        {
            string logData = "";
            for (int i = 0; i < times.Length; i++)
                logData += times[i].ToString() + " ";
            Log(logData);
            
            double t = 0;
            if(!Double.TryParse(textBoxTimec.Text,out t))
                return;

          //  t *= Math.Pow(10, -6);
            double[] d = new double[12];
            for(int i = 0; i < d.Length; i++)
                d[i] = 1 / (times[i] * t);

            double d03 = d[2] - d[5];
            double d12 = d[8] - d[11];

            double d01 = d[1] - d[6];
            double d02 = d[0] - d[9];
            double d31 = d[7] - d[4];
            double d32 = d[10] - d[3];

            double k =  (1 / 2f) * (double)numericPathLength.Value * Math.Pow(10, 4);

            velocities[0] = d03 * k;
            velocities[1] = d12 * k;
            velocities[2] = d01 * k;
            velocities[3] = d02 * k;
            velocities[4] = d32 * k;
            velocities[5] = d31 * k;

            groupBoxVector.Refresh();
            groupBoxVelocities.Refresh();
           
        }

        private void readData(string buffer)
        {
            // message _0XXXX1XXXX2XXXX3XXXX4XXXX5XXXX6XXXX7XXXX8XXXX9XXXXaXXXXbXXXXcXXXXCC_ 
      
            if (buffer == "_E_")
            {
                Log("Measuring mismatch");
                return;
            }

            if (buffer.Length == 64)
            {
                int[] values = new int[12];
                string schecksum = buffer.Substring(61, 2);
                byte checksum = byte.Parse(schecksum,System.Globalization.NumberStyles.HexNumber);
                if (CheckCS(buffer.Substring(1, 60), (byte)checksum))
                {
                    for (int i = 0; i < values.Length; i++)
                    {
                        string svalue = buffer.Substring(2 + i * 5, 4);
                        values[i] = int.Parse(svalue, System.Globalization.NumberStyles.HexNumber);
                        actualData[i] = values[i];
                        values[i] += offset[i];
                    }
                    if (frm != null)
                        if (frm.writing)
                            frm.AddRow(values);

                    newData(values);
                }
                else
                    Log("Checksum failed");

            }
            else
                Log("Communication mismatch");

        }

        void device_OnRead(string buffer)
        {
            listBoxLog.Invoke(new StringDelegate(device_OnReadInvoked), buffer);
        }

        void device_OnReadInvoked(string buffer)
        {
            if (buffer == "Communication started")
            {
                Log("Communication started");
                buttonMeasure.Enabled = true;
                return;
            }
            InputBuffer += buffer;
            string splitters = "ZZSS";
            string[] data = Regex.Split(InputBuffer, splitters); // choose relevant strings
            InputBuffer = "";
            for(int i = 0; i < data.Length; i++)
            {
                string d = data[i];
                if (d == "") continue;
               
                if ((d[0] == '_') && (d[d.Length - 1] == '_'))
                    readData(d);
                else
                    InputBuffer = d;
            }
        }

        private void timerConnecting_Tick(object sender, EventArgs e)
        {
            string[] devices = FT2232.getList();
            if (devices == null)
            {
                return;
            }
            Log(devices.Length.ToString() + " devices found");
            foreach (string s in devices)
                listBoxLog.Items.Add("_" + s);
            Log("*********************************");
            timerConnecting.Enabled = false;
        }

        private void buttonMeasure_Click(object sender, EventArgs e)
        {
            device.WriteByte('r');
        }

        private void groupBoxVelocities_Paint(object sender, PaintEventArgs e)
        {
            int centerX = groupBoxVelocities.Width / 2;
            int centerY = groupBoxVelocities.Height / 2;
            int d = (int)(groupBoxVelocities.Width / 1.5f);
            int d2 = d / 2;

            Point[] p = new Point[4];
            p[0] = new Point(centerX, centerY - d2);
            p[1] = new Point(centerX, centerY + d2);
            p[2] = new Point(centerX - d2, centerY);
            p[3] = new Point(centerX + d2, centerY);


            foreach (Point po in p)
            {
                e.Graphics.FillEllipse(new SolidBrush(Color.Red), po.X - 3, po.Y - 3, 6, 6);
                foreach (Point pi in p)
                    e.Graphics.DrawLine(new Pen(Color.LightGray), po, pi);
            }

            e.Graphics.FillPie(new SolidBrush(Color.LightGray), p[0].X + 1, p[0].Y + 1, 5, 5, 0, 360);
            e.Graphics.FillPie(new SolidBrush(Color.LightGray), p[0].X - 3, p[0].Y + 1, 5, 5, 0, 360);
            e.Graphics.FillPie(new SolidBrush(Color.LightGray), p[0].X - 6, p[0].Y + 1, 5, 5, 0, 360);

            e.Graphics.FillPie(new SolidBrush(Color.LightGray), p[3].X - 7, p[3].Y - 3, 5, 5, 0, 360);
            e.Graphics.FillPie(new SolidBrush(Color.LightGray), p[3].X - 5, p[3].Y + 2, 5, 5, 0, 360);

            e.Graphics.FillPie(new SolidBrush(Color.LightGray), p[2].X + 1, p[2].Y + 1, 5, 5, 0, 360);

            e.Graphics.DrawString(string.Format("{0:0.00e+0}", velocities[0]), new Font("Arial", 8), new SolidBrush(Color.Black), new PointF(centerX, centerY - 25));
            e.Graphics.DrawString(string.Format("{0:0.00e+0}", velocities[1]), new Font("Arial", 8), new SolidBrush(Color.Black), new PointF(centerX - 30, centerY));
            e.Graphics.DrawString(string.Format("{0:0.00e+0}", velocities[2]), new Font("Arial", 8), new SolidBrush(Color.Black), new PointF(centerX - d2 / 2 - 20, centerY + d2 / 2));
            e.Graphics.DrawString(string.Format("{0:0.00e+0}", velocities[3]), new Font("Arial", 8), new SolidBrush(Color.Black), new PointF(centerX + d2 / 2 + 2, centerY + d2 / 2));
            e.Graphics.DrawString(string.Format("{0:0.00e+0}", velocities[4]), new Font("Arial", 8), new SolidBrush(Color.Black), new PointF(centerX + d2 / 2 + 2, centerY - d2 / 2 - 8));
            e.Graphics.DrawString(string.Format("{0:0.00e+0}", velocities[5]), new Font("Arial", 8), new SolidBrush(Color.Black), new PointF(centerX - d2 / 2 - 20, centerY - d2 / 2 - 8));
        }

        private void MainForm_Resize(object sender, EventArgs e)
        { 
            groupBoxVelocities.Width = this.Width / 3;
            groupBoxVector.Width = groupBoxVelocities.Width;
        }

        private void listBoxLog_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (listBoxLog.SelectedItems.Count == 0) return;
            selectedText = listBoxLog.SelectedItem.ToString(); // trim time
            buttonConnect.Enabled = (selectedText[0] == '_');
        }

        private void listBoxLog_DoubleClick(object sender, EventArgs e)
        {
            buttonConnect_Click(null, null);
        }

        private void label7_Click(object sender, EventArgs e)
        {

        }

        private void groupBoxVector_Paint(object sender, PaintEventArgs e)
        {
            // cos(a) = y/v;
            // y = cos(45).v;
            // x = sin(45).v;
            // sin(45) = cos(45) = 1/sqrt(2);

            double d = 1/Math.Sqrt(2);

            int size = (groupBoxVector.Width < groupBoxVector.Height) ? groupBoxVector.Width : groupBoxVector.Height;
            int centerX = size / 2;
            int centerY = size / 2;
         
            e.Graphics.DrawLine(new Pen(Color.Gray), 0, centerY, size, centerY);
            e.Graphics.DrawLine(new Pen(Color.Gray), centerX, 10, centerX, size);
            
            e.Graphics.DrawLine(new Pen(Color.LightGray), 10, 10, size, size);
            e.Graphics.DrawLine(new Pen(Color.LightGray), size-10, 10, 0, size);

            double maxvel = 0;
            foreach (double v in velocities)
                if (Math.Abs(v) > Math.Abs(maxvel))
                    maxvel = Math.Abs(v);

            // zoom is rounded 
            double zoom = centerX / (1.3*(double)maxvel);
            zoom = Math.Floor(zoom);
            zoom -= zoom % 10;

            Pen pen = new Pen(Color.Gray);
            pen.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
           
            if (maxvel != 0) 
            {
                e.Graphics.DrawLine(new Pen(Color.Black), centerX - 3, centerY - (int)(velocities[0] * zoom), centerX + 3, centerY - (int)(velocities[0] * zoom));
                e.Graphics.DrawLine(new Pen(Color.Black), centerX + (int)(velocities[1] * zoom), centerY - 3, centerX + (int)(velocities[1] * zoom), centerY + 3);

                double velY2 = (velocities[3] > velocities[5]) ? velocities[3] * zoom : velocities[5]* zoom;
                double velY2xy = velY2 * d;
                e.Graphics.DrawLine(new Pen(Color.Gray), centerX + (int)(velY2xy) - 2, centerY - (int)(velY2xy) - 2,centerX + (int)(velY2xy) + 2, centerY - (int)(velY2xy) + 2);
                double velX2 = (velocities[2] > velocities[4]) ? velocities[2] * zoom : velocities[4] * zoom;
                double velX2xy = velX2 * d;
                e.Graphics.DrawLine(new Pen(Color.Gray), centerX - (int)(velX2xy) - 2, centerY - (int)(velX2xy) + 2, centerX - (int)(velX2xy) + 2, centerY - (int)(velX2xy) - 2);

                pen.Color = Color.Green;
                e.Graphics.DrawLine(pen, centerX, centerY, (int)(centerX + velocities[1] * zoom), (int)(centerY - velocities[0] * zoom));

                double alfa = Math.Atan2(velX2,velY2);
                alfa += (45 * (Math.PI / (double)180));
         
                double V2 = Math.Sqrt(Math.Pow(velX2,2) + Math.Pow(velY2,2));

                double X2 = V2 * Math.Cos(alfa);
                double Y2 = V2 * Math.Sin(alfa);

                pen.Color = Color.Blue;
                e.Graphics.DrawLine(pen, centerX, centerY, (int)(centerX + X2), (int)(centerY - Y2));

                double X = velocities[1] * zoom;
                double Y = velocities[0] * zoom;


                double finalX = (X + X2) / (double)2;
                double finalY = (Y + Y2) / (double)2;

                pen.Color = Color.Red;
                pen.Width = 3;
                e.Graphics.DrawLine(pen, centerX, centerY, (int)(centerX + finalX), (int)(centerY - finalY));
                pen.Width = 1;

                double finalV = Math.Sqrt(Math.Pow(finalX, 2) + Math.Pow(finalY, 2));
                double finalA = Math.Atan2(finalY, finalX) * (180 / Math.PI);

                finalV /= zoom;
                if (finalA < 0) finalA += 360;

                e.Graphics.DrawString("Velocitiy: " + finalV.ToString(), new Font("Arial",10), new SolidBrush(Color.Black), 10, 2 * centerY + 20);
                e.Graphics.DrawString("Angle: " + finalA.ToString(), new Font("Arial", 10), new SolidBrush(Color.Black), 10, 2 * centerY + 20 + 15); 

            }
            
          
        }

        private void buttonXML_Click(object sender, EventArgs e)
        {
            frm = new FormDataSet();
            frm.Show();
        }

        private void buttonOffset_Click(object sender, EventArgs e)
        {
            int d03 = (actualData[2] + actualData[5]) / 2;
            int d12 = (actualData[8] + actualData[11]) / 2;

            int d01 = (actualData[1] + actualData[6]) / 2;
            int d02 = (actualData[0] + actualData[9]) / 2;
            int d31 = (actualData[4] + actualData[7]) / 2;
            int d32 = (actualData[3] + actualData[10]) / 2;

            offset[2] = d03 - actualData[2];
            offset[5] = d03 - actualData[5];
            offset[8] = d12 - actualData[8];
            offset[11] = d12 - actualData[11];
            offset[1] = d01 - actualData[1];
            offset[6] = d01 - actualData[6];
            offset[0] = d02 - actualData[0];
            offset[9] = d02 - actualData[9];
            offset[4] = d31 - actualData[4];
            offset[7] = d31 - actualData[7];
            offset[3] = d32 - actualData[3];
            offset[10] = d32 - actualData[10];


        }
    }
}
