using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;

namespace Babebi4
{
	public class GuiTable__WordConcatenatedComponent : DataTable
	{
		private MainForm		mainForm;

		private BabebiDataSet	dataSet
		{
			get
			{
				return this.mainForm.DataSet;
			}
		}

		#region		shortcuts about tables

		private BabebiDataSet.WordDataTable							table__word
		{
			get { return this.dataSet.Word; }
		}
		private BabebiDataSet.Word_LanguageDataTable				table__word_language
		{
			get { return this.dataSet.Word_Language; }
		}
		private BabebiDataSet.Word_LanguageWordDataTable			table__word_languageWord
		{
			get { return this.dataSet.Word_LanguageWord; }
		}
		private BabebiDataSet.LanguageWordDataTable					table__languageWord
		{
			get { return this.dataSet.LanguageWord; }
		}
		private BabebiDataSet.WordConcatenatedDataTable				table__wordConcatenated
		{
			get { return this.dataSet.WordConcatenated; }
		}
		private BabebiDataSet.WordConcatenatedComponentDataTable	table__wordConcatenatedComponent
		{
			get { return this.dataSet.WordConcatenatedComponent; }
		}

		#endregion	shortcuts about tables

		private BabebiDataSet.LanguageRow	currentLanguage
		{
			get
			{
				return this.mainForm.Current__Language;
			}
		}
		private string						currentLanguageCode
		{
			get
			{
				return this.mainForm.Current__Language.Code;
			}
		}

		public DataSet		DataSet__for_the_BindingSource;

		#region		Columns

		public DataColumn	Rank;					/// PK 
		public DataColumn	WordId;					/// hidden
		public DataColumn	WordString;				/// from parent
		public DataColumn	Word_LanguageMeaning;	//  from Word_Language
		public DataColumn	SubStringIndex;			//	native
		public DataColumn	SubStringLength;		//	native
		public DataColumn	CURRENT__WordId;		/// hidden	: la valeur de l'Id avant qu'elle ne soit modifiée dans le MainForm DataSet.

		#endregion	Columns

		#region		getters : GetValue__[columnName](guiDataRow)

		public short	GetValue__Rank(DataRow guiDataRow)					{return guiDataRow.Field<short	>(this.Rank					);}
		public int		GetValue__WordId(DataRow guiDataRow)				{return guiDataRow.Field<int	>(this.WordId				);}
		public string	GetValue__WordString(DataRow guiDataRow)			{return guiDataRow.Field<string	>(this.WordString			);}
		public string	GetValue__Word_LanguageMeaning(DataRow guiDataRow)	{return guiDataRow.Field<string	>(this.Word_LanguageMeaning	);}
		public short?	GetValue__SubStringIndex(DataRow guiDataRow)		
		{
			object subStringIndex = guiDataRow[this.SubStringIndex];		
			
			if(subStringIndex == DBNull.Value)
			{
				return null;
			}
			else
			{
				return (short)(subStringIndex);
			}
		}
		public short?	GetValue__SubStringLength(DataRow guiDataRow)		
		{
			object subStringLength = guiDataRow[this.SubStringLength];
			if(subStringLength == DBNull.Value)
			{
				return null;
			}
			else
			{
				return (short)(subStringLength);
			}
		}
		public int		GetValue__CURRENT__WordId(DataRow guiDataRow)		{return guiDataRow.Field<int	>(this.CURRENT__WordId		);}

		#endregion	getters : GetValue__[columnName](guiDataRow)

