using System.Collections.Generic;
using System.IO;
using System.Linq;
using LeafWeb.Core.Entities;
using LeafWeb.Core.Utility;

namespace LeafWeb.Core.Parsers
{
	public class LeafGasComparisonParser : CsvParserBase
	{
		public LeafGasComparisonParser(FileSystemInfo csvFile) : base(csvFile)
		{
		}

		public LeafGasComparisonParser(byte[] fileContents) : base(fileContents)
		{
		}

		public LeafGasComparison[] Parse(string matchCurveId = null)
		{
			var fittingTitles = GetNextCsvRowValues();
			if (fittingTitles == null)
				throw new ParseException($"Could not read data header row on line number {CsvReader.Context.Row}");
			var fitUnits = GetNextCsvRowValues();
			if (fitUnits == null)
				throw new ParseException($"Could not read data units row on line number {CsvReader.Context.Row}");

			return ParseLeafGasComparisonSet(fittingTitles, matchCurveId).ToArray();
		}

		public string[] ExtractCurveIds()
		{
			var fittingTitles = GetNextCsvRowValues();
			if (fittingTitles == null)
				throw new ParseException($"Could not read data header row on line number {CsvReader.Context.Row}");
			var fitUnits = GetNextCsvRowValues();
			if (fitUnits == null)
				throw new ParseException($"Could not read data units row on line number {CsvReader.Context.Row}");

			return ExtractSectionCurveIds(fittingTitles).Distinct().ToArray();
		}

		private IEnumerable<string> ExtractSectionCurveIds(string[] fittingTitles)
		{
			string[] values;
			do
			{
				values = GetNextCsvRowValues();
				if (values == null)
					yield break;

				var fittingInfo = ParsedObjectFactory<LeafGasComparisonFittingInfo>
					.Create(fittingTitles, new[] {values});
				yield return fittingInfo[0].CurveID;

				while (CsvReader.Context.Record.Length != 0)
					values = GetNextCsvRowValues();
			} while (values != null);
		}

		private IEnumerable<LeafGasComparison> ParseLeafGasComparisonSet(string[] fittingTitles, string matchCurveId = null)
		{
			var matcher = new ParseInfoPropertyMatcherWithCache<LeafGasComparisonPhotosyntheticInfo>();
			var endOfFile = false;
			while (!endOfFile)
			{
				// First Section
				var fittingValues = new List<string[]>();
				string[] photosyntheticTitles;
				string curveId = null;
				while (true)
				{
					var values = GetNextCsvRowValues();
                    if (values == null) // end of file
                        yield break;
                    if (string.IsNullOrEmpty(CsvReader.Context.RawRecord))
						continue;
                    if (matcher.IsPropertiesTitlesMatch(values))
					{
						photosyntheticTitles = values;
						break;
					}
					fittingValues.Add(values);

					// extract the curveId
					if (!string.IsNullOrEmpty(matchCurveId) && curveId == null)
					{
						var testFittingInfo = 
							ParsedObjectFactory<LeafGasComparisonFittingInfo>
								.Create(fittingTitles, fittingValues.ToArray());
						curveId = testFittingInfo[0].CurveID;
					}
				}

				var photosyntheticValues = new List<string[]>();
				while (true)
				{
					var values = GetNextCsvRowValues();
					if (CsvReader.Context.Record.Length == 0) // end of set
						break;
					if (values == null)
					{
						endOfFile = true;
                        break;
					}
					photosyntheticValues.Add(values);
				}

				// don't parse the values if it's not the curve we're wanting
				if (!string.IsNullOrEmpty(matchCurveId) && curveId != matchCurveId)
					continue;

				var fittingInfo =
					ParsedObjectFactory<LeafGasComparisonFittingInfo>
						.Create(fittingTitles, fittingValues.ToArray());

				var photosyntheticInfo =
					ParsedObjectFactory<LeafGasComparisonPhotosyntheticInfo>
						.Create(photosyntheticTitles, photosyntheticValues.ToArray());

				yield return new LeafGasComparison
				{
					FittingInfo = fittingInfo,
					PhotosyntheticInfo = photosyntheticInfo
				};
			}
		}
	}
}
