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

namespace StrokeStyleT
{
	// InputNote クラス - 入力データの最小単位。

	class InputNote : ICloneable
	{
		// 入力のあったデバイスのID。
		public int nデバイスID
		{
			get
			{
				lock( this )
				{
					return this._nデバイスID;
				}
			}
			set
			{
				lock( this )
				{
					this._nデバイスID = value;
				}
			}
		}

		// 入力データ。
		public int nノート番号
		{
			get
			{
				lock( this )
				{
					return this._nノート番号;
				}
			}
			set
			{
				lock( this )
				{
					this._nノート番号 = value;
				}
			}
		}

		public InputNote()
		{
			this._nデバイスID = 0;
			this._nノート番号 = 0;
		}

		public void Load( XmlTextReader reader )
		{
			if( ( XmlNodeType.Element != reader.NodeType ) || !reader.Name.Equals( "InputNote" ) )
				return;

			lock( this )
			{
				string n;

				n = reader.GetAttribute( "デバイス番号" );
				this.nデバイスID = ( string.IsNullOrEmpty( n ) ) ? 0 : int.Parse( n );

				n = reader.GetAttribute( "ノート番号" );
				this.nノート番号 = ( string.IsNullOrEmpty( n ) ) ? 0 : int.Parse( n );
			}
		}
		public void Save( XmlTextWriter writer )
		{
			lock( this )
			{
				// <InputNote デバイス番号="0" ノート番号="0" />	…… １行で出力。

				writer.WriteStartElement( null, "InputNote", null );
				writer.WriteAttributeString( "デバイス番号", this.nデバイスID.ToString() );
				writer.WriteAttributeString( "ノート番号", this.nノート番号.ToString() );
				writer.WriteEndElement();
			}
		}

		// ICloneable 実装
		public object Clone()
		{
			object objClone = null;

			lock( this )
			{
				objClone = (object) new InputNote() {
					nデバイスID = this._nデバイスID,
					nノート番号 = this._nノート番号,
				};
			}
			return objClone;
		}

		private int _nデバイスID;
		private int _nノート番号;
	}


	// PadAssign クラス

	class PadAssign : IDisposable
	{
		public Dictionary<Eドラム入力, List<InputNote>> dicドラム入力to入力ノートリスト
		{
			get
			{
				lock( this )
				{
					this.Disposed.tDispose済みまたは実行中なら例外発生( "PadAssign" );
					return this._dicドラム入力to入力ノートリスト;
				}
			}
		}

		public PadAssign()
		{
			this._dicドラム入力to入力ノートリスト = new Dictionary<Eドラム入力, List<InputNote>>();

			// 全パッド分の空のノートリストを作成。
			foreach( var pad in Enum.GetValues( typeof( Eドラム入力 ) ) )
				this._dicドラム入力to入力ノートリスト.Add( (Eドラム入力) pad, new List<InputNote>() );
		}

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

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

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

					if( null != this._dicドラム入力to入力ノートリスト )
					{
						// パッドのノートリストをクリア。
						foreach( var kvp in this._dicドラム入力to入力ノートリスト )
							kvp.Value.Clear();

						this._dicドラム入力to入力ノートリスト.Clear();
						this._dicドラム入力to入力ノートリスト = null;
					}
				}

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

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

				if( ( XmlNodeType.Element != reader.NodeType ) || !reader.Name.Equals( "PadAssign" ) || reader.IsEmptyElement )
					return;		// 空白・改行・<PadAssign>以外の要素・子要素なしの要素は無視

				while( reader.Read() )
				{
					if( ( XmlNodeType.EndElement == reader.NodeType ) && reader.Name.Equals( "PadAssign" ) )
						break;	// </PadAssign>

					if( ( XmlNodeType.Element == reader.NodeType ) && !reader.IsEmptyElement )	// 孫要素のない子要素はスキップ
					{
						Eドラム入力 eパッド;
						string stgパッド;

						if( Enum.TryParse<Eドラム入力>( reader.Name, out eパッド ) )
						{
							stgパッド = reader.Name;

							while( reader.Read() )
							{
								if( ( XmlNodeType.EndElement == reader.NodeType ) && reader.Name.Equals( stgパッド ) )
									break;

								if( ( XmlNodeType.Element == reader.NodeType ) && reader.Name.Equals( "InputNote" ) && !reader.IsEmptyElement )
								{
									var note = new InputNote();
									note.Load( reader );
									Debug.Assert( this._dicドラム入力to入力ノートリスト.ContainsKey( eパッド ) );	// コンストラクタで全パッドをdicに登録済み
									this._dicドラム入力to入力ノートリスト[ eパッド ].Add( note );
								}
							}
						}
					}
				}
			}
		}
		public void Save( XmlTextWriter writer )
		{
			lock( this )
			{
				this.Disposed.tDispose済みまたは実行中なら例外発生( "PadAssign" );

				writer.WriteStartElement( null, "PadAssign", null );	// <PadAssign>
				{
					foreach( var kvp in this._dicドラム入力to入力ノートリスト )
					{
						writer.WriteStartElement( null, kvp.Key.ToString(), null );
						{
							foreach( var note in kvp.Value )
								note.Save( writer );
						}
						writer.WriteEndElement();
					}
				}
				writer.WriteEndElement();								// </PadAssign>
			}
		}

		private readonly CDisposed Disposed = new CDisposed();
		private Dictionary<Eドラム入力, List<InputNote>> _dicドラム入力to入力ノートリスト = null;
	}
}