		/// ctor
		public GuiTable__WordConcatenatedComponent(MainForm mainform) : base("WordConcatenatedComponent_")
		{
			this.mainForm = mainform;

			this.DataSet__for_the_BindingSource = new DataSet("WordConcatenatedComponent__DataSet");

			this.DataSet__for_the_BindingSource.Tables.Add(this);

			#region		columns

			this.Rank					= this.Columns.Add("Rank"					, typeof(short));
			this.WordId					= this.Columns.Add("WordId"					, typeof(int));
			this.WordString				= this.Columns.Add("WordString"				, typeof(string));
			this.Word_LanguageMeaning	= this.Columns.Add("Word_LanguageMeaning"	, typeof(string));
			this.SubStringIndex			= this.Columns.Add("SubStringIndex"			, typeof(short));
			this.SubStringLength		= this.Columns.Add("SubStringLength"		, typeof(short));
			this.CURRENT__WordId		= this.Columns.Add("CURRENT__WordId"		, typeof(int));

			this.Rank					.AllowDBNull = false;
			this.WordId					.AllowDBNull = false;
			this.WordString				.AllowDBNull = false;
			this.Word_LanguageMeaning	.AllowDBNull = false;
			this.SubStringIndex			.AllowDBNull = true;
			this.SubStringLength		.AllowDBNull = true;
			this.CURRENT__WordId		.AllowDBNull = false;

			this.WordString				.MaxLength = 32;
			this.Word_LanguageMeaning	.MaxLength = 256;

			this.PrimaryKey 	= new DataColumn[]{this.Rank};

			#endregion	columns

			this.dataSet.WordConcatenatedComponent.WordConcatenatedComponentRowChanged 	+= WordConcatenatedComponent_WordConcatenatedComponentRowChanged;

			this.dataSet.Word.RowChanging			+= Word__RowChanging;
			this.dataSet.Word.RowChanged			+= Word__RowChanged;
			this.dataSet.Word.WordRowDeleting		+= Word__RowDeleting;

			this.dataSet.Word_Language.RowChanged	+= Word__Language__RowChanged; 

			this.dataSet.WordConcatenatedComponent.WordConcatenatedComponentRowDeleting += WordConcatenatedComponent_WordConcatenatedComponentRowDeleting;
		}

		#region		listening the DataSet events

		private void WordConcatenatedComponent_WordConcatenatedComponentRowChanged	(object sender, BabebiDataSet.WordConcatenatedComponentRowChangeEvent e)
		{
			if(e.Action == DataRowAction.Commit)
			{
				return;
			}

			BabebiDataSet.WordConcatenatedComponentRow wordConcatenatedComponent = e.Row;

			/// trap not-related events.
			if 
			(
				this.mainForm.Current__WordConcatenated == null 
				|| 
				wordConcatenatedComponent.RowState == DataRowState.Detached 
				|| 
				wordConcatenatedComponent.WordConcatenatedId != this.mainForm.Current__WordConcatenated.Id
			)
			{
				return;
			}

			if (e.Action == DataRowAction.Add)
			{
				this.addGuiDataRow(wordConcatenatedComponent);
			}
			else if(e.Action == DataRowAction.Change)
			{
				this.updateGuiDataRow(wordConcatenatedComponent);
			}
		}
		private void WordConcatenatedComponent_WordConcatenatedComponentRowDeleting	(object sender, BabebiDataSet.WordConcatenatedComponentRowChangeEvent e)
		{
		//	if (e.Row.HasVersion(DataRowVersion.Original))
		//	{
				BabebiDataSet.WordConcatenatedComponentRow wordConcatenatedComponent = e.Row;

				/// trap not-related events.
				if 
				(
					this.mainForm.Current__WordConcatenated == null 
					|| 
					wordConcatenatedComponent.RowState == DataRowState.Detached 
					|| 
					wordConcatenatedComponent.WordConcatenatedId != this.mainForm.Current__WordConcatenated.Id
				)
				{
					return;
				}

				DataRow guiDataRow = this.Find(wordConcatenatedComponent.Rank);

				if (guiDataRow != null)
				{
					this.Rows.Remove(guiDataRow);
				}
		//	}
		//	else
		//	{ 
		//		this.Populate();
		//	}
		}

