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 ConditionCoverageEmbedder
	{
		private int _iBranch;

		public void Embed(XElement root, IXElementRangeSelector ifRangeSelector, IXElementRangeSelector condRangeSelector, ITaggedXElementDecorator covDec, ITagger tagger, IDictionary<string, CoverageInfomation> covInfos)
		{
			ifRangeSelector.Select(root)
				.ForEach(ifCondBlock => {
					var ifPos = CodePositionUtil.CreateCodePosition(ifCondBlock);

					ifCondBlock.SelectMany(e_ => condRangeSelector.Select(e_))
						.ForEach((target, iCondition) => {
							var targetList = target.ToList();
							var key = "cond," + (_iBranch++) + ">" + iCondition;
							var pos = CodePositionUtil.CreateCodePosition(targetList);
							covInfos[key] = new CoverageInfomation(ifPos, pos, tagger.Generate(targetList));

							// 直前に要素があるかどうか調べる
							var prev = targetList[0].PreviousNode;
							if (prev != null)
							{
								// 要素の複製防止のために削除して，同じ位置に挿入し直す
								targetList.Remove();
								prev.AddAfterSelf(covDec.Generate(targetList, key));
							}
							else
							{
								var parent = targetList[0].Parent;
								// 要素の複製防止のために削除して，同じ位置に挿入し直す
								targetList.Remove();
								parent.AddFirst(covDec.Generate(targetList, key));
							}
						});
				});
		}

		public void Embed(XElement root, IXElementSelector ifSelector, IXElementSelector condSelector, ITaggedXElementDecorator covDec, ITagger tagger, IDictionary<string, CoverageInfomation> covInfos)
		{
			ifSelector.Select(root)
				.ForEach(ifCondition => {
					var ifPos = CodePositionUtil.CreateCodePosition(ifCondition);

					condSelector.Select(ifCondition)
						.ForEach((target, iCondition) => {
							var key = "cond," + (_iBranch++) + ">" + iCondition;
							var pos = CodePositionUtil.CreateCodePosition(target);
							covInfos[key] = new CoverageInfomation(ifPos, pos, tagger.Generate(target));

							// 直前に要素があるかどうか調べる
							var prev = target.PreviousNode;
							if (prev != null)
							{
								// 要素の複製防止のために削除して，同じ位置に挿入し直す
								target.Remove();
								prev.AddAfterSelf(covDec.Generate(new[] { target }, key));
							}
							else
							{
								var parent = target.Parent;
								// 要素の複製防止のために削除して，同じ位置に挿入し直す
								target.Remove();
								parent.AddFirst(covDec.Generate(new[] { target }, key));
							}
						});
				});
		}
	}
}