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

namespace Babebi4
{
	internal abstract class TreeViewNodeTag
	{
		protected MainForm						mainForm;

		internal BabebiDataSet.WordOrPatternRow WordOrPattern { get; }

		protected TreeViewNodeTag(MainForm mainForm, BabebiDataSet.WordOrPatternRow wordOrPattern)
		{
			this.mainForm = mainForm;

			this.WordOrPattern = wordOrPattern;
		}

		internal virtual TreeViewNodeTag[] GetChildren()
		{
			return null;	/// n'est pas appelé de tout façon.
		}

		internal abstract string GetLabel();
	}

	internal class TreeViewNodeTag__Folder : TreeViewNodeTag
	{
		internal string								SubscriberCode		{get;}
		internal string								ModeCode			{get;}
		internal TreeViewNodeTag__WordOrPattern[]	TreeViewNodeTags	{get; private set; }

		internal TreeViewNodeTag__Folder
		(
			MainForm							mainForm, 
			BabebiDataSet.WordOrPatternRow		wordOrPattern,
			string								subscriberCode,
			string								modeCode,
			TreeViewNodeTag__WordOrPattern[]	treeViewNodeTags			
		) 
		: base(mainForm, wordOrPattern)
		{
			this.SubscriberCode		= subscriberCode;
			this.ModeCode			= modeCode;
			this.TreeViewNodeTags	= treeViewNodeTags;
		}

