using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Web.UI.DataVisualization.Charting;
using System.Web.UI.WebControls;
using LeafWeb.Core.Charter;
using LeafWeb.Core.Utility;

namespace LeafWeb.Web.Charter
{
	public static class LeafWebCharter
	{
		private static readonly Font TitleFont = new Font("Times New Roman", 10, FontStyle.Bold);
		private static readonly Font AxisFont = new Font("Times New Roman", 10, FontStyle.Bold);
		private static readonly Font Font = new Font(new FontFamily("Trebuchet MS"), 9, FontStyle.Bold);
		private const int ChartWidth = 550;
		private const int ChartHeight = 400;

		// cntrlcomparison
		public static IEnumerable<Chart> ProduceCharts(CurveData curve)
		{
			var curveId = curve.CurveId;

			var paramTitles = new[]
			{
				new {param = curve.FixedCndFixedCmp,		title = ReflectionExtensions.GetPropertyDisplayName<CurveData>(c => c.FixedCndFixedCmp) },
				new {param = curve.FixedCndEstimatedCmp,	title = ReflectionExtensions.GetPropertyDisplayName<CurveData>(c => c.FixedCndEstimatedCmp) },
				new {param = curve.EstimatedCndFixedCmp,	title = ReflectionExtensions.GetPropertyDisplayName<CurveData>(c => c.EstimatedCndFixedCmp) },
				new {param = curve.EstimatedCndEstimatedCmp,title = ReflectionExtensions.GetPropertyDisplayName<CurveData>(c => c.EstimatedCndEstimatedCmp) },
			};

			return paramTitles.SelectMany(item => CurveSeries(curveId, item.param, item.title));
		}

		private static IEnumerable<Chart> CurveSeries(string curveId, CurveParamSet paramSet, string chartTitle)
		{
			var chloroChart = CreateEmptyChart("Chloroplastic CO2 partial pressure (Pa)", ChartWidth, ChartHeight);
			var interChart = CreateEmptyChart("Intercellular CO2 partial pressure (Pa)", ChartWidth, ChartHeight);

			// Set the points for the symbol series for paramater set 1, chloroplastic
			AddAnetMeasPoints(paramSet.AnetMeasChloro1Data, chloroChart.Series["Rubisco-limited"]);
			AddAnetMeasPoints(paramSet.AnetMeasChloro2Data, chloroChart.Series["RuBP regeneration-limited"]);

			var tpuSeries = NewTpuSeries(paramSet.AnetMeasChloro3Data);
			AddAnetMeasPoints(paramSet.AnetMeasChloro3Data, tpuSeries);
			chloroChart.Series.Add(tpuSeries);

			// Set the points for the symbol series for paramater set 1, intercellular
			AddAnetMeasPoints(paramSet.AnetMeasInter1Data, interChart.Series["Rubisco-limited"]);
			AddAnetMeasPoints(paramSet.AnetMeasInter2Data, interChart.Series["RuBP regeneration-limited"]);

			tpuSeries = NewTpuSeries(paramSet.AnetMeasInter3Data);
			AddAnetMeasPoints(paramSet.AnetMeasInter3Data, tpuSeries);
			interChart.Series.Add(tpuSeries);

			// Set the points on the asymptote curve for parameter set 1, chloroplast
			AddAsymptotePoints(paramSet.AcChloroData, chloroChart.Series["acCurve"]);
			AddAsymptotePoints(paramSet.AjChloroData, chloroChart.Series["ajCurve"]);
			AddAsymptotePoints(paramSet.AtChloroData, chloroChart.Series["atCurve"]);

			// Set the points on the asymptote curve for parameter set 1, intercellular
			AddAsymptotePoints(paramSet.AcInterData, interChart.Series["acCurve"]);
			AddAsymptotePoints(paramSet.AjInterData, interChart.Series["ajCurve"]);
			AddAsymptotePoints(paramSet.AtInterData, interChart.Series["atCurve"]);

			var title = new Title($"LeafWeb curveID = {curveId}\n{chartTitle}"){Font = TitleFont};
			chloroChart.Titles.Add(title);
			interChart.Titles.Add(title);

			chloroChart.ChartAreas["ChartArea"].AxisX.TitleFont = AxisFont;
			chloroChart.ChartAreas["ChartArea"].AxisY.TitleFont = AxisFont;

			interChart.ChartAreas["ChartArea"].AxisX.TitleFont = AxisFont;
			interChart.ChartAreas["ChartArea"].AxisY.TitleFont = AxisFont;

			yield return chloroChart;
			yield return interChart;
		}

		private static Series NewTpuSeries(IReadOnlyCollection<XyPoint> data)
		{
			var seriesName = "TPU-limited";
			if (data.Count == 0)
				seriesName = "Curve Asymptote";
			var series3 = new Series(seriesName)
			{
				MarkerSize = 9,
				BorderWidth = 3,
				XValueType = ChartValueType.Double,
				ChartType = SeriesChartType.Point,
				MarkerStyle = MarkerStyle.Square,
				ShadowColor = Color.Black,
				BorderColor = Color.Black,
				Color = Color.Orange,
				ShadowOffset = 0,
				YValueType = ChartValueType.Double
			};

			return series3;
		}

