using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Babebi4
{
	public partial class Form__Derivating__CreateUpdate : Form
	{
		private MainForm	mainForm;
		private bool		trueForCreate__falseForUpdate;

		#region		convenient shorcuts

		private BabebiDataSet.DerivatingDataTable					table__Derivating					{ get{return this.mainForm.DataSet.Derivating					;}}
		private BabebiDataSet.Derivating_LanguageDataTable			table__Derivating_Language			{ get{return this.mainForm.DataSet.Derivating_Language			;}}
		private BabebiDataSet.DerivatingWordTypeDataTable			table__DerivatingWordType			{ get{return this.mainForm.DataSet.DerivatingWordType			;}}
		private BabebiDataSet.DerivatingWordType_LanguageDataTable	table__DerivatingWordType_Language	{ get{return this.mainForm.DataSet.DerivatingWordType_Language	;}}
		private BabebiDataSet.DerivatedWordTypeDataTable			table__DerivatedWordType			{ get{return this.mainForm.DataSet.DerivatedWordType			;}}
		private BabebiDataSet.DerivatedWordType_LanguageDataTable	table__DerivatedWordType_Language	{ get{return this.mainForm.DataSet.DerivatedWordType_Language	;}}
		private BabebiDataSet.LetterDataTable						table__Letter						{ get{return this.mainForm.DataSet.Letter						;}}
		private BabebiDataSet.LetterClusterDataTable				table__LetterCluster				{ get{return this.mainForm.DataSet.LetterCluster				;}}
		private BabebiDataSet.LetterClusterLetterDataTable			table__LetterClusterLetter			{ get{return this.mainForm.DataSet.LetterClusterLetter			;}}

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

		private BabebiDataSet.DerivatingRow current__Derivating
		{
			get { return	this.mainForm.Current__Derivating; }
			set {			this.mainForm.Current__Derivating = value;}
		}
		private BabebiDataSet.Derivating_LanguageRow current__Derivating_Language
		{
			get { return	this.mainForm.Current__Derivating_Language; }
			set {			this.mainForm.Current__Derivating_Language = value;}
		}

		#endregion	convenient shorcuts
		#region		variables

		private bool dontTriggerEvent = false;

		private short derivatingId = -1;

		private BabebiDataSet.DerivatingWordType_LanguageRow	selected__DerivatingWordType_Language = null;
		private BabebiDataSet.DerivatedWordType_LanguageRow		selected__DerivatedWordType_Language = null;
		private BabebiDataSet.LetterClusterRow					selected__LetterCluster	= null;

		List<BabebiDataSet.LetterRow> letterList = new List<BabebiDataSet.LetterRow>();

		#endregion	variables
		#region		error management

		private bool hasError__DerivatingId_ = false;
		private bool hasError__DerivatingId
		{
			get { return this.hasError__DerivatingId_; }
			set
			{
				this.hasError__DerivatingId_ = value;

				if (this.hasError__DerivatingId_)
				{
					this.label__DerivatingId.ForeColor = Color.Red;
					this.textBox__DerivatingId.BackColor = Color.White;
					this.textBox__DerivatingId.ForeColor = Color.Red;
				}
				else
				{
					this.label__DerivatingId.ForeColor = Color.Black;
					this.textBox__DerivatingId.BackColor = Color.White;
					this.textBox__DerivatingId.ForeColor = Color.Black;
				}
			}
		}

		private bool hasError__DerivatingLetterClusterString_ = false;
		private bool hasError__DerivatingLetterClusterString
		{
			get { return this.hasError__DerivatingLetterClusterString_; }
			set
			{
				this.hasError__DerivatingLetterClusterString_ = value;

				if (this.hasError__DerivatingLetterClusterString_)
				{
					this.label__DerivatingLetterClusterString.ForeColor = Color.Red;
					this.textBox__DerivatingLetterClusterString.BackColor = Color.White;
					this.textBox__DerivatingLetterClusterString.ForeColor = Color.Red;
				}
				else
				{
					this.label__DerivatingLetterClusterString.ForeColor = Color.Black;
					this.textBox__DerivatingLetterClusterString.BackColor = Color.White;
					this.textBox__DerivatingLetterClusterString.ForeColor = Color.Black;
				}
			}
		}

		#endregion	error management
		#region		ctors

		public Form__Derivating__CreateUpdate(MainForm mainForm, bool trueForCreate__falseForUpdate) : this()
		{
			this.mainForm						= mainForm;
			this.trueForCreate__falseForUpdate	= trueForCreate__falseForUpdate;

			if (trueForCreate__falseForUpdate)
			{
				this.button__Create.Text = "CREATE";
				this.Text = "Create a new Derivating :";

				this.dontTriggerEvent = true;
				#region		Derivating Id

				foreach (BabebiDataSet.DerivatingRow derivating in this.table__Derivating)
				{
					if (derivating.Id > this.derivatingId)
					{
						this.derivatingId = derivating.Id;
					}
				}
				this.derivatingId++;
				this.textBox__DerivatingId.Text = this.derivatingId.ToString();

				#endregion	Derivating Id
				#region		DerivatingWordTypeName

				if (this.mainForm.Current__Language != null && this.mainForm.Current__DerivatingWordType_DerivatedWordType != null)
				{
					this.selected__DerivatingWordType_Language
						= this.mainForm.DataSet
						.DerivatingWordType_Language
						.FindByDerivatingWordTypeIdLanguageCode
						(
							this.mainForm.Current__DerivatingWordType_DerivatedWordType.DerivatingWordTypeId,
							this.mainForm.Current__Language.Code
						);
				}
				else
				{
					this.selected__DerivatingWordType_Language = null;
				}

				List<DerivatingWordTypeComboBoxItem> derivatingWordTypeComboBoxItems
					= DerivatingWordTypeComboBoxItem.BuildDerivatingWordTypeComboBoxItems
					(
						this.mainForm.Current__Language,
						this.selected__DerivatingWordType_Language,
					out DerivatingWordTypeComboBoxItem selectedDerivatingWordTypeComboBoxItem
					);
				this.comboBox__DerivatingWordType_LanguageName.Items.AddRange(derivatingWordTypeComboBoxItems.ToArray());
				if (selectedDerivatingWordTypeComboBoxItem != null)
				{
					this.comboBox__DerivatingWordType_LanguageName.SelectedItem = selectedDerivatingWordTypeComboBoxItem;
				}

				#endregion	DerivatingWordTypeName
				#region		DerivatedWordTypeName

				/// on tente de pré-remplir en fonction du contexte =>
				/// (this.mainForm.Current__DerivatingWordType_DerivatedWordType sachant qu'une langue est toujours choisie)
				if (selectedDerivatingWordTypeComboBoxItem != null)
				{
					if (this.mainForm.Current__Language != null && this.mainForm.Current__DerivatingWordType_DerivatedWordType != null)
					{
						this.selected__DerivatedWordType_Language
							= this.mainForm.DataSet
							.DerivatedWordType_Language
							.FindByDerivatedWordTypeIdLanguageCode
							(
								this.mainForm.Current__DerivatingWordType_DerivatedWordType.DerivatedWordTypeId,
								this.mainForm.Current__Language.Code
							);
					}
				}

				List<DerivatedWordTypeComboBoxItem> derivatedWordTypeComboBoxItems 
					= DerivatedWordTypeComboBoxItem.BuildDerivatedWordTypeComboBoxItems
						(
							this.selected__DerivatingWordType_Language,
						ref this.selected__DerivatedWordType_Language,
						out	DerivatedWordTypeComboBoxItem selectedDerivatedWordTypeComboBoxItem
						);

				this.comboBox__DerivatedWordType_LanguageName.Items.AddRange(derivatedWordTypeComboBoxItems.ToArray());
				if (selectedDerivatedWordTypeComboBoxItem != null)
				{
					this.comboBox__DerivatedWordType_LanguageName.SelectedItem = selectedDerivatedWordTypeComboBoxItem;
				}

				#endregion	DerivatedWordTypeName
				this.dontTriggerEvent = false;
			}
			else if (!trueForCreate__falseForUpdate)
			{
				this.button__Create.Text = "UPDATE";
				this.Text = "Update an existing Derivating :";

				this.dontTriggerEvent = true;
				#region		Derivating Id

				this.textBox__DerivatingId.Text = this.current__Derivating.Id.ToString();

				#endregion	Derivating Id
				#region		DerivatingWordTypeName

				this.selected__DerivatingWordType_Language 
					= this.mainForm.Current__Derivating_Language
					.DerivatingWordType_LanguageRowParent;

				List<DerivatingWordTypeComboBoxItem> derivatingWordTypeComboBoxItems 
					= DerivatingWordTypeComboBoxItem.BuildDerivatingWordTypeComboBoxItems
					(
						this.mainForm.Current__Language,
						this.selected__DerivatingWordType_Language, 
					out DerivatingWordTypeComboBoxItem selectedDerivatingWordTypeComboBoxItem
					);
				this.comboBox__DerivatingWordType_LanguageName.Items.AddRange(derivatingWordTypeComboBoxItems.ToArray());
				this.comboBox__DerivatingWordType_LanguageName.SelectedItem = selectedDerivatingWordTypeComboBoxItem;

				#endregion	DerivatingWordTypeName
				#region		DerivatedWordTypeName

				this.selected__DerivatedWordType_Language 
					= this.mainForm.Current__Derivating_Language
					.DerivatedWordType_LanguageRowParent;

				List<DerivatedWordTypeComboBoxItem> derivatedWordTypeComboBoxItems 
					= DerivatedWordTypeComboBoxItem.BuildDerivatedWordTypeComboBoxItems
						(
							this.selected__DerivatingWordType_Language,
						ref this.selected__DerivatedWordType_Language,
						out	DerivatedWordTypeComboBoxItem selectedDerivatedWordTypeComboBoxItem
						);
				if (selectedDerivatedWordTypeComboBoxItem == null)
				{
					throw new Exception();
				}

				this.comboBox__DerivatedWordType_LanguageName.Items.AddRange(derivatedWordTypeComboBoxItems.ToArray());
				this.comboBox__DerivatedWordType_LanguageName.SelectedItem = selectedDerivatedWordTypeComboBoxItem;

				#endregion	DerivatedWordTypeName
				this.dontTriggerEvent = false;
			}

			if (this.current__Derivating != null && this.current__Derivating_Language != null)
			{
				/// Create (cloning...) + Update
		
				#region		DerivatingName	(Babebi's language one)

				this.textBox__DerivatingName.Text = this.current__Derivating.Name;

				#endregion	DerivatingName	(Babebi's language one)
				#region		Name (the one in all the languages)

				this.textBox__Name.Text = this.current__Derivating_Language.Name;

				#endregion	Name (the one in all the languages)
				#region		DerivatingLetterClusterString	(on veut l'event ici pour fabriquer les ranks__letters)

				this.textBox__DerivatingLetterClusterString.Text = this.current__Derivating_Language.DerivatingRowParent.LetterClusterString;

				#endregion	DerivatingLetterClusterString   (on veut l'event ici pour fabriquer les ranks__letters)
				#region		AppendStringAtLast

				this.checkBox__AppendStringAtLast.Checked = this.current__Derivating.AppendStringAtLast;

				#endregion	AppendStringAtLast				
			}
			else
			{
				/// Create (without value)
				
				this.checkBox__AppendStringAtLast.Checked = true;	/// default value.
			}
		}

		public Form__Derivating__CreateUpdate()
		{
			InitializeComponent();
		}

		#endregion	ctors
		#region		control events

		private void textBox__DerivatingId_KeyPress(object sender, KeyPressEventArgs e)
		{
			if (this.dontTriggerEvent)
			{
				return;
			}

			char c = e.KeyChar;

			/// les chiffres + back + coller.
			if (char.IsNumber(c) || c == '\b' || c == '\u0016')	
			{
				e.Handled = false;
			}
			else
			{ 
				e.Handled = true;
			}
		}
		private void textBox__DerivatingId_Leave(object sender, EventArgs e)
		{
			if (this.dontTriggerEvent)
			{
				return;
			}

			string derivatingIdString = this.textBox__DerivatingId.Text;

			if (string.IsNullOrEmpty(derivatingIdString))
			{
				this.hasError__DerivatingId = true;

				MessageBox.Show
				(
					"The value of the 'Derivating Id' cannot be let undefined.", 
					"Derivating Id required", 
					MessageBoxButtons.OK, 
					MessageBoxIcon.Error
				);

				return;
			}

			this.derivatingId = short.Parse(derivatingIdString);    /// validé par le KeyPress comme un nombre => go : pas de TryParse(...).

			if (this.current__Derivating == null || this.derivatingId != this.current__Derivating.Id)
			{
				BabebiDataSet.DerivatingRow alreadyExistingDerivating
					= this.table__Derivating.FindById(derivatingId);

				if (alreadyExistingDerivating != null)
				{
					BabebiDataSet.Derivating_LanguageRow alreadyExistingDerivating_Language
						= this.table__Derivating_Language
						.FindByDerivatingIdLanguageCode
						(
							derivatingId,
							this.currentLanguageCode
						);

					string derivatingWordTypeName = alreadyExistingDerivating_Language.DerivatingWordType_LanguageName;
					this.hasError__DerivatingId = true;

					MessageBox.Show
					(
						"This value of the 'Derivating Id' is already associated to the existing Derivating defined by:\n\n'" +
						"   - Derivating Word Type Name = '" + alreadyExistingDerivating_Language.DerivatingWordType_LanguageName + "',\n" +
						"   - Derivated Word Type Name = '" + alreadyExistingDerivating_Language.DerivatedWordType_LanguageName + "',\n" +
						"   - Name = '" + alreadyExistingDerivating_Language.Name + "'.",
						"Derivating Id already exising",
						MessageBoxButtons.OK,
						MessageBoxIcon.Error
					);

					return;
				}
				else
				{
					this.hasError__DerivatingId = false;
				}
			}
			else
			{ 
				this.hasError__DerivatingId = false;
			}
		}

		private void comboBox__DerivatingWordType_LanguageName_SelectedIndexChanged(object sender, EventArgs e)
		{
			if (this.dontTriggerEvent)
			{
				return;
			}

			DerivatingWordTypeComboBoxItem selectedDerivatingWordTypeComboBoxItem 
				= (DerivatingWordTypeComboBoxItem)(this.comboBox__DerivatingWordType_LanguageName.SelectedItem);

			this.selected__DerivatingWordType_Language
				= selectedDerivatingWordTypeComboBoxItem
				.Row;

			List<DerivatedWordTypeComboBoxItem> derivatedWordTypeComboBoxItems 
				= DerivatedWordTypeComboBoxItem.BuildDerivatedWordTypeComboBoxItems
					(
						this.selected__DerivatingWordType_Language,
					ref this.selected__DerivatedWordType_Language,
					out	DerivatedWordTypeComboBoxItem selectedDerivatedWordTypeComboBoxItem
					);

			this.comboBox__DerivatedWordType_LanguageName.Items.Clear();

			if (derivatedWordTypeComboBoxItems.Count != 1)
			{
				this.comboBox__DerivatedWordType_LanguageName.Items.AddRange(derivatedWordTypeComboBoxItems.ToArray());

				this.comboBox__DerivatedWordType_LanguageName.Text = null;
			}
			else
			{
				DerivatedWordTypeComboBoxItem derivatedWordTypeComboBoxItem = derivatedWordTypeComboBoxItems[0];

				this.comboBox__DerivatedWordType_LanguageName.Items.Add(derivatedWordTypeComboBoxItem);

				this.comboBox__DerivatedWordType_LanguageName.SelectedItem = derivatedWordTypeComboBoxItem;


			}
		}
		private void comboBox__DerivatedWordType_LanguageName_SelectedIndexChanged(object sender, EventArgs e)
		{
			DerivatedWordTypeComboBoxItem selectedDerivatedWordTypeComboBoxItem 
				= (DerivatedWordTypeComboBoxItem)(this.comboBox__DerivatedWordType_LanguageName.SelectedItem);

			this.selected__DerivatedWordType_Language
				= selectedDerivatedWordTypeComboBoxItem
				.Row;
		}

		private void textBox__DerivatingLetterClusterString_TextChanged(object sender, EventArgs e)
		{
			if (dontTriggerEvent)
			{
				return;
			}

			string letterClusterString = this.textBox__DerivatingLetterClusterString.Text;

			this.letterList.Clear();

			DataRow[] letterClusterdataRows = this.table__LetterCluster.Select("String = '" + letterClusterString + "'");

			if (letterClusterdataRows.Length == 0)
			{
				/// doesnot exit yet => is the input string valid or not?

				#region		check if the LetterCluster string only contains valid Letters

				string invalidCharString 
					= this.mainForm.Split_a_string_into_Letters(letterClusterString, this.letterList);

				if (invalidCharString != null)
				{ 
					this.hasError__DerivatingLetterClusterString = true;

					MessageBox.Show
					(
						"The 'Letter Cluster' string contains the invalid character: '" +
						invalidCharString +
						"'.",
						"Invalid character",
						MessageBoxButtons.OK,
						MessageBoxIcon.Error
					);

					return;
				}

				this.selected__LetterCluster = null;    /// will be created while click the UPDATE button, which is a proof that this value is not so important...

				this.hasError__DerivatingLetterClusterString = false;

				#endregion	check if the LetterCluster string only contains valid Letters
			}
			else if (letterClusterdataRows.Length == 1)
			{
				this.selected__LetterCluster = (BabebiDataSet.LetterClusterRow)(letterClusterdataRows[0]);
			}
			else
			{
				throw new Exception();
			}
		}

		#endregion	control events

		private void button__Create__Click(object sender, EventArgs e)
		{
			#region		checking

			if (this.hasError__DerivatingId)
			{ 
				MessageBox.Show("There is an error about the 'Id'.","Error on Id", MessageBoxButtons.OK, MessageBoxIcon.Error);
				return;
			}

			if (this.selected__DerivatingWordType_Language == null)
			{ 
				MessageBox.Show("The 'Derivating Word Type' is not defined.","Error on Derivating Word Type", MessageBoxButtons.OK, MessageBoxIcon.Error);
				return;
			}

			if (this.selected__DerivatedWordType_Language == null)
			{ 
				MessageBox.Show("The 'Derivated Word Type' is not defined.","Error on Derivated Word Type", MessageBoxButtons.OK, MessageBoxIcon.Error);
				return;
			}

			if (this.hasError__DerivatingLetterClusterString)
			{ 
				MessageBox.Show("There is an error about the 'Letter Cluster String'.","Error on Letter Cluster String", MessageBoxButtons.OK, MessageBoxIcon.Error);
				return;
			}
			string derivatingLetterClusterString	= this.textBox__DerivatingLetterClusterString.Text;

			string name								= this.textBox__Name.Text;
			if ( ! MainForm.UserEntryChecking(this.table__Derivating_Language	.NameColumn					, name						)) { return; }

			string derivatingName					= this.textBox__DerivatingName.Text;
			if (string.IsNullOrEmpty(derivatingName) || derivatingName.StartsWith("**") || derivatingName.StartsWith("...") )
			{
				derivatingName = "**" + this.currentLanguageCode + "**" + name;	/// parce qu'on ne connait bien sûr pas encore le vocabulaire grammaticale en Babebi.
			}
			else
			{
				if (!MainForm.UserEntryChecking(this.table__Derivating.NameColumn, derivatingName)) { return; }
			}

			#endregion	checking

			short derivatingWordTypeId			= this.selected__DerivatingWordType_Language.DerivatingWordTypeId;
			short derivatedWordTypeId			= this.selected__DerivatedWordType_Language.DerivatedWordTypeId;
			short derivatedWordTypeWordTypeId	= this.selected__DerivatedWordType_Language.WordTypeId;

			if (this.selected__LetterCluster == null)
			{ 
				this.selected__LetterCluster = this.mainForm.build__LetterCluster(this.letterList);
			}

			if (this.trueForCreate__falseForUpdate)
			{
				BabebiDataSet.DerivatingRow derivating
					= this.table__Derivating.AddDerivatingRow
					(
						this.derivatingId,
						derivatingWordTypeId,
						derivatedWordTypeId,
						derivatingName,
						this.selected__LetterCluster,
						this.checkBox__AppendStringAtLast.Checked
					);

				#region		build DerivatingWordType_Language dataRows

				foreach (BabebiDataSet.LanguageRow language in this.mainForm.DataSet.Language)
				{
					this.table__Derivating_Language
						.AddDerivating_LanguageRow
						(
							derivating.Id,
							language,
							(language == this.mainForm.Current__Language ? name : "**" + name + "**"),
							derivatingWordTypeId,
							derivatedWordTypeId
						);
				}

				#endregion	build DerivatingWordType_Language dataRows
			}
			else if (! this.trueForCreate__falseForUpdate)
			{
				bool hasChanged = false;
				if
				(
					this.selected__LetterCluster.Id				!= this.current__Derivating.LetterClusterId
					||
					this.checkBox__AppendStringAtLast.Checked	!= this.current__Derivating.AppendStringAtLast
				)
				{
					hasChanged = true;
				}

				/// on est obligé de mirorer ces 2 rows car la modification du DerivatedWordTypeId déclenche
				/// l'event CurrentChanged du binding (à cause du filtering) et du coup, on finirait en updatant 
				/// une autre row (celle qui obtient le focus lorsque cette row part ailleurs par filtrage).
				BabebiDataSet.DerivatingRow				updatedDerivating			= this.mainForm.Current__Derivating;
				BabebiDataSet.Derivating_LanguageRow	updatedDerivating_Language	= this.mainForm.Current__Derivating_Language;

				updatedDerivating.Id					= this.derivatingId;
				updatedDerivating.DerivatingWordTypeId	= derivatingWordTypeId;
				updatedDerivating.DerivatedWordTypeId	= derivatedWordTypeId;
				updatedDerivating.Name					= derivatingName;
				updatedDerivating.LetterClusterId		= this.selected__LetterCluster.Id;
				updatedDerivating.AppendStringAtLast	= this.checkBox__AppendStringAtLast.Checked;

				updatedDerivating_Language.Name			= name;

				#region		build Derivating_Language dataRows

				foreach 
				(
					BabebiDataSet.Derivating_LanguageRow derivating_language 
					in 
					updatedDerivating.GetDerivating_LanguageRows()
				)
				{
					if (derivating_language.LanguageCode == this.currentLanguageCode)
					{
						continue;	/// puisque cette update a déjà été faite au-dessus sur 'updatedDerivating_Language'.
					}

					MainForm.PropagateNaming
					(
						name, 
						this.table__Derivating_Language.NameColumn, 
						derivating_language, 
						updatedDerivating_Language
					);
				}

				#endregion	build Derivating_Language dataRows			

				if (hasChanged)
				{
					WordDerivated.DerivatingChanging(updatedDerivating);
				}
			}

			this.Close();
		}
	}
}