		internal void RefreshChildren()
		{
			if (this.WordOrPattern.SubscriberCode == MainForm.SubscriberCode_Word)
			{
				BabebiDataSet.WordRow word = this.mainForm.DataSet.Word.FindById(this.WordOrPattern.SubscriberId);

				if (this.SubscriberCode == MainForm.SubscriberCode_Word)
				{ 
					if (this.ModeCode == MainForm.ModeCode_Derivated)
					{ 
						BabebiDataSet.WordDerivatingRow wordDerivating = this.mainForm.DataSet.WordDerivating.FindByWordId(word.Id);

						if (wordDerivating == null)
						{
							this.TreeViewNodeTags = new TreeViewNodeTag__WordOrPattern[] { };
						}
						else
						{
							List<TreeViewNodeTag__WordOrPattern> list = new List<TreeViewNodeTag__WordOrPattern>();
							foreach (BabebiDataSet.WordDerivatedRow wordDerivated in wordDerivating.GetWordDerivatedRows())
							{
								list.Add(new TreeViewNodeTag__WordDerivated(this.mainForm, wordDerivated));
							}
							this.TreeViewNodeTags = list.ToArray();
						}
					}
					else if (this.ModeCode == MainForm.ModeCode_ByInsertion)
					{ 
						List<TreeViewNodeTag__WordOrPattern> list = new List<TreeViewNodeTag__WordOrPattern>();
						foreach (BabebiDataSet.WordByInsertionRow wordByInsertion in word.GetWordByInsertionRowsByWordByInsertion__Word__Origin())
						{
							list.Add(new TreeViewNodeTag__WordByInsertion(this.mainForm, wordByInsertion));
						}
						this.TreeViewNodeTags = list.ToArray();
					}
					else
					{ 
						return;
					}
				}
				else if (this.SubscriberCode == MainForm.SubscriberCode_Pattern)
				{ 
					if (this.ModeCode == MainForm.ModeCode_ByInsertion)
					{ 
						List<TreeViewNodeTag__WordOrPattern> list = new List<TreeViewNodeTag__WordOrPattern>();
						foreach (BabebiDataSet.PatternByInsertionRow patternByInsertion in word.WordOrPatternRowParent.GetPatternByInsertionRows())
						{
							list.Add(new TreeViewNodeTag__PatternByInsertion(this.mainForm, patternByInsertion));
						}
						this.TreeViewNodeTags = list.ToArray();
					}
					else
					{ 
						return;
					}
				}
				else
				{ 
					throw new NotImplementedException(this.SubscriberCode);
				}
			}
			else if (this.WordOrPattern.SubscriberCode == MainForm.SubscriberCode_Pattern)
			{ 
				BabebiDataSet.PatternRow pattern = this.mainForm.DataSet.Pattern.FindById(this.WordOrPattern.SubscriberId);

				if (this.SubscriberCode == MainForm.SubscriberCode_Word)
				{ 
					if (this.ModeCode == MainForm.ModeCode_FromPattern)
					{ 
						List<TreeViewNodeTag__WordOrPattern> list = new List<TreeViewNodeTag__WordOrPattern>();
						foreach (BabebiDataSet.FromPatternRow fromPattern in pattern.GetFromPatternRows())
						{
							if (fromPattern.SubscriberCode == MainForm.SubscriberCode_Pattern)
							{
								continue;
							}

							BabebiDataSet.WordFromPatternRow wordFromPattern = this.mainForm.DataSet.WordFromPattern.FindById(fromPattern.SubscriberId);

							list.Add(new TreeViewNodeTag__WordFromPattern(this.mainForm, wordFromPattern));
						}
						this.TreeViewNodeTags = list.ToArray();
					}
					else
					{ 
						return;
					}
				}
				else if (this.SubscriberCode == MainForm.SubscriberCode_Pattern)
				{ 
					if (this.ModeCode == MainForm.ModeCode_FromPattern)
					{ 
						List<TreeViewNodeTag__WordOrPattern> list = new List<TreeViewNodeTag__WordOrPattern>();
						foreach (BabebiDataSet.FromPatternRow fromPattern in pattern.GetFromPatternRows())
						{
							if (fromPattern.SubscriberCode == MainForm.SubscriberCode_Word)
							{
								continue;
							}

							BabebiDataSet.PatternFromPatternRow patternFromPattern = this.mainForm.DataSet.PatternFromPattern.FindById(fromPattern.SubscriberId);

							list.Add(new TreeViewNodeTag__PatternFromPattern(this.mainForm, patternFromPattern));
						}
						this.TreeViewNodeTags = list.ToArray();
					}
					else if (this.ModeCode == MainForm.ModeCode_ByInsertion)
					{ 
						List<TreeViewNodeTag__WordOrPattern> list = new List<TreeViewNodeTag__WordOrPattern>();
						foreach (BabebiDataSet.PatternByInsertionRow patternByInsertion in pattern.GetPatternByInsertionRows())
						{
							list.Add(new TreeViewNodeTag__PatternByInsertion(this.mainForm, patternByInsertion));
						}
						this.TreeViewNodeTags = list.ToArray();
					}
					else
					{ 
						return;
					}
				}
				else
				{ 
					throw new NotImplementedException(this.SubscriberCode);
				}
			}
			else
			{ 
					throw new NotImplementedException(this.WordOrPattern.SubscriberCode);
			}
		}

		internal override TreeViewNodeTag[] GetChildren()
		{ 
			return this.TreeViewNodeTags;
		}

		internal override string GetLabel()
		{
			switch (this.SubscriberCode)
			{
				case MainForm.SubscriberCode_Word:
				{
					switch (this.ModeCode)
					{
						case MainForm.ModeCode_FromPattern	:
						{
							return "'Words (From Pattern)'";
						}
						case MainForm.ModeCode_ByInsertion :
						{
							return "'Words (By insertion)'";
						}
						case MainForm.ModeCode_Derivated :
						{
							return "'Words (Derivated)'";
						}
						case MainForm.ModeCode_Concatenated :
						{
							return "'Words (Concatenated)'";
						}
						default: throw new Exception(this.ModeCode);
					}
				}
				case MainForm.SubscriberCode_Pattern:
				{
					switch (this.ModeCode)
					{
						case MainForm.ModeCode_FromPattern	:
						{
							return "'Patterns (From Pattern)'";
						}
						case MainForm.ModeCode_ByInsertion :
						{
							return "'Patterns (By insertion)'";
						}
						default: throw new Exception(this.ModeCode);
					}
				}
				default: throw new Exception(this.SubscriberCode);
			}
		}
	}

