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

namespace ClipClop.User
{
	public abstract class ContextMenuSettingHelper
	{
		static readonly CultureInfo jpCulture_;
		static readonly CultureInfo enCulture_;

		class Trans
		{
			protected readonly string meta_;
			protected readonly string format_;
			protected readonly CultureInfo culture_;

			public int CompLen
			{
				get
				{
					return this.meta_.Length;
				}
			}

			public virtual string Rep(DateTime now)
			{
				if (this.culture_ == null)
					return now.ToString(this.format_);

				return now.ToString(this.format_, this.culture_);
			}

			public bool Compare(string s)
			{
				return string.Compare(this.meta_, 0, s, 0, this.meta_.Length) == 0 ? true : false;
			}

			public Trans(string meta, string format, CultureInfo culture)
			{
				this.meta_ = meta;
				this.format_ = format;
				this.culture_ = culture;
			}
		}

		class TransEscapeSequence : Trans
		{
			public TransEscapeSequence()
				: base(@"\\", "", null)
			{
			}

			public override string Rep(DateTime now)
			{
				return @"\";
			}
		}

		class TransYear : Trans
		{
			public TransYear(string meta, string format, CultureInfo culture)
				: base(meta, format, culture)
			{
			}

			public override string Rep(DateTime now)
			{
				if (this.culture_ == null)
					return now.Year.ToString(this.format_);

				return now.Year.ToString(this.format_, this.culture_);
			}
		}

		static readonly Trans[] transTable_;

		static ContextMenuSettingHelper()
		{
			jpCulture_ = new CultureInfo("ja-JP");
			jpCulture_.DateTimeFormat.Calendar = new System.Globalization.JapaneseCalendar();

			enCulture_ = new CultureInfo("en-US");


			transTable_ = new Trans[]{
				new Trans(@"\x", "%y/%M/%d",null),	//0 YY/MM/DD 
				new Trans(@"\0x","yy/MM/dd",null),	//1 YY/MM/DD
				new Trans(@"\g", "gyy",jpCulture_),	//2 平成XX年
				new Trans(@"\m", "MM",null),	//3 YY月
				new Trans(@"\d", "dd",null),	//4 ZZ日
				new Trans(@"\B", "MMMM",enCulture_),	//5 January～December
				new Trans(@"\w", "ddd",jpCulture_),	//6 日～土
				new Trans(@"\A", "dddd",enCulture_),	//7 Sunday～Saturday
				new Trans(@"\X", "HH:mm:ss",null),	//8 （24時間）23:59:00
				new Trans(@"\r", "hh:mm:ss tt",enCulture_),	//9 （12時間）10:12:30 AM
				new TransYear(@"\Y", "",enCulture_),	//10 2009
				new Trans(@"\0m","MM",null),	//11 YY月
				new Trans(@"\0d","dd",null),	//12 ZZ日
				new TransEscapeSequence(),
			};
        }


        //TODO これは移す
        #region Attribute    

        public static bool SetValueAttribute(XmlNode node, string str, XmlDocument doc)
        {
            if (ContextMenuSettingDefinition.Sentence_ == node.Name)
            {
                XmlAttribute attri = node.Attributes[ContextMenuSettingDefinition.Value_];
                if (null == attri)
                {
                    attri = doc.CreateAttribute(ContextMenuSettingDefinition.Value_);
                    node.Attributes.Append(attri);
                }
                attri.Value = str;
                return true;
            }
            return false;
        }

        public static bool SetNameAttribute(XmlNode node, string str, XmlDocument doc)
        {
            if (ContextMenuSettingDefinition.Sentence_ == node.Name ||
                ContextMenuSettingDefinition.Folder_ == node.Name)
            {
                XmlAttribute attri = node.Attributes[ContextMenuSettingDefinition.Name_];
                if (attri == null)
                {
                    attri = doc.CreateAttribute(ContextMenuSettingDefinition.Name_);
                    node.Attributes.Append(attri);
                }

                attri.Value = str;
                return true;
            }
            return false;
        }

        public static bool RemoveNameAttribute(XmlNode node)
        {
            if (ContextMenuSettingDefinition.Sentence_ == node.Name)
            {
                XmlAttribute attri = node.Attributes[ContextMenuSettingDefinition.Name_];
                if (attri == null)
                {
                    return true;
                }

                node.Attributes.Remove(attri);
                return true;
            }
            return false;
        }


        public static bool SetTypeAttribute(XmlNode node, ContextMenuSettingDefinition.SentenceType sentenceType)
        {
            if (ContextMenuSettingDefinition.Sentence_ == node.Name)
            {
                XmlAttribute attri = node.Attributes[ContextMenuSettingDefinition.Type_];
                if (null == attri)
                {
                    //これは必ずあるはず
                    return false;
                }
                attri.Value = sentenceType.ToString();
                return true;
            }
            return false;
        }
        #endregion

        public static bool IsRoot(XmlNode root)
		{
            if (string.IsNullOrEmpty(XmlNodeHelper.GetAttributeValue(root, ContextMenuSettingDefinition.RootAttribute.magicnumber.ToString()))
                || string.IsNullOrEmpty(XmlNodeHelper.GetAttributeValue(root, ContextMenuSettingDefinition.RootAttribute.version.ToString())))
			{
				return false;
			}

			return true;
		}

		const char ESCAPE_SEQUENCE = '\\';

		public static string GetValueReplaced(XmlNode node, DateTime now)
		{
            string value = XmlNodeHelper.GetDisplayValue(node);
			if (string.IsNullOrEmpty(value))
				return string.Empty;

			if (!value.Contains(ESCAPE_SEQUENCE))
				return value;

			StringBuilder sb = new StringBuilder();

			for (int idx = 0; idx < value.Length; idx++)
			{
				if (value[idx] != ESCAPE_SEQUENCE)
				{
					sb.Append(value[idx]);
					continue;
				}

				bool hit = false;
				foreach (Trans t in transTable_)
				{
					int leftLength = value.Length - idx;

					if (leftLength < t.CompLen )
						continue;

					if (!t.Compare(value.Substring(idx)))
						continue;

					sb.Append(t.Rep(now));

					idx = idx + t.CompLen - 1;//forループでインクリメントされるから
					hit = true;
				}

				if (!hit)
				{
					sb.Append(value[idx]);
					continue;
				}
			}

			return string.Format(sb.ToString());
		}		

	}
}
