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

namespace StrokeStyleT
{
	// User クラス

	class User : IDisposable
	{
		public string stg名前
		{
			get
			{
				lock( this )
				{
					this.Disposed.tDispose済みまたは実行中なら例外発生( "User" );
					return this._stg名前;
				}
			}
			set
			{
				lock( this )
				{
					this.Disposed.tDispose済みまたは実行中なら例外発生( "User" );
					this._stg名前 = value;
				}
			}
		}
		public Options Options	// ユーザ毎にオプションを持つ
		{
			get
			{
				lock( this )
				{
					this.Disposed.tDispose済みまたは実行中なら例外発生( "User" );
					return this._Options;
				}
			}
		}
		public Songs Songs		// ユーザ毎に曲リストを持つ
		{
			get
			{
				lock( this )
				{
					this.Disposed.tDispose済みまたは実行中なら例外発生( "User" );
					return this._Songs;
				}
			}
		}

		public User()
		{
			this._stg名前 = null;
		}

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

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

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

					if( XmlNodeType.Element == reader.NodeType )
					{
						switch( reader.Name )
						{
							case "名前":
								Global.tXMLのテキスト要素を読み込む( reader, ( value ) => {
									this._stg名前 = reader.Value;
								} );
								break;

							case "Option":
								this._Options.Load( reader );
								break;

							case "Songs":
								this._Songs.Load( reader );
								break;
						}
					}
				}
			}
		}
		public void Save( XmlTextWriter writer )
		{
			lock( this )
			{
				this.Disposed.tDispose済みまたは実行中なら例外発生( "User" );

				writer.WriteElementString( "名前", null, this._stg名前 );
				this._Options.Save( writer );
				this._Songs.Save( writer );
			}
		}

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

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

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

					if( null != this._Songs )
						this._Songs.Dispose();

					if( null != this._Options )
						this._Options.Dispose();
				}

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

		private readonly CDisposed Disposed = new CDisposed();

		private string _stg名前;
		private readonly Options _Options = new Options();
		private readonly Songs _Songs = new Songs();
	}


	// Users クラス

	class Users : List<User>, IDisposable
	{
		public Users()
		{
			this._SelectedUserIndex = -1;
		}

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

				var xmlFiles = Directory.EnumerateFiles( Global.Folders.stgユーザ共通フォルダパス, @"User_*.xml" );

				foreach( var file in xmlFiles )
				{
					var xr = new XmlTextReader( new StreamReader( file ) );		// file はフルパスである

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

							if( XmlNodeType.Element == xr.NodeType )
							{
								switch( xr.Name )
								{
									case "User":
										if( !xr.IsEmptyElement )
										{
											var us = new User();
											us.Load( xr );
											this.Add( us );
										}
										break;
								}
							}
						}
					}
					finally
					{
						xr.Close();
					}
				}
			}
		}
		public void Save()
		{
			lock( this )
			{
				this.Disposed.tDispose済みまたは実行中なら例外発生( "Users" );

				foreach( var user in this )
				{
					var xw = new XmlTextWriter( new StreamWriter( Path.Combine( Global.Folders.stgユーザ共通フォルダパス, @"User_" + user.stg名前 + @".xml" ) ) );

					try
					{
						xw.Formatting = Formatting.Indented;

						xw.WriteStartDocument();
						xw.WriteStartElement( null, "User", null );

						user.Save( xw );

						xw.WriteEndElement();
						xw.WriteEndDocument();
					}
					finally
					{
						xw.Close();
					}
				}
			}
		}

		public int SelectedUserIndex	// これを外部から修正すると
		{
			get
			{
				lock( this )
				{
					this.Disposed.tDispose済みまたは実行中なら例外発生( "Users" );
					return this._SelectedUserIndex;
				}
			}
			set
			{
				lock( this )
				{
					this.Disposed.tDispose済みまたは実行中なら例外発生( "Users" );
					this._SelectedUserIndex = value;
				}
			}
		}
		public User SelectedUser		// これから User を取得できる。
		{
			get
			{
				lock( this )
				{
					this.Disposed.tDispose済みまたは実行中なら例外発生( "Users" );

					if( this._SelectedUserIndex < 0 || this._SelectedUserIndex >= this.Count )
						return null;

					return this[ this._SelectedUserIndex ];
				}
			}
		}

		public void tユーザを選択する( string stgユーザ名 )
		{
			lock( this )
			{
				this.Disposed.tDispose済みまたは実行中なら例外発生( "Users" );
				this._SelectedUserIndex = this.FindIndex( ( user ) => { return user.stg名前.Equals( stgユーザ名 ); } );	// FindIndex() は、見つからなかったら -1 を返す。
			}
		}

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

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

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

					this.Save();					// 内容を保存。

					foreach( var user in this )		// ユーザオブジェクトの解放。
						user.Dispose();

					this.Clear();					// ユーザリストをクリア。
				}

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

		private readonly CDisposed Disposed = new CDisposed();
		private int _SelectedUserIndex;
	}
}
