using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using CaLib.User;
using System.Diagnostics;

namespace ClipClop.User
{
	/// <summary>
	/// 改行だけの行は無視される
	/// - だけの行はセパレータ
	/// > が先頭にある行は階層化する
	/// *EX tab 表示する文字列:コマンド文字列
	/// *E	NOTEPAD "%1"
	/// *T	テキスト履歴(&T)
	/// *C	クリップボード履歴(&C)
	/// *P	テキスト(&P)
	/// </summary>
    public class QtClipContextMenuReader : IContextMenuReader
    {
		XmlCipheredDocument doc_;

		public XmlCipheredDocument GetDocument()
		{
			return this.doc_;
		}


		/// <summary>
		/// 読み込み処理。何かあると例外投入する。
		/// </summary>
		/// <param name="filePath"></param>
		public void Read(string filePath)
        {
            doc_ = XmlCipheredDocument.CreateEmptyDocument();

			using( FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read ))
			{
				using (StreamReader sr = new StreamReader(fs, Encoding.GetEncoding("Shift_JIS")))
				{
					int count = 0;
					string line = "";
					XmlNode currentElement = doc_.GetRoot();

					while ((line = sr.ReadLine()) != null)
					{
						count++;
						currentElement = Parse(currentElement, line);

						if (currentElement == null)
						{
							throw new FundamentalException(string.Format(global::ClipClop.Properties.Resources.EF001, filePath, count));
						}
					}
				}
			}
			//doc_.Save(filePath+".test");
        }


		/// <summary>
		/// 読み込んだ文字列の解析を行う。
		/// </summary>
		/// <param name="currentElement"></param>
		/// <param name="line"></param>
		/// <returns></returns>
		XmlNode Parse(XmlNode currentElement, string line)
		{
			if (string.IsNullOrEmpty(line) )
			{
				//改行だけの行は無視される
				return currentElement;
			}

			if ( line[0] == '\t')
			{
				//タブが行頭にある行はコメント...何も足さない
				return currentElement;
			}

			if (line == "-")
			{
				// - だけの行はセパレータ
                XmlElement newElement = XmlNodeHelper.CreateXmlNode(
                    ContextMenuSettingDefinition.Classification.separator,
                    ContextMenuSettingDefinition.SentenceType.non, 
                    null, 
                    null, 
                    doc_);
                currentElement.AppendChild(newElement);
				return currentElement;
			}

			if (line[0] == '>')
			{
				// > が先頭にある行は階層化する
                XmlElement newElement = XmlNodeHelper.CreateXmlNode(
                    ContextMenuSettingDefinition.Classification.folder,
                    ContextMenuSettingDefinition.SentenceType.non, 
                    line.Substring(1), 
                    null, 
                    doc_);
                currentElement.AppendChild(newElement);
                return newElement;
			}
			if (line[0] == '<')
			{ 
				//親に移動する。
				return currentElement.ParentNode;
			}

			// 定型文
			if (!ParseSentence(currentElement, line, this.doc_))
			{
				return null;
			}
			return currentElement;
		}