		private void Word__RowChanging(object sender, DataRowChangeEventArgs e)
		{
			if (e.Action == DataRowAction.Change)
			{
				if (this.mainForm.Current__WordConcatenated == null || this.Rows.Count == 0)
				{
					return;
				}

				DataRow dataRow = e.Row;
		
				int current__WordId		= (int)(dataRow[this.mainForm.DataSet.Word.IdColumn, DataRowVersion.Current	]);
				int proposed__wordId	= (int)(dataRow[this.mainForm.DataSet.Word.IdColumn, DataRowVersion.Proposed]);

				if (proposed__wordId != current__WordId)
				{
					foreach (DataRow guiDataRow in this.Rows)
					{ 
						int guiWordId = this.GetValue__WordId(guiDataRow);

						if (guiWordId == current__WordId)
						{
							guiDataRow[this.WordId] = proposed__wordId;

							guiDataRow.AcceptChanges();
						}
					}
				}
			}
		}
		private void Word__RowChanged(object sender, DataRowChangeEventArgs e)
		{
			if (e.Action == DataRowAction.Change)
			{
				if (this.mainForm.Current__WordConcatenated == null || this.Rows.Count == 0)
				{
					return;
				}

				BabebiDataSet.WordRow word = (BabebiDataSet.WordRow)(e.Row);

				int wordId = word.Id;

				foreach (DataRow guiDataRow in this.Rows)
				{
					int guiWordId = this.GetValue__WordId(guiDataRow);

					if (guiWordId == wordId)
					{
						string guiWordUniqueKeyString = this.GetValue__WordString(guiDataRow);

						if (guiWordUniqueKeyString != word.UniqueKeyString)
						{
							guiDataRow[this.WordString] = word.UniqueKeyString;
						}
					}
				}
			}
		}
		private void Word__RowDeleting(object sender, BabebiDataSet.WordRowChangeEvent e)
		{
			if (this.Rows.Count == 0)
			{
				return;
			}

			if (e.Action == DataRowAction.Delete)
			{
				if (this.mainForm.Current__WordConcatenated == null || this.Rows.Count == 0)
				{
					return;
				}

				BabebiDataSet.WordRow word = e.Row;
				
				foreach (DataRow guiDataRow in this.Rows)
				{
					int guiWordId = this.GetValue__WordId(guiDataRow);

					if (guiWordId == word.Id)
					{
						this.Rows.Remove(guiDataRow);
					}
				}
			}
		}

		private void Word__Language__RowChanged(object sender, DataRowChangeEventArgs e)
		{
			if (e.Action == DataRowAction.Change)
			{
				BabebiDataSet.Word_LanguageRow word_language = (BabebiDataSet.Word_LanguageRow)(e.Row);

				if (word_language.LanguageRow != this.currentLanguage)
				{
					return;
				}

				foreach(DataRow guiDataRow in this.Rows)
				{
					int guiWordId = this.GetValue__WordId(guiDataRow);

					if (guiWordId == word_language.WordId)
					{
						string guiWord_LanguageMeaning = this.GetValue__Word_LanguageMeaning(guiDataRow);

						if (guiWord_LanguageMeaning != word_language.Meaning)
						{
							guiDataRow[this.Word_LanguageMeaning] = word_language.Meaning;
						}
					}
				}
			}
		}

		#endregion	listening the DataSet events

		public void Populate()
		{
			this.Clear();

			if (this.currentLanguage == null || this.mainForm.Current__WordConcatenated == null)
			{
				return;
			}

			/// les WordConcatenatedComponent rows ne sont pas forcement insérées dans la table selon 
			/// l'ordre de leurs Ranks...
			
			BabebiDataSet.WordConcatenatedComponentRow[] wordConcatenatedComponents
				= this.mainForm.Current__WordConcatenated.GetWordConcatenatedComponentRows();
			
			SortedDictionary<short, BabebiDataSet.WordConcatenatedComponentRow> keyValuePairs
				= new SortedDictionary<short, BabebiDataSet.WordConcatenatedComponentRow>();

			foreach
			(
				BabebiDataSet.WordConcatenatedComponentRow wordConcatenatedComponent
				in
				wordConcatenatedComponents
			)
			{
				keyValuePairs.Add(wordConcatenatedComponent.Rank, wordConcatenatedComponent);
			}

			foreach
			(
				KeyValuePair<short, BabebiDataSet.WordConcatenatedComponentRow> keyValuePair in keyValuePairs
			)
			{
				BabebiDataSet.WordConcatenatedComponentRow wordConcatenatedComponent = keyValuePair.Value;

				this.addGuiDataRow(wordConcatenatedComponent);
			}
		}

		private void addGuiDataRow(BabebiDataSet.WordConcatenatedComponentRow wordConcatenatedComponent)
		{
			BabebiDataSet.WordRow			word			= wordConcatenatedComponent.WordRow;

			BabebiDataSet.Word_LanguageRow	word_language 	
				= this.table__word_language
				.FindByWordIdLanguageCode
				(
					word.Id,
					this.currentLanguageCode
				);
				
			DataRow guiDataRow = this.NewRow();

			guiDataRow[this.Rank				] = wordConcatenatedComponent.Rank;
			guiDataRow[this.WordId				] = word.Id;
			guiDataRow[this.WordString			] = word.UniqueKeyString;
			guiDataRow[this.Word_LanguageMeaning] = word_language.Meaning;

			if( ! wordConcatenatedComponent.IsSubStringIndexNull())
			{
				guiDataRow[this.SubStringIndex	] = wordConcatenatedComponent.SubStringIndex;
			}

			if( ! wordConcatenatedComponent.IsSubStringLengthNull())
			{
				guiDataRow[this.SubStringLength		] = wordConcatenatedComponent.SubStringLength;
			}

			guiDataRow[this.CURRENT__WordId		] = word.Id;

			this.Rows.Add(guiDataRow);
		}

