using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace NovelInterpreter.Compiler
{
	/// <summary>
	/// リストにパーズされた吉里吉里構文をXMLで通用する形に直す
	/// </summary>
	public class ListParser
	{
		/// <summary>
		/// 与えられた吉里吉里構文を分割したリストから、XML形式に変換し直す
		/// </summary>
		/// <param name="list">吉里吉里構文を格納したリスト</param>
		/// <returns>
		/// 要素の種類, 要素名の順番に並んだリスト
		/// 要素の種類はElement, Attribute, Value（属性の値）, Label, Shiori, Word
		/// </returns>
		public static List<KeyValuePair<string, string>> Parse(List<string> list)
		{
			List<KeyValuePair<string, string>> result = new List<KeyValuePair<string, string>>();

			foreach (string elem in list)
			{
				List<KeyValuePair<string, string>> buf = new List<KeyValuePair<string,string>>();

				switch (elem[0])
				{
					case '[':
					case '@':
						// 要素,(属性,値)*の追加
						buf = ParseElement(elem);
						foreach (var b in buf) result.Add(b);
						break;

					case '*':
						// ラベル,しおりの追加
						buf = ParseLabel(elem);
						foreach (var b in buf) result.Add(b);
						break;

					default:
						// コメント文, 改行は除く
						if (!Regex.IsMatch(elem, "(//)|(/\\*)|(\n)"))
						{
							// 表示させる文字
							if (Regex.IsMatch(elem, "\n")) break;	// 何もなしの改行の場合は無視する
							result.Add(new KeyValuePair<string, string>("Word", elem));
						}
						break;
				}
			}
			return result;
		}

		static List<KeyValuePair<string, string>> ParseElement(string elem)
		{
			List<KeyValuePair<string, string>> result = new List<KeyValuePair<string,string>>();

			// 文字列の先頭と後端を削除
			if (elem[0] == '[')
				elem = elem.Remove(elem.Length - 1);
			elem = elem.Remove(0, 1);
			
			// スペースを含めたインジェクション回避のため
			// 先頭要素を取り除いた状態でやる
			string[] splitedSpace = elem.Split(' ');

			// 要素の印刷
			result.Add(new KeyValuePair<string, string>("Element", splitedSpace[0]));

			// 2項目以上引っかかった場合、属性を含んでいる
			if (splitedSpace.Length > 1)
			{
				// 属性を含む場合
				string combineSpace = "";
				for (int i = 1; i < splitedSpace.Length; i++)
					combineSpace += splitedSpace[i] + " ";
				combineSpace = combineSpace.Remove(combineSpace.Length - 1);	// 元に戻す

				// 属性のみマッチング
				List<string> attrs = RegexParser.Matches(combineSpace, "\\w+=((\\w+)|(\\\"([\\w\\n\\s!#-@^-~]|(\\\\\\\"|\\\\\\[|\\\\\\]|\\\\\\\\))+\\\"))");
				foreach (string attr in attrs)
				{
					// 属性名とその値を挿入
					var parsed = ParseAttribute(attr);
					result.Add(parsed[0]);	// Attribute
					result.Add(parsed[1]);	// Value
				}
			}

			return result;
		}

		/// <summary>
		/// 属性を受け取り、Attribute, Valueの順番で返す
		/// </summary>
		/// <param name="attr">走査対象の要素</param>
		/// <returns>要素、値の順番</returns>
		static KeyValuePair<string, string>[] ParseAttribute(string attr)
		{
			KeyValuePair<string, string>[] result = new KeyValuePair<string,string>[2];
			string[] splited = attr.Split('=');
			result[0] = new KeyValuePair<string, string>("Attribute", splited[0]);

			// 結合
			string combined = "";
			for (int i = 1; i < splited.Length; i++)
				combined += splited[i] + "=";
			combined = combined.Remove(combined.Length - 1);

			if (combined[0] == '"')
			{
				// "で囲ってある場合は削除
				combined = combined.Remove(0, 1);
				combined = combined.Remove(combined.Length - 1);
			}
			result[1] = new KeyValuePair<string, string>("Value", combined);

			return result;
		}

		/// <summary>
		/// ラベルを受け取り、Label, Shioriの順番で返す
		/// </summary>
		/// <param name="elem">走査対象のラベル</param>
		/// <returns>Label, Shioriの順番</returns>
		static List<KeyValuePair<string, string>> ParseLabel(string elem)
		{
			List<KeyValuePair<string, string>> result = new List<KeyValuePair<string, string>>();
			
			elem = elem.Remove(0, 1);	// 最初に*を削る
			string[] splited = elem.Split('|');	// しおりと分離させる
			result.Add(new KeyValuePair<string, string>("Label", splited[0]));
			if (splited.Length > 1)
				result.Add(new KeyValuePair<string,string>("Shiori", splited[1]));

			return result;
		}
	}
}
