using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.IO;
using System.Drawing;
using FDK;

namespace StrokeStyleT
{
	class Options :IDisposable
	{
		public float fスクロールスピード
		{
			get
			{
				lock( this )
				{
					this.Disposed.tDispose済みまたは実行中なら例外発生( "Options" );
					return this._fスクロールスピード;
				}
			}
			set
			{
				lock( this )
				{
					this.Disposed.tDispose済みまたは実行中なら例外発生( "Options" );
					this._fスクロールスピード = value;
				}
			}
		}
		public bool bチャイナが左にある
		{
			get
			{
				lock( this )
				{
					this.Disposed.tDispose済みまたは実行中なら例外発生( "Options" );
					return this._bチャイナが左にある;
				}
			}
			set
			{
				lock( this )
				{
					this.Disposed.tDispose済みまたは実行中なら例外発生( "Options" );
					this._bチャイナが左にある = value;
				}
			}
		}
		public bool bチャイナが右にある
		{
			get { return !this.bチャイナが左にある; }
			set { this.bチャイナが左にある = !value; }
		}
		public bool bライドが左にある
		{
			get
			{
				lock( this )
				{
					this.Disposed.tDispose済みまたは実行中なら例外発生( "Options" );
					return this._bライドが左にある;
				}
			}
			set
			{
				lock( this )
				{
					this.Disposed.tDispose済みまたは実行中なら例外発生( "Options" );
					this._bライドが左にある = value;
				}
			}
		}
		public bool bライドが右にある
		{
			get { return !this.bライドが左にある; }
			set { this.bライドが左にある = !value; }
		}
		public bool bスプラッシュが左にある
		{
			get
			{
				lock( this )
				{
					this.Disposed.tDispose済みまたは実行中なら例外発生( "Options" );
					return this._bスプラッシュが左にある;
				}
			}
			set
			{
				lock( this )
				{
					this.Disposed.tDispose済みまたは実行中なら例外発生( "Options" );
					this._bスプラッシュが左にある = value;
				}
			}
		}
		public bool bスプラッシュが右にある
		{
			get { return !this.bスプラッシュが左にある; }
			set { this.bスプラッシュが左にある = !value; }
		}
		public bool b自動演奏
		{
			get
			{
				lock( this )
				{
					this.Disposed.tDispose済みまたは実行中なら例外発生( "Options" );
					return this._b自動演奏;
				}
			}
			set
			{
				lock( this )
				{
					this.Disposed.tDispose済みまたは実行中なら例外発生( "Options" );
					this._b自動演奏 = value;
				}
			}
		}
		public Dictionary<Eヒット判定, int> dicヒット判定toRange
		{
			get
			{
				lock( this )
				{
					this.Disposed.tDispose済みまたは実行中なら例外発生( "Options" );
					return this._dicヒット判定toRange;
				}
			}
			set
			{
				lock( this )
				{
					this.Disposed.tDispose済みまたは実行中なら例外発生( "Options" );
					this._dicヒット判定toRange = value;
				}
			}
		}
		public Size sz全画面
		{
			get
			{
				lock( this )
				{
					this.Disposed.tDispose済みまたは実行中なら例外発生( "Config" );
					return this._sz全画面;
				}
			}
			set
			{
				lock( this )
				{
					this.Disposed.tDispose済みまたは実行中なら例外発生( "Config" );
					this._sz全画面 = value;
				}
			}
		}
		public bool b全画面モード
		{
			get
			{
				lock( this )
				{
					this.Disposed.tDispose済みまたは実行中なら例外発生( "Config" );
					return this._b全画面モード;
				}
			}
			set
			{
				lock( this )
				{
					this.Disposed.tDispose済みまたは実行中なら例外発生( "Config" );
					this._b全画面モード = value;
				}
			}
		}
		public int n譜面ボード透明度
		{
			get
			{
				lock( this )
				{
					this.Disposed.tDispose済みまたは実行中なら例外発生( "Config" );
					return this._n譜面ボード透明度;
				}
			}
			set
			{
				lock( this )
				{
					this.Disposed.tDispose済みまたは実行中なら例外発生( "Config" );
					this._n譜面ボード透明度 = Math.Min( Math.Max( value, 0 ), 255 );
				}
			}
		}