		private void updateGuiDataRow(BabebiDataSet.WordConcatenatedComponentRow wordConcatenatedComponent)
		{
			BabebiDataSet.WordRow			word			= wordConcatenatedComponent.WordRow;

			BabebiDataSet.Word_LanguageRow	word_language 	
				= this.table__word_language
				.FindByWordIdLanguageCode
				(
					word.Id,
					this.currentLanguageCode
				);
				
			DataRow guiDataRow = this.find(wordConcatenatedComponent.Rank);

			#region		Word

			if(this.GetValue__WordId(guiDataRow) != word.Id)
			{
				guiDataRow[this.WordId				] = word.Id;
				guiDataRow[this.WordString			] = word.UniqueKeyString;
				guiDataRow[this.Word_LanguageMeaning] = word_language.Meaning;
			}

			#endregion	Word
			#region		SubStringIndex

			short? currentGuiSubStringIndex = this.GetValue__SubStringIndex(guiDataRow);

			if(wordConcatenatedComponent.IsSubStringIndexNull())
			{
				if(currentGuiSubStringIndex.HasValue)
				{
					guiDataRow[this.SubStringIndex] = DBNull.Value;
				}
			}
			else
			{
				if( ! currentGuiSubStringIndex.HasValue)
				{
					guiDataRow[this.SubStringIndex] = wordConcatenatedComponent.SubStringIndex;
				}
				else
				{
					if(currentGuiSubStringIndex != wordConcatenatedComponent.SubStringIndex)
					{
						guiDataRow[this.SubStringIndex] = wordConcatenatedComponent.SubStringIndex;
					}
				}
			}

			#endregion	SubStringIndex
			#region		SubStringLength

			short? currentGuiSubStringLength = this.GetValue__SubStringLength(guiDataRow);

			if(wordConcatenatedComponent.IsSubStringLengthNull())
			{
				if(currentGuiSubStringLength.HasValue)
				{
					guiDataRow[this.SubStringLength] = DBNull.Value;
				}
			}
			else
			{
				if( ! currentGuiSubStringLength.HasValue)
				{
					guiDataRow[this.SubStringLength] = wordConcatenatedComponent.SubStringLength;
				}
				else
				{
					if(currentGuiSubStringLength != wordConcatenatedComponent.SubStringLength)
					{
						guiDataRow[this.SubStringLength] = wordConcatenatedComponent.SubStringLength;
					}
				}
			}

			#endregion	SubStringLength
		}

		public	DataRow Find(short rank)
		{
			return this.Rows.Find(rank);
		}

		/// <summary>
		/// Updated-Rank-proofed.
		/// </summary>
		private DataRow find(short rank)
		{ 
			DataRow guiDataRow = this.Find(rank);

			/// on est en train d'updater le Rank => on n'a donc pas trouver la gui row.
			if(guiDataRow == null)
			{
				/// 1) on fait la liste de tous les ranks existants dans le DataSet (de la MainForm).
				List<short> ranks = new List<short>();
				foreach
				(
					BabebiDataSet.WordConcatenatedComponentRow aWordConcatenatedComponentRow 
					in 
					this.mainForm.Current__WordConcatenated.GetWordConcatenatedComponentRows())
				{
					ranks.Add(aWordConcatenatedComponentRow.Rank);
				}

				/// 2) on parcourt tous les ranks affichés dans cette GuiTable :
				///    le premier rank affiché qui n'est pas dans le DS est celui
				///    qui est en cours d'update (puisque les autres matchent 
				///    forcément).
				foreach(DataRow aGuiDataRow in this.Rows)
				{
					short guiRank = this.GetValue__Rank(aGuiDataRow);

					if( ! ranks.Contains(guiRank))
					{
						guiDataRow = aGuiDataRow;
						break;
					}
				}
				if(guiDataRow == null)
				{
					throw new Exception("C'était la dernière cartouche...");
				}

				/// on met à jour la nouvelle valeur du rank pour ne plus avoir ce
				/// problème qui est maintenant résolu.
				guiDataRow[this.Rank] = rank;
			}

			return guiDataRow;
		}
	}
}
