using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace friction
{
	public class TrendLine
	{
		public struct POINT
		{
			public float X;
			public float Y;
		}


		private readonly List<POINT> AxisValues;
		private int count;
		private float xAxisValuesSum;
		private float xxSum;
		private float xySum;
		private float yAxisValuesSum;

		//public TrendLine(IList<float> xAxisValues, IList<float> yAxisValues)
		//{
		//	this.xAxisValues = xAxisValues;
		//	this.yAxisValues = yAxisValues;
			

		//	this.Initialize();
		//}

		public TrendLine(List<POINT> points)
		{
			AxisValues = points;
			AxisValues.Sort((POINT a, POINT b) => (a.X == b.X) ? 0 : (a.X < b.X) ? -1 : 1);

			this.Initialize();
		}

		public float Slope { get; private set; }
		public float Intercept { get; private set; }
		public float Start { get; private set; }
		public float End { get; private set; }

		private void Initialize()
		{
			this.count = this.AxisValues.Count;
			this.yAxisValuesSum = this.AxisValues.Sum(e => e.Y);
			this.xAxisValuesSum = this.AxisValues.Sum(e => e.X);
			this.xxSum = 0;
			this.xySum = 0;

			for (int i = 0; i < this.count; i++)
			{
				this.xySum += (this.AxisValues[i].X * this.AxisValues[i].Y);
				this.xxSum += (this.AxisValues[i].X * this.AxisValues[i].X);
			}

			this.Slope = this.CalculateSlope();
			this.Intercept = this.CalculateIntercept();
			this.Start = this.CalculateStart();
			this.End = this.CalculateEnd();
		}

		private float CalculateSlope()
		{
			try
			{
				return ((this.count * this.xySum) - (this.xAxisValuesSum * this.yAxisValuesSum)) / ((this.count * this.xxSum) - (this.xAxisValuesSum * this.xAxisValuesSum));
			}
			catch (DivideByZeroException)
			{
				return 0;
			}
		}

		private float CalculateIntercept()
		{
			return (this.yAxisValuesSum - (this.Slope * this.xAxisValuesSum)) / this.count;
		}

		private float CalculateStart()
		{
			return (this.Slope * this.AxisValues.First().X) + this.Intercept;
		}

		private float CalculateEnd()
		{
			return (this.Slope * this.AxisValues.Last().X) + this.Intercept;
		}

		public float GetY(float fX)
		{
			return (this.Slope * fX) + this.Intercept;
		}
	}
}
