using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text;
using System.Text.RegularExpressions;
using System.Diagnostics;
using System.Reflection;
namespace X03.PageElements.Notations
{
abstract public class Nestable : PageElements.Notation, Plugin.PageElement
{
new static public IEnumerable<Type> GetPluginClasses()
{
return Utils.GetPluginClasses(typeof(PageElements.Notations.Nestable));
}
private static PageElement createNestableElement(Type notationClass, PageElement parent, List<PageElement> 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 patterns = notationClass.GetField("Patterns", BindingFlags.Static | BindingFlags.Public).GetValue(null) as string[];
if (patterns == null || patterns.Length < 2)
return ret;
var beginElementIndexes = new Stack<int>();
var beginMatchGroups = new Stack<Group>();
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(), @"(?<begin>" + patterns[0] + @")|(?<end>" + patterns[1] + @")", RegexOptions.Singleline | RegexOptions.IgnoreCase);
while (m.Success)
{
Debug.Assert(ret[idx] is PageElements.Wikitext);
if (m.Groups["begin"].Success)
{
// begin発見
beginElementIndexes.Push(idx);
beginMatchGroups.Push(m.Groups["begin"]);
}
else if (m.Groups["end"].Success && beginElementIndexes.Count >= 1 && beginMatchGroups.Count >= 1)
{
// end発見→PageElement生成
Group beginMatchGroup;
int beginElementIndex;
int beginStringIndex;
int beginStringLength;
int endElementIndex;
int endStringIndex;
int endStringLength;
{
// idx用意
beginMatchGroup = beginMatchGroups.Pop();
beginElementIndex = beginElementIndexes.Pop();
beginStringIndex = beginMatchGroup.Index;
beginStringLength = beginMatchGroup.Length;
endElementIndex = idx;
endStringIndex = m.Groups["end"].Captures[0].Index;
endStringLength = m.Groups["end"].Captures[0].Length;
}
var additions = new List<PageElement>();
{
// 退避 ret.GetRange() -> additions, ret.RemoveRange()
additions.AddRange(ret.GetRange(beginElementIndex, endElementIndex - beginElementIndex + 1));
ret.RemoveRange(beginElementIndex, endElementIndex - beginElementIndex + 1);
idx = beginElementIndex - 1;
//endElementIndex = -1;
}
{
Debug.Assert(beginElementIndex <= endElementIndex);
var subs = new string[6] { "", "", "", "", "", "" };
{
// additions.First()を3分割
// additions.Last()を3分割
Debug.Assert(additions.First() is PageElements.Wikitext);
Debug.Assert(additions.Last() is PageElements.Wikitext);
var first = ((PageElements.Wikitext)additions.First()).ToWikitext();
var last = ((PageElements.Wikitext)additions.Last()).ToWikitext();
subs[0] = first.Substring(0, beginStringIndex - 1 + 1);
subs[1] = first.Substring(beginStringIndex, beginStringLength);
if (beginElementIndex == endElementIndex)
{
subs[2] = "";
subs[3] = last.Substring(beginStringIndex + beginStringLength, (endStringIndex - 1) - (beginStringIndex + beginStringLength) + 1);
}
else
{
subs[2] = first.Substring(beginStringIndex + beginStringLength);
subs[3] = last.Substring(0, endStringIndex - 1 + 1);
}
subs[4] = last.Substring(endStringIndex, endStringLength);
subs[5] = last.Substring(endStringIndex + endStringLength);
Debug.Print("subs: {0}, first: {1}, last: {2}", subs.Sum(x => x.Length), first.Length, last.Length);
if (beginElementIndex == endElementIndex) Debug.Assert(subs.Sum(x => x.Length) == first.Length && subs.Sum(x => x.Length) == last.Length);
else Debug.Assert(subs.Sum(x => x.Length) == first.Length + last.Length);
}
{
{
// additions:retに追加する分
if (beginElementIndex == endElementIndex)
{
additions.Remove(additions.First());
Debug.Assert(additions.Count == 0);
}
else
{
additions.Remove(additions.First());
additions.Remove(additions.Last());
}
if (subs[2].Length > 0)
additions.Insert(0, new PageElements.Wikitext(subs[2]));
Debug.Assert(subs[1] == beginMatchGroup.Value);
additions.Insert(0, new PageElements.Affix(parent, subs[1])); // m[begin].Value
if (subs[3].Length > 0)
additions.Add(new PageElements.Wikitext(subs[3]));
Debug.Assert(subs[4] == m.Value);
additions.Add(new PageElements.Affix(parent, subs[4])); // m[end].Value
}
if (subs[5].Length > 0)
{
ret.Insert(beginElementIndex, new PageElements.Wikitext(subs[5]));
idx++;
}
if (notationClass.GetMethod("Merge") != null)
{
if (beginStringIndex == 0 && mergeTarget != null && mergeTarget.GetType().Name == notationClass.Name)
{
// 連結(既存インスタンスと統合)。新しいインスタンスは生成しない。
notationClass.GetMethod("Merge").Invoke(null, new object[] { parent, PageElements.Wikitext.Tokenize(parent, additions, targetClasses), mergeTarget });
//mergeTarget はそのまま
}
else
{
// createElement
mergeTarget = createNestableElement(notationClass, parent, PageElements.Wikitext.Tokenize(parent, additions, targetClasses));
ret.Insert(beginElementIndex, mergeTarget);
idx++;
}
}
else
{
// createElement
ret.Insert(beginElementIndex, createNestableElement(notationClass, parent, PageElements.Wikitext.Tokenize(parent, additions, targetClasses)));
idx++;
}
if (subs[0].Length > 0)
{
ret.Insert(beginElementIndex, new PageElements.Wikitext(subs[0]));
idx++;
}
}
idx--; // 追加された最後の要素を指すように、直後に実行されるidx++に合わせて調整
break;
//continue;
}
}
else
{
//Debug.Fail(m.Value);
}
m = m.NextMatch();
}
}
else
{
}
idx++;
}
return ret;
}
public override void Accept(PageElementVisitor visitor)
{
throw new NotImplementedException();
}
public override void InAction()
{
throw new NotImplementedException();
}
public override string CreateTag()
{
throw new NotImplementedException();
}
public static string[] Patterns;
public Nestable(PageElement parent, List<PageElement> children)
: base(parent, children)
{
}
}
}