using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using CoverageFramework.Operator.Decorator;
using CoverageFramework.Operator.Selector;
using CoverageFramework.Model;
using CoverageFramework.Utility;
using Paraiba.Linq;

namespace CoverageFramework.Embedder
{
	public class DecisionCoverageEmbedder
	{
		private int _iBranch;

		public void Embed(XElement root, IXElementRangeSelector ifRangeSelector, ITaggedXElementDecorator covDec, ITagger tagger, IDictionary<string, CoverageInfomation> covInfos)
		{
			ifRangeSelector.Select(root)
				.ForEach(target => {
					var targetList = target.ToList();
					var tag = "branch," + (_iBranch++);
					var pos = CodePositionUtil.CreateCodePosition(targetList);
					covInfos[tag] = new CoverageInfomation(pos, tagger.Generate(targetList));

					// Replaceメソッドが思うように動作しないので、削除＆挿入で代用
					// 直前に要素があるかどうか調べる
					var prev = targetList[0].PreviousNode;
					if (prev != null)
					{
						// 要素の複製防止のために削除して，同じ位置に挿入し直す
						targetList.Remove();
						// 直前の要素の次に挿入
						prev.AddAfterSelf(covDec.Generate(targetList, tag));
					}
					else
					{
						var parent = targetList[0].Parent;
						// 要素の複製防止のために削除して，同じ位置に挿入し直す
						targetList.Remove();
						// 親要素の最初の子として挿入
						parent.AddFirst(covDec.Generate(targetList, tag));
					}
				});
		}

		public void Embed(XElement root, IXElementSelector ifSelector, ITaggedXElementDecorator covDec, ITagger tagger, IDictionary<string, CoverageInfomation> covInfos)
		{
			ifSelector.Select(root)
				.ForEach(target => {
					var tag = "branch," + (_iBranch++);
					var pos = CodePositionUtil.CreateCodePosition(target);
					covInfos[tag] = new CoverageInfomation(pos, tagger.Generate(target));

					// Replaceメソッドが思うように動作しないので、削除＆挿入で代用
					// 直前に要素があるかどうか調べる
					var prev = target.PreviousNode;
					if (prev != null)
					{
						// 要素の複製防止のために削除して，同じ位置に挿入し直す
						target.Remove();
						// 直前の要素の次に挿入
						prev.AddAfterSelf(covDec.Generate(new[] { target }, tag));
					}
					else
					{
						var parent = target.Parent;
						// 要素の複製防止のために削除して，同じ位置に挿入し直す
						target.Remove();
						// 親要素の最初の子として挿入
						parent.AddFirst(covDec.Generate(new[] { target }, tag));
					}
				});
		}
	}
}