	internal abstract class TreeViewNodeTag__WordOrPattern : TreeViewNodeTag
	{
		protected BabebiDataSet dataSet
		{
			get
			{
				return this.mainForm.DataSet;
			}
		}

		protected TreeViewNodeTag__WordOrPattern(MainForm mainForm, BabebiDataSet.WordOrPatternRow wordOrPattern) : base(mainForm, wordOrPattern)
		{
		}

		internal override TreeViewNodeTag[] GetChildren()
		{
			List<TreeViewNodeTag> treeViewNodeTagList = new List<TreeViewNodeTag>();

			foreach (BabebiDataSet.PatternByInsertionRow patternByInsertion in this.WordOrPattern.GetPatternByInsertionRows())
			{
				TreeViewNodeTag__PatternByInsertion treeViewNodeTag__PatternByInsertion
					= new TreeViewNodeTag__PatternByInsertion(this.mainForm, patternByInsertion);

				treeViewNodeTagList.Add(treeViewNodeTag__PatternByInsertion);		
			}

			return treeViewNodeTagList.ToArray();
		}

		protected void append
		(
			MainForm mainForm, 
			BabebiDataSet.WordOrPatternRow wordOrPattern,
		ref	string priorSubscriberCode, 
		ref	string priorModeCode,
		ref	List<TreeViewNodeTag> priorList, 
			string newSubscriberCode, 
			string newModeCode,
			List<TreeViewNodeTag__WordOrPattern> newList
		)
		{
			if (newList.Count == 0)
			{
				return;		/// aucun nouveau node => on ne touche à rien.
			}
			else
			{
				if (priorList.Count == 0)
				{
					/// on rajoute les nodes en vrac à la liste car 
					/// ils seront peut-être la seule espèce.

					priorList.AddRange(newList);

					/// pour que cela marche l'itération d'après lorsque 
					/// ces nodes devront être packagées dans un folder.
					priorSubscriberCode	= newSubscriberCode	; 
					priorModeCode		= newModeCode		;
				}
				else
				{
					
					if (priorList.Last() is TreeViewNodeTag__WordOrPattern)
					{
						/// les nodes d'avant étaient en vrac : on les reconditionne 
						/// dans un folder que l'on rajoute à la liste vidée.
						
						TreeViewNodeTag__WordOrPattern[] treeViewNodeTag__WordOrPatterns 
							= new TreeViewNodeTag__WordOrPattern[priorList.Count];

						for (int i = 0; i < priorList.Count; i++)
						{
							treeViewNodeTag__WordOrPatterns[i] = (TreeViewNodeTag__WordOrPattern)(priorList[i]);
						}

						TreeViewNodeTag__Folder treeViewNodeTag__Folder__PRIOR
							= new TreeViewNodeTag__Folder
							(
								mainForm, 
								wordOrPattern,
								priorSubscriberCode,
								priorModeCode,
								treeViewNodeTag__WordOrPatterns
							);

						priorList.Clear();

						priorList.Add(treeViewNodeTag__Folder__PRIOR);
					}

					TreeViewNodeTag__Folder treeViewNodeTag__Folder__NEW
						= new TreeViewNodeTag__Folder
						(
							mainForm, 
							wordOrPattern,
							newSubscriberCode,
							newModeCode,
							newList.ToArray()
						);

					priorList.Add(treeViewNodeTag__Folder__NEW);
				}
			}
		}

		internal string GetUniqueKeyString	()	{ return this.getUniqueKeyString(); }
		internal string GetMeaning			()	{ return this.getMeaning(); }

		protected abstract string getUniqueKeyString();
		protected abstract string getMeaning();

		internal override string GetLabel()
		{
			return "[ " + this.getUniqueKeyString() + " ] : '" + this.getMeaning() + "'";
		}

		internal abstract string GetBuildingString();
	}

