using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using WeifenLuo.WinFormsUI.Docking;
using LiveCharts;
using LiveCharts.Wpf;
using LiveCharts.WinForms;
using LiveCharts.Defaults;
using System.Windows.Media;
using System.Threading;

namespace friction
{
	public partial class PanelTrendGraph : DockContent
	{
		public enum GRAPH_TYPE
		{
			NONE,
			HUMIDITY,
			TEMPERATURE,
			FORCE,
			VELOCITY
		}


		MainForm m_Owner = null;
		DataHandler m_DataHandler = null;

		string m_CurSpring = "";
		string m_CurTable = "";
		GRAPH_TYPE m_GraphType = GRAPH_TYPE.NONE;

		// for report
		bool m_bReport = false;

		public PanelTrendGraph(MainForm owner, DataHandler data)
		{
			InitializeComponent();

			m_Owner = owner;
			m_DataHandler = data;


			Theme.Apply(this);
			Theme.Apply(trendChart);
			Theme.Apply(groupBox1);
			Theme.Apply(rbHumidity);
			Theme.Apply(rbTemp);


			trendChart.AxisX.Add(new Axis
			{
				Title = "Humidity",
			});

			trendChart.AxisY.Add(new Axis
			{
				Title = "RPN",
				MinValue = 0,
				MaxValue = 10,

				Sections = new SectionsCollection
				{
					new AxisSection
					{
						Value = 5,
						SectionWidth = 5,
						Fill = new SolidColorBrush
						{
							Color = System.Windows.Media.Color.FromArgb(Theme.Red.A, Theme.Red.R, Theme.Red.G, Theme.Red.B),
							Opacity = .75
						}
					},
					new AxisSection
					{
						Value = 3,
						SectionWidth = 2,
						Fill = new SolidColorBrush
						{
							Color = System.Windows.Media.Color.FromArgb(Theme.Yellow.A, Theme.Yellow.R, Theme.Yellow.G, Theme.Yellow.B),
							Opacity = .75
						}
					},
					new AxisSection
					{
						Value = 0,
						SectionWidth = 3,
						Fill = new SolidColorBrush
						{
							Color = System.Windows.Media.Color.FromArgb(Theme.Green.A, Theme.Green.R, Theme.Green.G, Theme.Green.B),
							Opacity = .75
						}
					}
				}
			});

			trendChart.LegendLocation = LegendLocation.Right;
			trendChart.DataClick += TrendChart_DataClick;

			trendChart.DefaultLegend.Foreground = new SolidColorBrush(
				System.Windows.Media.Color.FromArgb(
					Theme.Forecolor.A, Theme.Forecolor.R, Theme.Forecolor.G, Theme.Forecolor.B));
		}

		public void Reset()
		{
			m_CurSpring = "";
			m_CurTable = "";
			m_GraphType = GRAPH_TYPE.NONE;
		}

		private void TrendChart_DataClick(object sender, ChartPoint chartPoint)
		{
			switch (m_GraphType)
			{
				case GRAPH_TYPE.HUMIDITY:
					m_Owner.OnTrendSelectByHumidity(m_CurSpring, m_CurTable, (float)chartPoint.X, (float)chartPoint.Y);
					break;

				case GRAPH_TYPE.TEMPERATURE:
					m_Owner.OnTrendSelectByTemperature(m_CurSpring, m_CurTable, (float)chartPoint.X, (float)chartPoint.Y);
					break;

				case GRAPH_TYPE.FORCE:
					m_Owner.OnTrendSelectByForce(m_CurSpring, m_CurTable, (float)chartPoint.X, (float)chartPoint.Y);
					break;

				case GRAPH_TYPE.VELOCITY:
					m_Owner.OnTrendSelectByVelocity(m_CurSpring, m_CurTable, (float)chartPoint.X, (float)chartPoint.Y);
					break;
			}
		}

