using System;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.IO;
using System.Diagnostics;
using System.Windows.Forms.DataVisualization.Charting;
using System.Runtime.InteropServices;
using System.Net;

namespace WindowsFormsApp1
{
  public partial class MainForm : Form
  {
    public MainForm()
    {
      InitializeComponent();

      foreach (var s in chart_Graph.Series) s.XValueType = ChartValueType.DateTime;
      chart_Graph.ChartAreas[0].AxisX.LabelStyle.Format = "mm:ss";

      chart_Graph.ChartAreas[0].AxisX.Minimum = DateTime.Now.ToOADate();
      chart_Graph.ChartAreas[0].AxisX.Maximum = DateTime.Now.AddSeconds(trackBar_GraphX_Down.Value).ToOADate();
      chart_Graph.ChartAreas[0].AxisX.IntervalAutoMode = IntervalAutoMode.FixedCount;
      chart_Graph.ChartAreas[0].AxisX.Interval = (new DateTime(1, 1, 1, 0, 0, 1)).ToOADate();

    }

    private const int RecvCount = 4;
    private byte[] RecvData = new byte[RecvCount];
    private int RecvSize = 0;

    private enum RecvModeEnum : byte { Begin, Data, Done };

    private int TimerStop = 0;

    private DateTime GraphLast = DateTime.Now;

    private RecvModeEnum RecvMode;

    private void DrawGraph(byte[] data, int from, int size)
    {
      if (checkBox_Track.Checked)
      {
        chart_Graph.ChartAreas[0].AxisX.Minimum = DateTime.Now.AddSeconds(-trackBar_GraphX_Down.Value).ToOADate();
        chart_Graph.ChartAreas[0].AxisX.Maximum = DateTime.Now.ToOADate();
      }
      else
      {
        TimeSpan shift = DateTime.Now.Subtract(GraphLast);
        if (shift.TotalSeconds > trackBar_GraphX_Down.Value)
        {
          GraphLast = DateTime.Now;
          for (int a = 0; a < chart_Graph.Series.Count; a++) chart_Graph.Series[a].Points.Clear();
          chart_Graph.ChartAreas[0].AxisX.Minimum = DateTime.Now.ToOADate();
          chart_Graph.ChartAreas[0].AxisX.Maximum = DateTime.Now.AddSeconds(trackBar_GraphX_Down.Value).ToOADate();
        }
      }

      float[] lines = new float[1];
      Buffer.BlockCopy(data, from, lines, 0, size);

      chart_Graph.Series[0].Points.AddXY(DateTime.Now, lines[0]);

      if (checkBox_Track.Checked)
      {
        while (true)
        {
          if ((DateTime.Now - DateTime.FromOADate(chart_Graph.Series[0].Points[0].XValue)).TotalSeconds > trackBar_GraphX_Down.Value + 1)
            chart_Graph.Series[0].Points.RemoveAt(0);
          else break;
        }
      }
    }