	internal abstract class TreeViewNodeTag__Word : TreeViewNodeTag__WordOrPattern
	{
		internal	BabebiDataSet.WordRow Word { get; private set; }

		private		BabebiDataSet.Word_LanguageRow word_Language;

		public TreeViewNodeTag__Word(MainForm mainForm, BabebiDataSet.WordRow word) 
		: base(mainForm, word.WordOrPatternRowParent)
		{
			this.Word = word;

			this.word_Language 
				= this.dataSet.Word_Language.FindByWordIdLanguageCode
				(
					this.Word.Id, 
					this.mainForm.Current__Language.Code
				);
		}

		internal override TreeViewNodeTag[] GetChildren()
		{
			TreeViewNodeTag[] base__TreeViewNodeTags = base.GetChildren();

			#region		(base) 'Patterns (By insertion)'

			string priorSubscriberCode	= MainForm.SubscriberCode_Pattern;
			string priorModeCode		= MainForm.ModeCode_ByInsertion;
			List<TreeViewNodeTag> priorList = new List<TreeViewNodeTag>(base__TreeViewNodeTags);

			#endregion	(base) 'Patterns (By insertion)'
			#region		'Words (Derivated)' children

			if (this.Word.HasDerivating)
			{
				BabebiDataSet.WordDerivatingRow wordDerivating 
					= this.dataSet.WordDerivating
					.FindByWordId(this.Word.Id);

				List<TreeViewNodeTag__WordOrPattern> newList__WordDerivatived 
					= new List<TreeViewNodeTag__WordOrPattern>();

				foreach (BabebiDataSet.WordDerivatedRow wordDerivated in wordDerivating.GetWordDerivatedRows())
				{
					TreeViewNodeTag__WordDerivated treeViewNodeTag__WordDerivated
						= new TreeViewNodeTag__WordDerivated(this.mainForm, wordDerivated);

					newList__WordDerivatived.Add(treeViewNodeTag__WordDerivated);
				}

				this.append
				(
					this.mainForm,
					this.WordOrPattern,
				ref	priorSubscriberCode, 
				ref	priorModeCode,
				ref	priorList, 
					MainForm.SubscriberCode_Word, 
					MainForm.ModeCode_Derivated,
					newList__WordDerivatived
				);
			}

			#endregion	'Words (Derivated)' children
			#region		'Words (By insertion)' children

			List<TreeViewNodeTag__WordOrPattern> newList__WordByInsertion = new List<TreeViewNodeTag__WordOrPattern>();

			foreach 
			(
				BabebiDataSet.WordByInsertionRow wordByInsertion 
				in 
				this.Word.GetWordByInsertionRowsByWordByInsertion__Word__Origin()
			)
			{
				TreeViewNodeTag__WordByInsertion treeViewNodeTag__WordByInsertion
					= new TreeViewNodeTag__WordByInsertion(this.mainForm, wordByInsertion);

				newList__WordByInsertion.Add(treeViewNodeTag__WordByInsertion);
			}

			this.append
			(
				this.mainForm,
				this.WordOrPattern,
			ref	priorSubscriberCode, 
			ref	priorModeCode,
			ref	priorList, 
				MainForm.SubscriberCode_Word, 
				MainForm.ModeCode_ByInsertion,
				newList__WordByInsertion
			);

			#endregion	'Words (By insertion)' children
			#region		'Words (Concatenated)' children

			List<TreeViewNodeTag__WordOrPattern> newList__WordConcatenated = new List<TreeViewNodeTag__WordOrPattern>();

			foreach 
			(
				BabebiDataSet.WordConcatenatedComponentRow wordConcatenatedComponent
				in 
				this.Word.GetWordConcatenatedComponentRows()
			)
			{
				TreeViewNodeTag__WordConcatenated treeViewNodeTag__WordConcatenated
					= new TreeViewNodeTag__WordConcatenated(this.mainForm, wordConcatenatedComponent.WordConcatenatedRow, this.Word);

				newList__WordConcatenated.Add(treeViewNodeTag__WordConcatenated);
			}

			this.append
			(
				this.mainForm,
				this.WordOrPattern,
			ref	priorSubscriberCode, 
			ref	priorModeCode,
			ref	priorList, 
				MainForm.SubscriberCode_Word, 
				MainForm.ModeCode_Concatenated,
				newList__WordConcatenated
			);

			#endregion	'Words (Concatenated)' children

			return priorList.ToArray();
		}