		private void UpdateGraphHumidity()
		{
			string strSpring = m_DataHandler.GetCurSpring();
			string strTable = m_DataHandler.GetCurTable();

			var Chart = m_DataHandler.GetTrendChart(strSpring, strTable);
			if (Chart.Count <= 0)
				return;

			trendChart.AxisX[0].Title = "Humidity";

			ChartValues<ScatterPoint>[] Points = {
					new ChartValues<ScatterPoint>(),
					new ChartValues<ScatterPoint>(),
					new ChartValues<ScatterPoint>() };

			var Values = new List<TrendLine.POINT>();

			foreach (var pnt in Chart)
			{
				if (pnt.TEMPERATURE < 0)
					Points[0].Add(new ScatterPoint(pnt.HUMIDITY, pnt.RPN, 2));
				else if (pnt.TEMPERATURE > 30)
					Points[2].Add(new ScatterPoint(pnt.HUMIDITY, pnt.RPN, 2));
				else
					Points[1].Add(new ScatterPoint(pnt.HUMIDITY, pnt.RPN, 2));

				Values.Add(new TrendLine.POINT { X = pnt.HUMIDITY, Y = pnt.RPN });
			}

			Values.Sort((a, b) => (a.X == b.X) ? 0 : (a.X < b.X) ? -1 : 1);
			TrendLine trendline = new TrendLine(Values);
			ChartValues<ScatterPoint> TrendPoints = new ChartValues<ScatterPoint>();
			TrendPoints.Add(new ScatterPoint(Values[0].X, trendline.GetY(Values[0].X)));
			TrendPoints.Add(new ScatterPoint(Values[Values.Count / 2].X, trendline.GetY(Values[Values.Count / 2].X)));
			TrendPoints.Add(new ScatterPoint(Values[Values.Count - 1].X, trendline.GetY(Values[Values.Count - 1].X)));

			System.Windows.Media.SolidColorBrush[] brushes = {
				System.Windows.Media.Brushes.DodgerBlue.Clone(),
				System.Windows.Media.Brushes.Green.Clone(),
				System.Windows.Media.Brushes.IndianRed.Clone() };
			foreach (var brush in brushes)
				brush.Opacity = 0.75;

			trendChart.Series = new SeriesCollection
				{
					new ScatterSeries
					{
						Title = "Low Temp",
						Values = Points[0],
						Fill = brushes[0],
						LabelPoint = p => string.Format("{0:n2}, {1}", p.X, p.Y),
					},
					new ScatterSeries
					{
						Title = "Mid Temp",
						Values = Points[1],
						Fill = brushes[1],
						LabelPoint = p => string.Format("{0:n2}, {1}", p.X, p.Y),
					},
					new ScatterSeries
					{
						Title = "High Temp",
						Values = Points[2],
						Fill = brushes[2],
						LabelPoint = p => string.Format("{0:n2}, {1}", p.X, p.Y),
					},
					new LineSeries
					{
						Title = "Trend",
						Values = TrendPoints,
						PointGeometry = DefaultGeometries.None,
						StrokeThickness = 4,
					},
				};


			trendChart.AxisX[0].MinValue = Chart.Min(r => r.HUMIDITY - 1);
			trendChart.AxisX[0].MaxValue = Chart.Max(r => r.HUMIDITY - 1);

			m_CurSpring = strSpring;
			m_CurTable = strTable;
		}