		public Options()
		{
			// 極めて個人的に決定された初期値。

			this._fスクロールスピード = 2.0f;
			this._bチャイナが左にある = false;
			this._bライドが左にある = false;
			this._bスプラッシュが左にある = true;
			this._b自動演奏 = false;
			this._dicヒット判定toRange = new Dictionary<Eヒット判定, int>( 6 ) {
				{ Eヒット判定.PERFECT, 34 },
				{ Eヒット判定.GREAT, 67 },
				{ Eヒット判定.GOOD, 84 },
				{ Eヒット判定.POOR, 117 },
				{ Eヒット判定.MISS, 0 },	// 使わない
				{ Eヒット判定.AUTO, 0 },	// 使わない
			};
			this._b全画面モード = false;
			this._n譜面ボード透明度 = 255;
		}

		#region [ Dispose-Finalize パターン ]
		//-------------------------
		public void Dispose()
		{
			if( this.Disposed.bDispose済みまたは処理中である )
				return;		// 例外を発出させない。

			if( !this.Disposed.t開始を宣言する() )
				return;		// 例外を発出させない。

			this.Dispose( true );
			GC.SuppressFinalize( this );
		}
		//~Options() { this.Dispose( false ); }		Unmanaged がないのでファイナライザは無し
		protected void Dispose( bool bReleaseManaged )
		{
			lock( this )
			{
				if( bReleaseManaged )
				{
					// TODO: ここで Managed を解放する

					if( null == this._dicヒット判定toRange )
					{
						this._dicヒット判定toRange.Clear();
						this._dicヒット判定toRange = null;
					}
				}

				// TODO: ここで Unmanaged を解放する
			}
		}
		//-------------------------
		#endregion