    private void button_Connect_Click(object sender, EventArgs e)
    {
      if (button_Connect.Text == "Connect")
      {
        try { serialPort_COM.PortName = comboBox_Port.Text; } catch { MessageBox.Show("Error to set port", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; }
        try
        { 
          serialPort_COM.Open();
          serialPort_COM.DiscardInBuffer();
        } 
        catch { MessageBox.Show("Error to connect", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; }
     
        timer_Tick.Enabled = true;
        button_Connect.Text = "Disonnect";
      }
      else
      {
        serialPort_COM.Close();
        timer_Tick.Enabled = false;
        button_Connect.Text = "Connect";
      }
    }

    private void timer_Tick_Tick(object sender, EventArgs e)
    {
      switch (RecvMode)
      {
        case RecvModeEnum.Begin:
          {
            TimerStop = 20;

            byte[] recv = new byte[1];
            int len;
            try { len = serialPort_COM.Read(recv, 0, 1); } catch { break; }
            if (recv[0] == 'Z')
            {
              RecvMode = RecvModeEnum.Data;
            }
            break;
          }

        case RecvModeEnum.Data:
          {
            int len;
            try { len = serialPort_COM.Read(RecvData, RecvSize, RecvData.Length - RecvSize); } catch { break; }
            RecvSize += len;
            if (RecvSize < RecvData.Length) break;
            RecvSize = 0;            

            DrawGraph(RecvData, 0, RecvData.Length);
            RecvMode = RecvModeEnum.Begin;
            break;
          }

        default:
          {
            RecvMode = RecvModeEnum.Begin;
            break;
          }
      }
      TimerStop--;
      if (TimerStop <= 0)
      {
        RecvMode = RecvModeEnum.Begin;
      }
    }

    private void comboBox_Port_DropDown(object sender, EventArgs e)
    {
      comboBox_Port.Items.Clear();
      foreach (string p in SerialPort.GetPortNames()) comboBox_Port.Items.Add(p);
    }

    private void numericUpDown_Min_ValueChanged(object sender, EventArgs e)
    {
      trackBar_GraphX_Down.Maximum = (int)numericUpDown_Min.Value;
      if (sender == numericUpDown_Min) trackBar_GraphX_Down.Value = trackBar_GraphX_Down.Maximum;
      else foreach (var s in chart_Graph.Series) s.Points.Clear();
      GraphLast = DateTime.Now;
      chart_Graph.ChartAreas[0].AxisX.Minimum = DateTime.Now.ToOADate();
      chart_Graph.ChartAreas[0].AxisX.Maximum = DateTime.Now.AddSeconds(trackBar_GraphX_Down.Value).ToOADate();
      chart_Graph.ChartAreas[0].AxisX.Interval = (new DateTime(1, 1, 1, 0, 0, 0).AddSeconds(((double)trackBar_GraphX_Down.Value) / 10)).ToOADate();
      if (trackBar_GraphX_Down.Value < 10) chart_Graph.ChartAreas[0].AxisX.LabelStyle.Format = "mm:ss.f";
      else chart_Graph.ChartAreas[0].AxisX.LabelStyle.Format = "mm:ss";
    }

    private void numericUpDown_Graph_MaxY_ValueChanged(object sender, EventArgs e)
    {
      chart_Graph.ChartAreas[0].AxisY.Minimum = (double)numericUpDown_Graph_MinY.Value;
      chart_Graph.ChartAreas[0].AxisY.Maximum = (double)numericUpDown_Graph_MaxY.Value;
      trackBar_GraphY_Left.Maximum = (int)numericUpDown_Graph_MaxY.Value;
      trackBar_GraphY_Left.Minimum = (int)numericUpDown_Graph_MinY.Value;
      trackBar_GraphY_Right.Maximum = (int)numericUpDown_Graph_MaxY.Value;
      trackBar_GraphY_Right.Minimum = (int)numericUpDown_Graph_MinY.Value;
    }

    private void checkBox_AutoY_CheckedChanged(object sender, EventArgs e)
    {
      if (checkBox_AutoY.Checked)
      {
        chart_Graph.ChartAreas[0].AxisY.Minimum = double.NaN;
        chart_Graph.ChartAreas[0].AxisY.Maximum = double.NaN;
        numericUpDown_Graph_MinY.Enabled = false;
        numericUpDown_Graph_MaxY.Enabled = false;
        panel_GraphY.Enabled = false;
      }
      else
      {
        numericUpDown_Graph_MaxY_ValueChanged(null, null);
        numericUpDown_Graph_MinY.Enabled = true;
        numericUpDown_Graph_MaxY.Enabled = true;
        panel_GraphY.Enabled = true;
        trackBar_GraphY_Left.Value = trackBar_GraphY_Left.Minimum;
        trackBar_GraphY_Right.Value = trackBar_GraphY_Right.Maximum;
      }
    }

    private void trackBar_GraphY_Left_Scroll(object sender, EventArgs e)
    {
      int min = trackBar_GraphY_Left.Value;
      int max = trackBar_GraphY_Right.Value;
      if (min > max)
      {
        int sub = min;
        min = max;
        max = sub;
      }

      if (max == min) max += 1;

      chart_Graph.ChartAreas[0].AxisY.Minimum = min;
      chart_Graph.ChartAreas[0].AxisY.Maximum = max;
    }

    private void button_Update_Click(object sender, EventArgs e)
    {

    }
  }
}