		protected override string getUniqueKeyString()	{ return this.Word.UniqueKeyString; }
		protected override string getMeaning()			{ return this.word_Language.Meaning; }
	}
	internal class TreeViewNodeTag__WordFromPattern : TreeViewNodeTag__Word
	{
		internal BabebiDataSet.WordFromPatternRow WordFromPattern { get; private set; }

		public TreeViewNodeTag__WordFromPattern(MainForm mainForm, BabebiDataSet.WordFromPatternRow wordFromPattern) 
		: base(mainForm, wordFromPattern.WordRowParent)
		{
			this.WordFromPattern = wordFromPattern;
		}

		internal override string GetBuildingString()
		{ 
			return MainForm.Compute__LetterDictionaryString__for_Word(this.WordFromPattern.FromPatternRowParent);
		}
	}
	internal class TreeViewNodeTag__WordByInsertion : TreeViewNodeTag__Word
	{
		internal BabebiDataSet.WordByInsertionRow WordByInsertion { get; private set; }

		public TreeViewNodeTag__WordByInsertion(MainForm mainForm, BabebiDataSet.WordByInsertionRow wordByInsertion) 
		: base(mainForm, wordByInsertion.WordRowParentByWordByInsertion__Word)
		{
			this.WordByInsertion = wordByInsertion;
		}

		internal override string GetBuildingString()
		{ 
			return 
				"( " + 
				this.WordByInsertion.LetterClusterRow.String + 
				" ; " + 
				MainForm.Convert__InsertionIndex__into__ComboBoxSelectedItem(this.WordByInsertion.InsertionIndex) + 
				" )";
		}
	}
	internal class TreeViewNodeTag__WordDerivated : TreeViewNodeTag__Word
	{
		internal BabebiDataSet.WordDerivatedRow WordDerivated { get; private set; }

		public TreeViewNodeTag__WordDerivated(MainForm mainForm, BabebiDataSet.WordDerivatedRow wordDerivated) 
		: base(mainForm, wordDerivated.WordRowParent)
		{
			this.WordDerivated = wordDerivated;
		}

		internal override string GetBuildingString()
		{ 
			return 
				"( " + 
				this.WordDerivated.DerivatingRowParent.LetterClusterString + 
				" ; " + 
				(this.WordDerivated.DerivatingRowParent.AppendStringAtLast ? "At last" : "At first") + 
				" )";
		}
	}
	internal class TreeViewNodeTag__WordConcatenated : TreeViewNodeTag__Word
	{
		internal BabebiDataSet.WordConcatenatedRow	WordConcatenated { get; private set; }

		internal BabebiDataSet.WordRow				PriorWord { get; private set; }

		public TreeViewNodeTag__WordConcatenated(MainForm mainForm, BabebiDataSet.WordConcatenatedRow wordConcatenatedRow, BabebiDataSet.WordRow priorWord) 
		: base(mainForm, wordConcatenatedRow.WordRowParent)
		{
			this.WordConcatenated	= wordConcatenatedRow;
			this.PriorWord			= priorWord;
		}

