using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Paraiba.Core;
using CoverageFramework.Model;

namespace CoverageFramework.Utility
{
	public static class CodePositionUtil
	{
		public static CodePosition CreateCodePosition(XElement element)
		{
			return PrivateCreateCodePosition(element.DescendantsAndSelf(), element.Value.Length);
		}

		public static CodePosition CreateCodePosition(IEnumerable<XElement> element)
		{
			return PrivateCreateCodePosition(element.DescendantsAndSelf(), element.Sum(e_ => e_.Value.Length));
		}

		private static CodePosition PrivateCreateCodePosition(IEnumerable<XElement> descendants, int length)
		{
			int startLine = 0, startPos = 0;
			var firstElement = descendants.FirstOrDefault(e => e.Attribute("startline") != null);
			if (firstElement != null)
			{
				var startlineAttr = firstElement.Attribute("startline");
				var startposAttr = firstElement.Attribute("startpos");

				startLine = startlineAttr.Value.TryToInt(startLine);
				if (startposAttr != null)
				{
					startPos = startposAttr.Value.TryToInt(startPos);
				}
			}

			int endLine = startLine, endPos = startPos + length;
			var lastElement = descendants.LastOrDefault(e => e.Attribute("startline") != null);
			if (lastElement != null)
			{
				var startlineAttr = lastElement.Attribute("startline");
				var startposAttr = lastElement.Attribute("startpos");
				var endlineAttr = lastElement.Attribute("endline");
				var endposAttr = lastElement.Attribute("endpos");

				endLine = startlineAttr.Value.TryToInt(endLine);
				if (endlineAttr != null)
				{
					endLine = endlineAttr.Value.TryToInt(endLine);
				}
				if (startposAttr != null)
				{
					int value;
					if (int.TryParse(startposAttr.Value, out value))
						endPos = value + startposAttr.Value.Length;
				}
				if (endposAttr != null)
				{
					endPos = endposAttr.Value.TryToInt(endPos);
				}
			}

			int startID = 0, endID = 0;
			var firstIDElement = descendants.FirstOrDefault(e_ => e_.Attribute("id") != null);
			if (firstIDElement != null)
				startID = firstIDElement.Attribute("id").Value.TryToInt();
			var lastIDElement = descendants.LastOrDefault(e_ => e_.Attribute("id") != null);
			if (lastIDElement != null)
				endID = lastIDElement.Attribute("id").Value.TryToInt();

			return new CodePosition(startLine, startPos, startID, endLine, endPos, endID);
		}
	}
}