		/// <summary>
		/// 読み込んだ定型文定義行を解析する。
		/// </summary>
		/// <param name="currentElement"></param>
		/// <param name="line"></param>
		/// <param name="doc"></param>
		/// <returns></returns>
		static bool ParseSentence(XmlNode currentElement, string line, XmlDocument doc)
		{
			int tabIndex = line.IndexOf('\t');

			if (line[0] == '*' && tabIndex == 1)
			{
				//特殊な定型文
				//"*" とタブが行頭にあると、その行はすべて分割して表示

				string s = line.Substring(tabIndex + 1).TrimStart();

				for( int i = 0; i < s.Length; i++ )
				{
                    //name要素は要らない
                    XmlElement node = XmlNodeHelper.CreateXmlNode(
                        ContextMenuSettingDefinition.Classification.sentence,
                        ContextMenuSettingDefinition.SentenceType.template,
                        null,
                        string.Format("{0}", s[i]),
                        doc);

					currentElement.AppendChild(node);
				}
				return true;
			}

			if (tabIndex < 0)
			{
				//名前省略
                XmlElement sentence = XmlNodeHelper.CreateXmlNode(
                    ContextMenuSettingDefinition.Classification.sentence,
                    ContextMenuSettingDefinition.SentenceType.template,
                    null,
                    line,
                    doc);

				currentElement.AppendChild(sentence);
				return true;
			}

			//タブ文字がある場合...先頭がタブ文字であることはない
			Debug.Assert(tabIndex > 0);

			if (line[0] == '*' && tabIndex == 2 )
			{
				// *T とかに続けてタブ文字の場合
				//何か実行する
                XmlElement sentence = null;

				switch (line[1])
				{
					case 'T': //テキスト保管一覧
						//sentence.SetAttribute(ContextMenuSettingDefinition.Type_, ContextMenuSettingDefinition.Mode.textfile.ToString());
						//sentence.SetAttribute(ContextMenuSettingDefinition.Name_, line.Substring(tabIndex + 1).TrimStart());
						//break;
						return true; //無視することにした

					case 'P': //テキスト保管２の一覧
						//sentence.SetAttribute(ContextMenuSettingDefinition.Type_, ContextMenuSettingDefinition.Mode.textfile.ToString());
						//sentence.SetAttribute(ContextMenuSettingDefinition.Name_, line.Substring(tabIndex + 1).TrimStart());
						//break;
						return true; //無視することにした

					case 'C': //クリップボード履歴
                        sentence = XmlNodeHelper.CreateXmlNode(
                            ContextMenuSettingDefinition.Classification.sentence,
                            ContextMenuSettingDefinition.SentenceType.clipboardhistory,
                            line.Substring(tabIndex + 1).TrimStart(),
                            line.Substring(tabIndex + 1).TrimStart(),
                            doc);
						break;

					case 'E': //メニュー定義ファイルの編集(%1 はメニュー定義ファイル名で置き換えられる)
                        sentence = XmlNodeHelper.CreateXmlNode(
                            ContextMenuSettingDefinition.Classification.sentence,
                            ContextMenuSettingDefinition.SentenceType.editfile,
                            null,
                            line.Substring(tabIndex + 1).TrimStart(),
                            doc);
						break;

					default:
						return false;
				}
				
                currentElement.AppendChild(sentence);
				return true;
			}

			if (line.StartsWith("*EX\t"))
			{
				//*EX の場合

				//"*EX" とタブが行頭にあると、任意のコマンド実行
				//文字列をタブで区切ると、１つ目はメニューに表示される文字列、２つ目は実際に入力される文字列
				//*EX は タブの後に、「表示する文字列:コマンド文字列」を記述します。

				string tmp = line.Substring(tabIndex + 1).TrimStart();

				string[] substring = tmp.Split('\t');

				if (substring.Length == 1)
				{
					substring = tmp.Split(':');
				}

				if (substring.Length != 2 || string.IsNullOrEmpty(substring[0]) || string.IsNullOrEmpty(substring[1]))
				{
					return false;
				}

                XmlElement sentence = XmlNodeHelper.CreateXmlNode(
                    ContextMenuSettingDefinition.Classification.sentence,
                    ContextMenuSettingDefinition.SentenceType.execute,
                    substring[0],
                    substring[1],
                    doc);

				currentElement.AppendChild(sentence);

				return true;
			}

			if (line.StartsWith("*INIT\t"))
			{
				//*INIT の場合 テキスト保管２のファイルを読み込み直します。(v2.7)
				//現状何もしない
				return true;
			}


			//名前ありの定型文
			string valueString = line.Substring(tabIndex + 1).TrimStart();

            XmlElement namedTemplate = XmlNodeHelper.CreateXmlNode(
                ContextMenuSettingDefinition.Classification.sentence,
                ContextMenuSettingDefinition.SentenceType.template,
                line.Substring(0, tabIndex),
                TransValueString(valueString),
                doc);

            currentElement.AppendChild(namedTemplate);
			return true;
		}


		static string TransValueString(string s)
		{
			//何もしないことにした
			//s = s.Replace(@"\n", Environment.NewLine);
			//s = s.Replace(@"\\t", @"\t"); ...だめ
			return s;
		}

    }
}