		internal override string GetBuildingString()
		{ 
			BabebiDataSet.WordConcatenatedComponentRow[] wordConcatenatedComponents	
				= this.WordConcatenated.GetWordConcatenatedComponentRows();
			
			SortedDictionary<short, BabebiDataSet.WordRow> ranks__words 
				= new SortedDictionary<short, BabebiDataSet.WordRow>();
			
			foreach (BabebiDataSet.WordConcatenatedComponentRow wordConcatenatedComponent in wordConcatenatedComponents)
			{
				if (wordConcatenatedComponent.WordRow == this.PriorWord)
				{
					continue;
				}

				ranks__words.Add(wordConcatenatedComponent.Rank, wordConcatenatedComponent.WordRow);
			}

			bool isFirst = true;
			bool hasMoreThan1 = false;
			string buildingString = "";
			foreach (BabebiDataSet.WordRow word in ranks__words.Values)
			{ 
				BabebiDataSet.Word_LanguageRow word_Language
					= this.dataSet.Word_Language
					.FindByWordIdLanguageCode
					(	
						word.Id, 
						this.mainForm.Current__Language.Code
					);

				if (isFirst)
				{
					buildingString += "( "; 

					isFirst = false;
				}
				else
				{ 
					buildingString += ", ( ";

					if (! hasMoreThan1)
					{ 
						hasMoreThan1 = true;
					}
				}
				buildingString += "[ " + word.UniqueKeyString + " ] : '" + word_Language.Meaning + "' )";
			}

			if (hasMoreThan1)
			{
				buildingString = "{ " + buildingString + " }";
			}

			return buildingString;
		}
	}

	internal abstract class TreeViewNodeTag__Pattern : TreeViewNodeTag__WordOrPattern
	{
		internal BabebiDataSet.PatternRow Pattern;

		private	 BabebiDataSet.Pattern_LanguageRow pattern_Language; 

		public TreeViewNodeTag__Pattern(MainForm mainForm, BabebiDataSet.PatternRow pattern) 
		: base(mainForm, pattern.WordOrPatternRowParent)
		{
			this.Pattern = pattern;

			this.pattern_Language
				= this.dataSet.Pattern_Language.FindByPatternIdLanguageCode
				(
					this.Pattern.Id, 
					this.mainForm.Current__Language.Code
				);
		}

		internal override TreeViewNodeTag[] GetChildren()
		{
			TreeViewNodeTag[] base__TreeViewNodeTags = base.GetChildren();

			#region		(base) 'Patterns (By insertion)'

			string priorSubscriberCode	= MainForm.SubscriberCode_Pattern;
			string priorModeCode		= MainForm.ModeCode_ByInsertion;
			List<TreeViewNodeTag> priorList = new List<TreeViewNodeTag>(base__TreeViewNodeTags);

			#endregion	(base) 'Patterns (By insertion)'

			BabebiDataSet.FromPatternRow[] mixed_and_unsorted_array_of_FromPatterns  = this.Pattern.GetFromPatternRows();

			#region		'Words (From Pattern)' children

			List<TreeViewNodeTag__WordOrPattern> newList__WordFromPattern = new List<TreeViewNodeTag__WordOrPattern>();

			BabebiDataSet.FromPatternRow[] fromPatterns__Word 
				= TreeViewNodeTag__FromPattern_
				.Sort
				(
					mixed_and_unsorted_array_of_FromPatterns,
					MainForm.SubscriberCode_Word, 
					this.mainForm.VowelStrings, 
					this.mainForm.ConsonantStrings
				);

			foreach(BabebiDataSet.FromPatternRow fromPattern in fromPatterns__Word)
			{
				if (fromPattern.SubscriberCode == MainForm.SubscriberCode_Word) /// il faut continuer à checker ici au cas où le Sort fails.
				{
					BabebiDataSet.WordFromPatternRow wordFromPattern
						= this.dataSet.WordFromPattern.FindById(fromPattern.SubscriberId);

					if (wordFromPattern != null)
					{
						TreeViewNodeTag__WordFromPattern treeViewNodeTag__WordFromPattern
							= new TreeViewNodeTag__WordFromPattern(this.mainForm, wordFromPattern);

						newList__WordFromPattern.Add(treeViewNodeTag__WordFromPattern);
					}
				}
			}

			this.append
			(
				this.mainForm,
				this.WordOrPattern,
			ref	priorSubscriberCode, 
			ref	priorModeCode,
			ref	priorList, 
				MainForm.SubscriberCode_Word, 
				MainForm.ModeCode_FromPattern,
				newList__WordFromPattern
			);

			#endregion	'Words (From Pattern)' children
			#region		'Patterns (From Pattern)' children

			List<TreeViewNodeTag__WordOrPattern> newList__PatternFromPattern = new List<TreeViewNodeTag__WordOrPattern>();

			BabebiDataSet.FromPatternRow[] fromPatterns__Pattern
				= TreeViewNodeTag__FromPattern_
				.Sort
				(
					mixed_and_unsorted_array_of_FromPatterns,
					MainForm.SubscriberCode_Pattern, 
					this.mainForm.VowelStrings, 
					this.mainForm.ConsonantStrings
				);

			foreach(BabebiDataSet.FromPatternRow fromPattern in fromPatterns__Pattern)
			{
				if (fromPattern.SubscriberCode == MainForm.SubscriberCode_Pattern)	/// il faut continuer à checker ici au cas où le Sort fails.
				{
					BabebiDataSet.PatternFromPatternRow patternFromPattern
						= this.dataSet.PatternFromPattern.FindById(fromPattern.SubscriberId);

					TreeViewNodeTag__PatternFromPattern treeViewNodeTag__PatternFromPattern
						= new TreeViewNodeTag__PatternFromPattern(this.mainForm, patternFromPattern);

					newList__PatternFromPattern.Add(treeViewNodeTag__PatternFromPattern);
				}
			}

			this.append
			(
				this.mainForm,
				this.WordOrPattern,
			ref	priorSubscriberCode, 
			ref	priorModeCode,
			ref	priorList, 
				MainForm.SubscriberCode_Pattern, 
				MainForm.ModeCode_FromPattern,
				newList__PatternFromPattern
			);

			#endregion	'Patterns (From Pattern)' children

			return priorList.ToArray();
		}