		private void UpdateGraphTemperature()
		{
			string strSpring = m_DataHandler.GetCurSpring();
			string strTable = m_DataHandler.GetCurTable();

			var Chart = m_DataHandler.GetTrendChart(strSpring, strTable);
			if (Chart.Count <= 0)
				return;

			trendChart.AxisX[0].Title = "Temperature";

			ChartValues<ScatterPoint>[] Points = {
					new ChartValues<ScatterPoint>(),
					new ChartValues<ScatterPoint>() };
			var Values = new List<TrendLine.POINT>();

			foreach (var pnt in Chart)
			{
				if (pnt.HUMIDITY <= 60)
					Points[0].Add(new ScatterPoint(pnt.TEMPERATURE, pnt.RPN, 2));
				else
					Points[1].Add(new ScatterPoint(pnt.TEMPERATURE, pnt.RPN, 2));

				Values.Add(new TrendLine.POINT { X = pnt.TEMPERATURE, Y = pnt.RPN });
			}

			Values.Sort((a, b) => (a.X == b.X) ? 0 : (a.X < b.X) ? -1 : 1);
			TrendLine trendline = new TrendLine(Values);
			ChartValues<ScatterPoint> TrendPoints = new ChartValues<ScatterPoint>();
			TrendPoints.Add(new ScatterPoint(Values[0].X, trendline.GetY(Values[0].X)));
			TrendPoints.Add(new ScatterPoint(Values[Values.Count / 2].X, trendline.GetY(Values[Values.Count / 2].X)));
			TrendPoints.Add(new ScatterPoint(Values[Values.Count - 1].X, trendline.GetY(Values[Values.Count - 1].X)));

			trendChart.Series = new SeriesCollection
				{
					new ScatterSeries
					{
						Title = "Low Humidity",
						Values = Points[0],
						Foreground = System.Windows.Media.Brushes.SkyBlue,
						LabelPoint = p => string.Format("{0:n2}, {1}", p.X, p.Y),
					},
					new ScatterSeries
					{
						Title = "High Humidity",
						Values = Points[1],
						Foreground = System.Windows.Media.Brushes.DarkBlue,
						LabelPoint = p => string.Format("{0:n2}, {1}", p.X, p.Y),
					},
					new LineSeries
					{
						Title = "Trend",
						Values = TrendPoints,
						PointGeometry = DefaultGeometries.None,
						StrokeThickness = 4,
					},
				};


			trendChart.AxisX[0].MinValue = Chart.Min(r => r.HUMIDITY - 1);
			trendChart.AxisX[0].MaxValue = Chart.Max(r => r.HUMIDITY - 1);
		}

		private void UpdateGraphForce()
		{
			string strSpring = m_DataHandler.GetCurSpring();
			string strTable = m_DataHandler.GetCurTable();

			var Chart = m_DataHandler.GetTrendChart(strSpring, strTable);
			if (Chart.Count <= 0)
				return;

			trendChart.AxisX[0].Title = "Force";

			var Points = new ChartValues<ScatterPoint>();
			var Values = new List<TrendLine.POINT>();

			foreach (var pnt in Chart)
			{
				Points.Add(new ScatterPoint(pnt.FORCE, pnt.RPN, 2));
				Values.Add(new TrendLine.POINT { X = pnt.FORCE, Y = pnt.RPN });
			}

			Values.Sort((a, b) => (a.X == b.X) ? 0 : (a.X < b.X) ? -1 : 1);
			TrendLine trendline = new TrendLine(Values);
			ChartValues<ScatterPoint> TrendPoints = new ChartValues<ScatterPoint>();
			TrendPoints.Add(new ScatterPoint(Values[0].X, trendline.GetY(Values[0].X)));
			TrendPoints.Add(new ScatterPoint(Values[Values.Count / 2].X, trendline.GetY(Values[Values.Count / 2].X)));
			TrendPoints.Add(new ScatterPoint(Values[Values.Count - 1].X, trendline.GetY(Values[Values.Count - 1].X)));

			trendChart.Series = new SeriesCollection
				{
					new ScatterSeries
					{
						Title = "RPN by force",
						Values = Points,
						Foreground = System.Windows.Media.Brushes.SkyBlue,
						LabelPoint = p => string.Format("{0:n2}, {1}", p.X, p.Y),
					},
					new LineSeries
					{
						Title = "Trend",
						Values = TrendPoints,
						PointGeometry = DefaultGeometries.None,
						StrokeThickness = 4,
					},
				};


			trendChart.AxisX[0].MinValue = Chart.Min(r => r.HUMIDITY - 1);
			trendChart.AxisX[0].MaxValue = Chart.Max(r => r.HUMIDITY - 1);
		}