		private static void AddAnetMeasPoints(IEnumerable<XyPoint> data, Series series)
		{
			// Set the points for the series from the ArrayList
			foreach (var xy in data)
			{
				series.Points.AddXY(xy.X, xy.Y);
			}
		}

		private static void AddAsymptotePoints(IEnumerable<XyPoint> data, Series series)
		{
			// Set the points for the series from the ArrayList
			foreach (var xy in data.Where(xy => (xy.X != -9999) && (xy.Y != -9999)))
			{
				series.Points.AddXY(xy.X, xy.Y);
			}
		}

		private static Chart CreateEmptyChart(string axisXTitle, int width=700, int height=500)
		{
			var borderColor = Color.FromArgb(180, 26, 59, 105);
			var chart = new Chart
			{
				BackColor = Color.White,
				Width = Unit.Pixel(width),
				Height = Unit.Pixel(height),
				//BorderSkin = {SkinStyle = BorderSkinStyle.None},
				BorderColor = borderColor,
				BorderlineColor = borderColor,
				BorderlineWidth = 1,
				BorderlineDashStyle = ChartDashStyle.Solid
			};

			chart.Legends.Add(new Legend
			{
				Enabled = true,
				IsTextAutoFit = false,
				Name = "Default",
				Docking = Docking.Bottom,
				BackColor = Color.Transparent,
				Font = Font
			});

			chart.ChartAreas.Add(new ChartArea
			{
				Name = "ChartArea",
				BorderColor = Color.FromArgb(64, 64, 64, 64),
				BorderDashStyle = ChartDashStyle.Solid,
				BackSecondaryColor = Color.White,
				BackColor = Color.OldLace,
				ShadowColor = Color.Transparent,
				BackGradientStyle = GradientStyle.TopBottom,
				AxisY = new Axis
				{
					LineColor = Color.FromArgb(64, 64, 64, 64),
					Title = "Net assimilation rate (umol/m2/s)",
					LabelStyle = { Font = Font },
					MajorGrid = new Grid { LineColor = Color.FromArgb(64, 64, 64, 64)}
				},
				AxisX = new Axis
				{
					LineColor = Color.FromArgb(64, 64, 64, 64),
					Minimum = 0,
					Title = axisXTitle,
					LabelStyle = { Font = Font },
					MajorGrid = new Grid { LineColor = Color.FromArgb(64, 64, 64, 64)}
				}
			});

			chart.Series.Add(new Series
			{
				MarkerSize = 8,
				BorderWidth = 3,
				XValueType = ChartValueType.Double,
				Name = "Rubisco-limited",
				ChartType = SeriesChartType.Point,
				MarkerStyle = MarkerStyle.Diamond,
				ShadowColor = Color.Black,
				BorderColor = borderColor,
				Color = Color.Red,
				ShadowOffset = 0,
				YValueType = ChartValueType.Double
			});

			chart.Series.Add(new Series
			{
				MarkerSize = 9,
				BorderWidth = 3,
				XValueType = ChartValueType.Double,
				Name = "RuBP regeneration-limited",
				ChartType = SeriesChartType.Point,
				MarkerStyle = MarkerStyle.Circle,
				ShadowColor = Color.Black,
				BorderColor = borderColor,
				Color = Color.Blue,
				ShadowOffset = 0,
				YValueType = ChartValueType.Double
			});

			chart.Series.Add(new Series
			{
				MarkerSize = 2,
				BorderWidth = 1,
				XValueType = ChartValueType.Double,
				Name = "acCurve",
				ChartType = SeriesChartType.Line,
				MarkerStyle = MarkerStyle.None,
				ShadowColor = Color.Black,
				BorderColor = borderColor,
				Color = Color.Red,
				ShadowOffset = 0,
				YValueType = ChartValueType.Double,
				IsVisibleInLegend = false
			});

			chart.Series.Add(new Series
			{
				MarkerSize = 2,
				BorderWidth = 1,
				XValueType = ChartValueType.Double,
				Name = "ajCurve",
				ChartType = SeriesChartType.Line,
				MarkerStyle = MarkerStyle.None,
				ShadowColor = Color.Black,
				BorderColor = borderColor,
				Color = Color.Blue,
				ShadowOffset = 0,
				YValueType = ChartValueType.Double,
				IsVisibleInLegend = false
			});

			chart.Series.Add(new Series
			{
				MarkerSize = 2,
				BorderWidth = 1,
				XValueType = ChartValueType.Double,
				Name = "atCurve",
				ChartType = SeriesChartType.Line,
				MarkerStyle = MarkerStyle.None,
				ShadowColor = Color.Black,
				BorderColor = borderColor,
				Color = Color.Orange,
				ShadowOffset = 0,
				YValueType = ChartValueType.Double,
				IsVisibleInLegend = false
			});

			return chart;
		}
	}
}