		protected override string getUniqueKeyString()	{ return this.Pattern.UniqueKeyString; }
		protected override string getMeaning()			{ return this.pattern_Language.Meaning; }
	}
	internal class TreeViewNodeTag__PatternExNihilo : TreeViewNodeTag__Pattern
	{
		internal BabebiDataSet.PatternExNihiloRow PatternExNihilo { get; private set; }

		public TreeViewNodeTag__PatternExNihilo(MainForm mainForm, BabebiDataSet.PatternExNihiloRow patternExNihilo) 
		: base(mainForm, patternExNihilo.PatternRowParent)
		{
			this.PatternExNihilo = patternExNihilo;
		}

		internal override string GetBuildingString()
		{
			throw new NotImplementedException();	/// should never be called.
		}
	}
	internal class TreeViewNodeTag__PatternFromPattern : TreeViewNodeTag__Pattern
	{
		internal BabebiDataSet.PatternFromPatternRow PatternFromPattern { get; private set; }

		public TreeViewNodeTag__PatternFromPattern(MainForm mainForm, BabebiDataSet.PatternFromPatternRow patternFromPattern) 
		: base(mainForm, patternFromPattern.PatternRowParent)
		{
			this.PatternFromPattern = patternFromPattern;
		}

		internal override string GetBuildingString()
		{ 
			return MainForm.Compute__LetterDictionaryString__for_Pattern(this.PatternFromPattern.FromPatternRowParent);
		}
	}
	internal class TreeViewNodeTag__PatternByInsertion : TreeViewNodeTag__Pattern
	{
		internal BabebiDataSet.PatternByInsertionRow PatternByInsertion { get; private set; }

		public TreeViewNodeTag__PatternByInsertion(MainForm mainForm, BabebiDataSet.PatternByInsertionRow patternByInsertion) 
		: base(mainForm, patternByInsertion.PatternRowParent)
		{
			this.PatternByInsertion = patternByInsertion;
		}