		private void UpdateGraphVelocity()
		{
			string strSpring = m_DataHandler.GetCurSpring();
			string strTable = m_DataHandler.GetCurTable();

			var Chart = m_DataHandler.GetTrendChart(strSpring, strTable);
			if (Chart.Count <= 0)
				return;

			trendChart.AxisX[0].Title = "Velocity";

			var Points = new ChartValues<ScatterPoint>();
			var Values = new List<TrendLine.POINT>();

			foreach (var pnt in Chart)
			{
				Points.Add(new ScatterPoint(pnt.VELOCITY, pnt.RPN, 2));
				Values.Add(new TrendLine.POINT { X = pnt.VELOCITY, Y = pnt.RPN });
			}

			Values.Sort((a, b) => (a.X == b.X) ? 0 : (a.X < b.X) ? -1 : 1);
			TrendLine trendline = new TrendLine(Values);
			ChartValues<ScatterPoint> TrendPoints = new ChartValues<ScatterPoint>();
			TrendPoints.Add(new ScatterPoint(Values[0].X, trendline.GetY(Values[0].X)));
			TrendPoints.Add(new ScatterPoint(Values[Values.Count / 2].X, trendline.GetY(Values[Values.Count / 2].X)));
			TrendPoints.Add(new ScatterPoint(Values[Values.Count - 1].X, trendline.GetY(Values[Values.Count - 1].X)));

			trendChart.Series = new SeriesCollection
				{
					new ScatterSeries
					{
						Title = "RPN by velocity",
						Values = Points,
						Foreground = System.Windows.Media.Brushes.SkyBlue,
						LabelPoint = p => string.Format("{0:n2}, {1}", p.X, p.Y),
					},
					new LineSeries
					{
						Title = "Trend",
						Values = TrendPoints,
						PointGeometry = DefaultGeometries.None,
						StrokeThickness = 4,
					},
				};


			trendChart.AxisX[0].MinValue = Chart.Min(r => r.HUMIDITY - 1);
			trendChart.AxisX[0].MaxValue = Chart.Max(r => r.HUMIDITY - 1);
		}

		public void UpdateGraph(GRAPH_TYPE Type=GRAPH_TYPE.NONE)
		{
			Console.WriteLine("[TrendGraph::UpdateGraph] start");

			if (Type == GRAPH_TYPE.NONE)
			{
				if (rbHumidity.Checked == true)
					UpdateGraph(GRAPH_TYPE.HUMIDITY);
				else if (rbTemp.Checked == true)
					UpdateGraph(GRAPH_TYPE.TEMPERATURE);
				else if (rbForce.Checked == true)
					UpdateGraph(GRAPH_TYPE.FORCE);
				else if (rbVelocity.Checked == true)
					UpdateGraph(GRAPH_TYPE.VELOCITY);

				Console.WriteLine("[TrendGraph::UpdateGraph] end");
				return;
			}

			string strSpring = m_DataHandler.GetCurSpring();
			string strTable = m_DataHandler.GetCurTable();

			switch (Type)
			{
				case GRAPH_TYPE.HUMIDITY:
					UpdateGraphHumidity();
					break;

				case GRAPH_TYPE.TEMPERATURE:
					UpdateGraphTemperature();
					break;

				case GRAPH_TYPE.FORCE:
					UpdateGraphForce();
					break;

				case GRAPH_TYPE.VELOCITY:
					UpdateGraphVelocity();
					break;
			}

			m_CurSpring = strSpring;
			m_CurTable = strTable;
			m_GraphType = Type;

			Console.WriteLine("[TrendGraph::UpdateGraph] end");
		}

		private void rbHumidity_CheckedChanged(object sender, EventArgs e)
		{
			UpdateGraph(GRAPH_TYPE.HUMIDITY);
		}

		private void rbTemp_CheckedChanged(object sender, EventArgs e)
		{
			UpdateGraph(GRAPH_TYPE.TEMPERATURE);
		}

		private void rbForce_CheckedChanged(object sender, EventArgs e)
		{
			UpdateGraph(GRAPH_TYPE.FORCE);
		}

		private void rbVelocity_CheckedChanged(object sender, EventArgs e)
		{
			UpdateGraph(GRAPH_TYPE.VELOCITY);
		}

		public void CopyChart(GRAPH_TYPE Type)
		{
			m_bReport = true;
			trendChart.DisableAnimations = true;
			UpdateGraph(Type);
		}

		private void trendChart_UpdaterTick(object sender)
		{
			if(m_bReport == true)
			{
				Thread.Sleep(1500);

				m_bReport = false;

				Bitmap bm = new Bitmap(Width, Height);
				DrawToBitmap(bm, new Rectangle(0, 0, Width, Height));
				m_Owner.OnChartUpdate(bm, m_GraphType);
			}

			Console.WriteLine("chart updated");
		}
	}
}
