using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text.RegularExpressions;
using System.Diagnostics;
using System.Reflection;

namespace X03.PageElements.Notations
{

	abstract public class NotNestable : PageElements.Notation, Plugin.PageElement
	{
		public List<PageElements.Plains.Plaintext> ChildrenAsPlaintext
		{
			get
			{
				return this.Children.Cast<PageElements.Plains.Plaintext>().ToList();
			}
			protected set
			{
				this.Children = value.Cast<PageElement>().ToList();
			}
		}
		new static public IEnumerable<Type> GetPluginClasses()
		{
			return Utils.GetPluginClasses(typeof(PageElements.Notations.NotNestable));
		}
		private static PageElement createNotNestableElement(Type notationClass, PageElement parent, List<PageElements.Plains.Plaintext> children)
		{
			return (PageElement)Assembly.GetAssembly(notationClass).CreateInstance(notationClass.FullName, false, BindingFlags.CreateInstance, null, new object[] { parent, children }, null, null);
		}
		public static List<PageElement> Generate(Type notationClass, PageElement parent, List<PageElement> elements, HashSet<Type> targetClasses)
		{
			var ret = new List<PageElement>(elements);
			var pattern = notationClass.GetField("Pattern", BindingFlags.Static | BindingFlags.Public).GetValue(null) as string;
			if (pattern == null)
				return ret;
			PageElement mergeTarget = null;
			Match m = null;
			var idx = 0;
			while (idx <= ret.Count - 1)
			{
				if (ret[idx] is PageElements.Wikitext)
				{
					PageElements.Wikitext wikitext = ret[idx] as PageElements.Wikitext;
					m = Regex.Match(wikitext.ToWikitext(), pattern, RegexOptions.Singleline | RegexOptions.IgnoreCase);
					if (m.Success)
					{
						var subs = new string[] {
                           wikitext.ToWikitext().Substring(0, (m.Index + 1) - 1),
                           m.Value,
                           wikitext.ToWikitext().Substring(m.Index + m.Length)
                       };
						var additions = new List<PageElement>();
						if (subs[0].Length > 0)
							additions.Add(new PageElements.Wikitext(subs[0]));
						// create PageElement
						if (notationClass.GetMethod("Merge") != null)
						{
							// 連結可能Notation
							Debug.Assert(notationClass.Name != null);
							if (m.Index == 0 && mergeTarget != null && mergeTarget.GetType().Name == notationClass.Name)
							{
								// 連結(既存インスタンスと統合)。新しいインスタンスは生成しない。
								notationClass.GetMethod("Merge").Invoke(null, new object[] { parent, new List<PageElements.Plains.Plaintext>() { new PageElements.Plains.Plaintext(parent, subs[1]) }, mergeTarget });
							}
							else
							{
								mergeTarget = createNotNestableElement(notationClass, parent, new List<PageElements.Plains.Plaintext>() { new PageElements.Plains.Plaintext(parent, subs[1]) });
								additions.Add(mergeTarget);
							}
						}
						else
						{
							// 連結しないNotation
							// 子Elementを持たないのでTokenize不要
							additions.Add(createNotNestableElement(notationClass, parent, new List<PageElements.Plains.Plaintext>() { new PageElements.Plains.Plaintext(parent, subs[1]) }));
						}
						if (subs[2].Length > 0)
							additions.Add(new PageElements.Wikitext(subs[2]));
						ret.RemoveAt(idx);
						ret.InsertRange(idx, additions);
						idx += additions.Count - 1 - 1;	// 追加された最後の要素を指すように、直後に実行されるidx++に合わせて調整
						break;
					}
				}
				else
				{
				}
				idx++;
			}
			return ret;
		}
		public static string Pattern;
		public NotNestable(PageElement parent, List<PageElements.Plains.Plaintext> children)
			: this(parent, children.Cast<PageElement>().ToList())
		{
		}
		public NotNestable(PageElement parent, List<PageElement> children)
			: base(parent, children)
		{
		}
	}

}