		internal override string GetBuildingString()
		{ 
			return 
				"( " + 
				this.PatternByInsertion.LetterOrSymbolClusterRow.String + 
				" ; " + 
				MainForm.Convert__InsertionIndex__into__ComboBoxSelectedItem(this.PatternByInsertion.InsertionIndex) + 
				" )";
		}
	}

	internal static class TreeViewNodeTag__FromPattern_
	{ 
		internal static BabebiDataSet.FromPatternRow[] Sort
		(
			BabebiDataSet.FromPatternRow[] mixed_and_unsorted_array_of_fromPatterns, 
			string subscriberCode,
			string[] vowels, 
			string[] consonants
		)
		{ 
			List<string>	letterTypeCodeList	= new List<string>();
			string[]		letterTypeCodes		= new string[0];

			Dictionary<string, BabebiDataSet.FromPatternRow> letterCombinationStrings__fromPatterns
				= new Dictionary<string, BabebiDataSet.FromPatternRow>();
			
			bool firstDone = false;
			foreach (BabebiDataSet.FromPatternRow fromPattern in mixed_and_unsorted_array_of_fromPatterns)
			{
				if (fromPattern.SubscriberCode != subscriberCode)
				{
					continue;
				}

				string letterCombinationString = "";

				BabebiDataSet.FromPatternLetterRow[] fromPatternLetters 
					= fromPattern.GetFromPatternLetterRows();

				if (firstDone && letterTypeCodes.Length != fromPatternLetters.Length)
				{
					return mixed_and_unsorted_array_of_fromPatterns;
				}

				SortedDictionary<short, string> ranks__fromPatternLetterStrings = new SortedDictionary<short, string>();

				int  letterIndex = -1;	/// pour les Patterns on ne peut pas utiliser le Rank de FromPatternLetter.
				foreach (BabebiDataSet.FromPatternLetterRow fromPatternLetter in fromPatternLetters)
				{
					letterIndex++;

					ranks__fromPatternLetterStrings
						.Add
						(
							fromPatternLetter.Rank, 
							fromPatternLetter.LetterString
						);

					string typeCode = fromPatternLetter.LetterTypeCode;

					if (!firstDone)
					{
						letterTypeCodeList.Add(typeCode);
					}
					else
					{
						if (typeCode != letterTypeCodes[letterIndex])
						{ 
							return mixed_and_unsorted_array_of_fromPatterns;
						}
					}
				}

				foreach (string fromPatternLetterString in ranks__fromPatternLetterStrings.Values)
				{
					letterCombinationString += (letterCombinationString == "" ? "" : "#") + fromPatternLetterString;
				}

				letterCombinationStrings__fromPatterns
					.Add
					(
						letterCombinationString,
						fromPattern
					);

				if (!firstDone)
				{	
					firstDone = true;

					letterTypeCodes = letterTypeCodeList.ToArray();
				}
			}

			if (letterTypeCodes.Length == 0)
			{
				return new BabebiDataSet.FromPatternRow[0];
			}

			List<BabebiDataSet.FromPatternRow> extracted_and_sorted_list_of_fromPatterns 
				= new List<BabebiDataSet.FromPatternRow>();

			RussianLetterIndexer russianLetterIndexer 
				= new RussianLetterIndexer
				(
					0, 
					letterTypeCodes, 
					vowels,
					consonants
				);

			do
			{
				string candidateLetterCombinationString = russianLetterIndexer.GetString_of_sharp_separated_letters();

				if (letterCombinationStrings__fromPatterns.ContainsKey(candidateLetterCombinationString))
				{
					extracted_and_sorted_list_of_fromPatterns.Add(letterCombinationStrings__fromPatterns[candidateLetterCombinationString]);

					if (extracted_and_sorted_list_of_fromPatterns.Count == letterCombinationStrings__fromPatterns.Count)
					{ 
						break;
					}
				}
			}
			while (russianLetterIndexer.Next()) ;
			
			return extracted_and_sorted_list_of_fromPatterns.ToArray();
		}
	}
}
