using System;
using System.Collections.Generic;
using System.Text;

namespace DTXMania
{
	/// <summary>
	/// <para>DTXMania のバージョン。</para>
	/// <para>例1："078b" → 整数部=078, 小数部=2000000 ('英字'+'yymmdd') </para>
	/// <para>例2："078a(100124)" → 整数部=078, 小数部=1100124 ('英字'+'yymmdd')</para>
	/// </summary>
	public class CDTXVersion
	{
		// プロパティ

		/// <summary>
		/// <para>バージョンが未知のときに true になる。</para>
		/// </summary>
		public bool Unknown
		{
			get;
			private set;
		}

		/// <summary>
		/// <para>DTXMania のバージョンの整数部を表す。</para>
		/// <para>例1："078b" → 整数部=078</para>
		/// <para>例2："078a(100124)" → 整数部=078</para>
		/// </summary>
		public int n整数部;

		/// <summary>
		/// <para>DTXMania のバージョンの小数部を表す。</para>
		/// <para>小数部は、'英字(0～26) * 1000000 + 日付(yymmdd)' の式で表される整数。</para>
		/// <para>例1："078b" → 小数部=2000000 </para>
		/// <para>例2："078a(100124)" → 小数部=1100124</para>
		/// </summary>
		public int n小数部;


		// コンストラクタ

		public CDTXVersion()
		{
			this.n整数部 = 0;
			this.n小数部 = 0;
			this.Unknown = true;
		}
		public CDTXVersion(int n整数部)
		{
			this.n整数部 = n整数部;
			this.n小数部 = 0;
			this.Unknown = false;
		}
		public CDTXVersion(string Version)
		{
			this.n整数部 = 0;
			this.n小数部 = 0;
			this.Unknown = true;

			if (Version.ToLower().Equals("unknown"))
			{
				this.Unknown = true;
			}
			else
			{
				int num = 0;
				int length = Version.Length;
				if ((num < length) && char.IsDigit(Version[num]))
				{
					// 整数部　取得
					while ((num < length) && char.IsDigit(Version[num]))
					{
						this.n整数部 = (this.n整数部 * 10) + CDTXVersion.DIG10.IndexOf(Version[num++]);
					}

					// 小数部(1)英字部分　取得
					while ((num < length) && ((Version[num] == ' ') || (Version[num] == '(')))
					{
						num++;
					}
					if ((num < length) && (CDTXVersion.DIG36.IndexOf(Version[num]) >= 10))
					{
						this.n小数部 = CDTXVersion.DIG36.IndexOf(Version[num++]) - 10;
						if (this.n小数部 >= 0x1a)
						{
							this.n小数部 -= 0x1a;
						}
						this.n小数部++;
					}

					// 小数部(2)日付部分(yymmdd)　取得
					while ((num < length) && ((Version[num] == ' ') || (Version[num] == '(')))
					{
						num++;
					}
					for (int i = 0; i < 6; i++)
					{
						this.n小数部 *= 10;
						if ((num < length) && char.IsDigit(Version[num]))
						{
							this.n小数部 += CDTXVersion.DIG10.IndexOf(Version[num]);
						}
						num++;
					}
					this.Unknown = false;
				}
				else
				{
					this.Unknown = true;
				}
			}
		}
		public CDTXVersion(int n整数部, int n小数部)
		{
			this.n整数部 = n整数部;
			this.n小数部 = n小数部;
			this.Unknown = false;
		}


		// メソッド

		public string toString()
		{
			var result = new StringBuilder(32);

			// 整数部
			result.Append(this.n整数部.ToString("000"));

			// 英字部分（あれば）
			if (this.n小数部 >= 1000000)
			{
				int n英字 = Math.Min(this.n小数部 / 1000000, 26);  // 1～26
				result.Append(CDTXVersion.DIG36[10 + (n英字 - 1)]);
			}

			// 日付部分（あれば）
			int n日付 = this.n小数部 % 1000000;
			if (n日付 > 0)
			{
				result.Append('(');
				result.Append(n日付.ToString("000000"));
				result.Append(')');
			}

			return result.ToString();
		}

		public static bool operator ==(CDTXVersion x, CDTXVersion y)
		{
			return (((x.n整数部 == y.n整数部) && (x.n小数部 == y.n小数部)) && (x.Unknown == y.Unknown));
		}
		public static bool operator >(CDTXVersion x, CDTXVersion y)
		{
			return ((x.n整数部 > y.n整数部) || ((x.n整数部 == y.n整数部) && (x.n小数部 > y.n小数部)));
		}
		public static bool operator >=(CDTXVersion x, CDTXVersion y)
		{
			return ((x.n整数部 > y.n整数部) || ((x.n整数部 == y.n整数部) && (x.n小数部 >= y.n小数部)));
		}
		public static bool operator !=(CDTXVersion x, CDTXVersion y)
		{
			if ((x.n整数部 == y.n整数部) && (x.n小数部 == y.n小数部))
			{
				return (x.Unknown != y.Unknown);
			}
			return true;
		}
		public static bool operator <(CDTXVersion x, CDTXVersion y)
		{
			return ((x.n整数部 < y.n整数部) || ((x.n整数部 == y.n整数部) && (x.n小数部 < y.n小数部)));
		}
		public static bool operator <=(CDTXVersion x, CDTXVersion y)
		{
			return ((x.n整数部 < y.n整数部) || ((x.n整数部 == y.n整数部) && (x.n小数部 <= y.n小数部)));
		}
		public override bool Equals(object obj)     // 2011.1.3 yyagi: warningを無くすために追加
		{
			if (obj == null)
			{
				return false;
			}
			if (this.GetType() != obj.GetType())
			{
				return false;
			}
			CDTXVersion objCDTXVersion = (CDTXVersion)obj;
			if (!int.Equals(this.n整数部, objCDTXVersion.n整数部) || !int.Equals(this.n小数部, objCDTXVersion.n小数部))
			{
				return false;
			}
			return true;
		}
		public override int GetHashCode()       // 2011.1.3 yyagi: warningを無くすために追加
		{
			string v = this.toString();
			return v.GetHashCode();
		}

		// その他

		#region [ private ]
		//-----------------
		private const string DIG36 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
		private const string DIG10 = "0123456789";
		//-----------------
		#endregion
	}
}