		public void Load( XmlTextReader reader )
		{
			lock( this )
			{
				this.Disposed.tDispose済みまたは実行中なら例外発生( "Options" );

				if( reader.NodeType != XmlNodeType.Element || !reader.Name.Equals( "Option" ) || reader.IsEmptyElement )
					return;

				while( reader.Read() )
				{
					bool bValue;
					float fValue;
					int nValue;
					string attrib;

					if( reader.NodeType == XmlNodeType.EndElement && reader.Name.Equals( "Option" ) )
						break;	// </Option>

					if( reader.NodeType == XmlNodeType.Element )
					{
						switch( reader.Name )
						{
							case "ScrollSpeed":
								Global.tXMLのテキスト要素を読み込む( reader, ( value ) => {
									if( float.TryParse( value, out fValue ) )
										this.fスクロールスピード = fValue;
								} );
								continue;

							case "ChinaPosition":
								Global.tXMLのテキスト要素を読み込む( reader, ( value ) => {
									this.bチャイナが右にある = ( value.Equals( "Right" ) );
								} );
								continue;

							case "RidePosition":
								Global.tXMLのテキスト要素を読み込む( reader, ( value ) => {
									this.bライドが右にある = ( value.Equals( "Right" ) );
								} );
								continue;

							case "SplashPosition":
								Global.tXMLのテキスト要素を読み込む( reader, ( value ) => {
									this.bスプラッシュが右にある = ( value.Equals( "Right" ) );
								} );
								continue;

							case "AutoPlay":
								Global.tXMLのテキスト要素を読み込む( reader, ( value ) => {
									if( bool.TryParse( value, out bValue ) )
										this.b自動演奏 = bValue;
								} );
								continue;

							case "HitRange":
								if( !reader.IsEmptyElement )
								{
									while( reader.Read() )
									{
										if( reader.NodeType == XmlNodeType.EndElement && reader.Name.Equals( "HitRange" ) )
											break;	// </HitRange>

										switch( reader.Name )
										{
											case "Perfect":
												Global.tXMLのテキスト要素を読み込む( reader, ( value ) => {
													if( int.TryParse( value, out nValue ) )
														this.dicヒット判定toRange[ Eヒット判定.PERFECT ] = nValue;
												} );
												continue;

											case "Great":
												Global.tXMLのテキスト要素を読み込む( reader, ( value ) => {
													if( int.TryParse( value, out nValue ) )
														this.dicヒット判定toRange[ Eヒット判定.GREAT ] = nValue;
												} );
												continue;

											case "Good":
												Global.tXMLのテキスト要素を読み込む( reader, ( value ) => {
													if( int.TryParse( value, out nValue ) )
														this.dicヒット判定toRange[ Eヒット判定.GOOD ] = nValue;
												} );
												continue;

											case "Poor":
												Global.tXMLのテキスト要素を読み込む( reader, ( value ) => {
													if( int.TryParse( value, out nValue ) )
														this.dicヒット判定toRange[ Eヒット判定.POOR ] = nValue;
												} );
												continue;

											default:
												continue;	// その他はデフォルトの初期値のまま
										}
									}
								}
								continue;

							case "Fullscreen":
								attrib = reader.GetAttribute( "Status" );
								this._b全画面モード = attrib.Equals( "Enable" ) ? true : false;
								attrib = reader.GetAttribute( "Width" );
								this._sz全画面.Width = ( string.IsNullOrEmpty( attrib ) ) ? 0 : int.Parse( attrib );
								attrib = reader.GetAttribute( "Height" );
								this._sz全画面.Height = ( string.IsNullOrEmpty( attrib ) ) ? 0 : int.Parse( attrib );
								continue;

							case "LanesBoard":
								attrib = reader.GetAttribute( "Transparency" );
								this.n譜面ボード透明度 =	// setで値域チェックさせるためプロパティのほうへ代入。
									( string.IsNullOrEmpty( attrib ) ) ? 0 : int.Parse( attrib );
								continue;
						}
					}
				}
			}
		}
		public void Save( XmlTextWriter writer )
		{
			lock( this )
			{
				this.Disposed.tDispose済みまたは実行中なら例外発生( "Options" );

				writer.WriteStartElement( null, "Option", null );		// <Option>

				// <ScrollSpeed>

				writer.WriteElementString( "ScrollSpeed", this.fスクロールスピード.ToString() );

				// <～Position>

				writer.WriteElementString( "ChinaPosition", ( this.bチャイナが右にある ) ? "Right" : "Left" );
				writer.WriteElementString( "RidePosition", ( this.bライドが右にある ) ? "Right" : "Left" );
				writer.WriteElementString( "SplashPosition", ( this.bスプラッシュが右にある ) ? "Right" : "Left" );

				// <AutoPlay>

				writer.WriteElementString( "AutoPlay", this.b自動演奏.ToString() );

				// <HitRange>

				writer.WriteStartElement( "HitRange" );
				writer.WriteElementString( "Perfect", this.dicヒット判定toRange[ Eヒット判定.PERFECT ].ToString() );
				writer.WriteElementString( "Great", this.dicヒット判定toRange[ Eヒット判定.GREAT ].ToString() );
				writer.WriteElementString( "Good", this.dicヒット判定toRange[ Eヒット判定.GOOD ].ToString() );
				writer.WriteElementString( "Poor", this.dicヒット判定toRange[ Eヒット判定.POOR ].ToString() );
				writer.WriteEndElement();

				// <Fullscreen>

				writer.WriteStartElement( null, "Fullscreen", null );
				writer.WriteAttributeString( "Status", this._b全画面モード ? "Enable" : "Disable" );
				writer.WriteAttributeString( "Width", this._sz全画面.Width.ToString() );
				writer.WriteAttributeString( "Height", this._sz全画面.Height.ToString() );
				writer.WriteEndElement();

				// <LanesBoard>

				writer.WriteStartElement( null, "LanesBoard", null );
				writer.WriteAttributeString( "Transparency", this._n譜面ボード透明度.ToString() );
				writer.WriteEndElement();

	
				writer.WriteEndElement();								// </Option>
			}
		}

		private readonly CDisposed Disposed = new CDisposed();

		private float _fスクロールスピード;
		private bool _bチャイナが左にある;
		private bool _bライドが左にある;
		private bool _bスプラッシュが左にある;
		private bool _b自動演奏;
		private Dictionary<Eヒット判定, int> _dicヒット判定toRange;
		private Size _sz全画面 = new Size( Theme.sz描画サイズ原寸px.Width, Theme.sz描画サイズ原寸px.Height );	// 初期希望サイズ
		private bool _b全画面モード;
		private int _n譜面ボード透明度;
	}
}
