using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace LeafWeb.Web.Charter
{
	[Serializable]
	public class CurveParamSet
	{
		private readonly List<XyPoint> _anetMeasChloro1Data; // y=AnetMeas column, x=PCO2c, for PointLimitType=1
		private readonly List<XyPoint> _anetMeasChloro2Data; // y=AnetMeas column, x=PCO2c, for PointLimitType=2
		private readonly List<XyPoint> _anetMeasChloro3Data; // y=AnetMeas column, x=PCO2c, for PointLimitType=3
		private readonly List<XyPoint> _anetMeasInter1Data; // y=AnetMeas column, x=PCO2i, for PointLimitType=1
		private readonly List<XyPoint> _anetMeasInter2Data; // y=AnetMeas column, x=PCO2i, for PointLimitType=2
		private readonly List<XyPoint> _anetMeasInter3Data; // y=AnetMeas column, x=PCO2i, for PointLimitType=3
		private readonly List<XyPoint> _acChloroData; // y=Ac column, x=CO2cc column
		private readonly List<XyPoint> _ajChloroData; // y=Aj column, x=CO2cj column
		private readonly List<XyPoint> _atChloroData; // y=At column, x=CO2ct column
		private readonly List<XyPoint> _acInterData; // y=Ac column, x=CO2i column
		private readonly List<XyPoint> _ajInterData; // y=Aj column, x=CO2i column
		private readonly List<XyPoint> _atInterData; // y=At column, x=CO2i column

		public CurveParamSet()
		{
		}

		public CurveParamSet(StreamReader sr, ref String errMsg, ref int lineNbr, ref String curveId)
		{
			bool curveIdSet = false, doneWithAnet = false;
			String line;
			var errorMsg = new StringBuilder("");
			List<string> phrases;
			XyPoint xyPoint1;
			_anetMeasChloro1Data = new List<XyPoint>();
			_anetMeasChloro2Data = new List<XyPoint>();
			_anetMeasChloro3Data = new List<XyPoint>();
			_anetMeasInter1Data = new List<XyPoint>();
			_anetMeasInter2Data = new List<XyPoint>();
			_anetMeasInter3Data = new List<XyPoint>();
			_acChloroData = new List<XyPoint>();
			_ajChloroData = new List<XyPoint>();
			_atChloroData = new List<XyPoint>();
			_acInterData = new List<XyPoint>();
			_ajInterData = new List<XyPoint>();
			_atInterData = new List<XyPoint>();

			while (!doneWithAnet)
			{
				lineNbr++;
				line = sr.ReadLine();
				if (line == null)
				{
					errorMsg.Append("Unexpected end-of-file at line " + lineNbr);
					sr.Close();
					errMsg = errorMsg.ToString();
					return;
				}

				phrases = SplitCsvLine(line);

				String firstField = phrases[0];
				if (firstField.Equals("CO2i"))
				{
					doneWithAnet = true;
				}
				else
				{
					// The fields on the line:
					// Column  Name
					//   0     CurveID
					//   1     ChlFlUse
					//   2     FitGi
					//   3     FitGamma
					//   4     FitKco
					//   5     FitRd
					//   6     FitAlpha
					//   7     LimitCombina
					//   8     PCO2i
					//   9     PCO2c
					//  10     AnetMeas
					//  11     AnetCal
					//  12     weitedrms
					//  13     PointLimitType

					if (!curveIdSet)
					{
						curveId = firstField;
						curveIdSet = true;
					}
					xyPoint1 = new XyPoint(phrases[9], phrases[10]); // AnetMeas(y), PCO2c(x)
					var xyPoint2 = new XyPoint(phrases[8], phrases[10]);
					var pointLimitType = Int32.Parse(phrases[13]);
					switch (pointLimitType)
					{
						case 1:
							_anetMeasChloro1Data.Add(xyPoint1);
							_anetMeasInter1Data.Add(xyPoint2);
							break;
						case 2:
							_anetMeasChloro2Data.Add(xyPoint1);
							_anetMeasInter2Data.Add(xyPoint2);
							break;
						case 3:
							_anetMeasChloro3Data.Add(xyPoint1);
							_anetMeasInter3Data.Add(xyPoint2);
							break;
					}
				}
			}

			// The next set of lines will have three pairs of x,y-coordinates to save.
			// A blank line signals the end of the data.

			var moreData = true;
			while (moreData)
			{
				// The fields on the line:
				// Column  Name
				//   0     CO2i
				//   1     CO2cc
				//   2     Ac
				//   3     CO2cj
				//   4     Aj
				//   5     CO2ct
				//   6     At

				lineNbr++;
				line = sr.ReadLine();
				if (line == null)
				{
					errorMsg.Append("Unexpected end-of-file at line " + lineNbr);
					sr.Close();
					errMsg = errorMsg.ToString();
					return;
				}

				if (line.Length == 0)
					moreData = false;
				else
				{
					phrases = SplitCsvLine(line);
					xyPoint1 = new XyPoint(phrases[1],phrases[2]); // Ac(y),CO2cc(x)
					if (xyPoint1.YIsInRange(-20.0, 50.0))
						_acChloroData.Add(xyPoint1);
					xyPoint1 = new XyPoint(phrases[3], phrases[4]); // Aj(y),CO2cj(x)
					if (xyPoint1.YIsInRange(-20.0, 50.0))
						_ajChloroData.Add(xyPoint1);
					xyPoint1 = new XyPoint(phrases[5], phrases[6]); // At(y),CO2ct(x)
					if (xyPoint1.YIsInRange(-20.0, 50.0))
						_atChloroData.Add(xyPoint1);

					xyPoint1 = new XyPoint(phrases[0], phrases[2]); // Ac(y),CO2i(x)
					if (xyPoint1.YIsInRange(-20.0, 50.0))
						_acInterData.Add(xyPoint1);
					xyPoint1 = new XyPoint(phrases[0], phrases[4]); // Aj(y),CO2i(x)
					if (xyPoint1.YIsInRange(-20.0, 50.0))
						_ajInterData.Add(xyPoint1);
					xyPoint1 = new XyPoint(phrases[0], phrases[6]); // At(y),CO2i(x)
					if (xyPoint1.YIsInRange(-20.0, 50.0))
						_atInterData.Add(xyPoint1);
				}
			}
		}

		/// <summary>
		///     This method assumes that the argument is a comma-, blank-, or
		///     tab-separated set of strings. It returns an ArrayList of those
		///     quantities. Consecutive commas will be returned as an empty string,
		///     but all empty strings  at the end of the line will be thrown away.
		/// </summary>
		/// <param name="line"></param>
		/// <returns></returns>
		private static List<string> SplitCsvLine(String line)
		{
			int i;
			var separator = new [] {',', ' ', '\t'};
			var phrases = line.Split(separator);

			//int lastNonBlank = -1;
			var retPhrases = new List<string>();
			for (i = 0; i < phrases.Length; i++)
			{
				var phrase = phrases[i].Trim();
				if (phrase.Length > 0)
					//    lastNonBlank = i;
					retPhrases.Add(phrase);
			}

			return retPhrases;
		}

		public List<List<XyPoint>> GetAnetMeasData()
		{
			var list = new List<List<XyPoint>>
				{
					_anetMeasChloro1Data,
					_anetMeasChloro2Data,
					_anetMeasChloro3Data,
					_anetMeasInter1Data,
					_anetMeasInter2Data,
					_anetMeasInter3Data
				};

			return list;
		}

		public List<XyPoint> GetAcChloroData()
		{
			return _acChloroData;
		}

		public List<XyPoint> GetAjChloroData()
		{
			return _ajChloroData;
		}

		public List<XyPoint> GetAtChloroData()
		{
			return _atChloroData;
		}

		public List<XyPoint> GetAcInterData()
		{
			return _acInterData;
		}

		public List<XyPoint> GetAjInterData()
		{
			return _ajInterData;
		}

		public List<XyPoint> GetAtInterData()
		{
			return _atInterData;
		}
	}
}