<#@ import namespace="System" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Text.RegularExpressions" #>
<#
	{
		var psPrevAfterLoadMetadata = AfterLoadMetadata;

		AfterLoadMetadata = _ =>
		{
			psPrevAfterLoadMetadata(_);

			if (PluralizeDataContextPropertyNames || SingularizeDataContextPropertyNames)
			{
				foreach (var t in Tables.Values)
				{
					var propName = t.DataContextPropertyName ?? t.ClassName ?? t.TableName;
					var newName  = PluralizeDataContextPropertyNames ? ToPlural(propName) : ToSingular(propName);

					t.DataContextPropertyName = newName;
				}
			}

			if (PluralizeClassNames || SingularizeClassNames)
			{
				foreach (var t in Tables.Values)
				{
					var className = t.ClassName ?? t.TableName;
					var newName   = PluralizeClassNames ? ToPlural(className) : ToSingular(className);

					t.ClassName = newName;
				}
			}
		};

		PluralizeAssociationName   = ToPlural;
		SingularizeAssociationName = ToSingular;
	}

#><#+

bool PluralizeClassNames                 = false;
bool SingularizeClassNames               = true;
bool PluralizeDataContextPropertyNames   = true;
bool SingularizeDataContextPropertyNames = false;

string ToPlural(string str)
{
	var word    = GetLastWord(str);
	var newWord = Plurals.ToPlural(word);

	if (word != newWord)
	{
		if (char.IsUpper(word[0]))
			newWord = char.ToUpper(newWord[0]) + newWord.Substring(1, newWord.Length - 1);

		return word == str ? newWord : str.Substring(0, str.Length - word.Length) + newWord;
	}
	
	return str;
}

string ToSingular(string str)
{
	var word    = GetLastWord(str);
	var newWord = Plurals.ToSingular(word);

	if (word != newWord)
	{
		if (char.IsUpper(word[0]))
			newWord = char.ToUpper(newWord[0]) + newWord.Substring(1, newWord.Length - 1);

		return word == str ? newWord : str.Substring(0, str.Length - word.Length) + newWord;
	}
	
	return str;
}

string GetLastWord(string word)
{
	if (string.IsNullOrEmpty(word))
		return word;

	var len = word.Length;
	var n   = len - 1;

	if (char.IsLower(word[n]))
	{
		for (; n > 0 && char.IsLower(word[n]); n--);
	}
	else
	{
		for (; n > 0 && char.IsUpper(word[n]); n--);
		if (char.IsLower(word[n]))
			n++;
	}

	return n > 0 ? word.Substring(n) : word;
}

// Shamelessly jacked from http://www.bennysutton.com/C-sharp/Plural-Singular-Words.aspx with little modifications.
//

//using System;
//using System.Collections.Generic;
//using System.Text;
//using System.Text.RegularExpressions;

/// <summary>
/// Convert words to and from singulars/plurals
/// Copyright www.BennySutton.com 2008
/// You may reuse this code BUT not for sale AND ONLY with credit to www.BennySutton.com
/// </summary>
public sealed class Plurals
{
	/// <summary>
	/// Store irregular plurals in a dictionary
	/// </summary>
	private static Dictionary<string, string> _dictionary = new Dictionary<string, string>();

	#region Constructors
	
	/// <summary>
	/// The singleton instance (thanks to dotnetpearls.com for help here)
	/// </summary>
	static readonly Plurals _instance = new Plurals();
	/// <summary>
	/// Get an instance of the structure singleton. This effectively caches the dictionary 
	/// </summary>
	public static Plurals Instance
	{
		get
		{
			// Fastest solution that avoids null check and is thread-safe
			// because of readonly keyword.
			return _instance;
		}
	}
	
	/// <summary>
	/// Run initialization on this singleton class
	/// </summary>
	private Plurals()
	{
		Initialize();
	}

	private void Initialize()
	{
		//to test that this class only initializes once uncomment next line
		//System.Web.HttpContext.Current.Response.Write("initializing singleton <br>");
		// irregular plurals
		_dictionary.Add("access",       "accesses");
		_dictionary.Add("afterlife",    "afterlives");
		_dictionary.Add("alga",         "algae");
		_dictionary.Add("alumna",       "alumnae");
		_dictionary.Add("alumnus",      "alumni");
		_dictionary.Add("analysis",     "analyses");
		_dictionary.Add("antenna",      "antennae");
		_dictionary.Add("appendix",     "appendices");
		_dictionary.Add("axis",         "axes");
		_dictionary.Add("bacillus",     "bacilli");
		_dictionary.Add("basis",        "bases");
		_dictionary.Add("Bedouin",      "Bedouin");
		_dictionary.Add("cactus",       "cacti");
		_dictionary.Add("calf",         "calves");
		_dictionary.Add("cherub",       "cherubim");
		_dictionary.Add("child",        "children");
		_dictionary.Add("cod",          "cod");
		_dictionary.Add("cookie",       "cookies");
		_dictionary.Add("criterion",    "criteria");
		_dictionary.Add("curriculum",   "curricula");
		_dictionary.Add("data",         "data");
		_dictionary.Add("deer",         "deer");
		_dictionary.Add("diagnosis",    "diagnoses");
		_dictionary.Add("die",          "dice");
		_dictionary.Add("dormouse",     "dormice");
		_dictionary.Add("elf",          "elves");
		_dictionary.Add("elk",          "elk");
		_dictionary.Add("erratum",      "errata");
		_dictionary.Add("esophagus",    "esophagi");
		_dictionary.Add("fauna",        "faunae");
		_dictionary.Add("fish",         "fish");
		_dictionary.Add("flora",        "florae");
		_dictionary.Add("focus",        "foci");
		_dictionary.Add("foot",         "feet");
		_dictionary.Add("formula",      "formulae");
		_dictionary.Add("fundus",       "fundi");
		_dictionary.Add("fungus",       "fungi");
		_dictionary.Add("genie",        "genii");
		_dictionary.Add("genus",        "genera");
		_dictionary.Add("goose",        "geese");
		_dictionary.Add("grouse",       "grouse");
		_dictionary.Add("hake",         "hake");
		_dictionary.Add("half",         "halves");
		_dictionary.Add("headquarters", "headquarters");
		_dictionary.Add("hippo",        "hippos");
		_dictionary.Add("hippopotamus", "hippopotami");
		_dictionary.Add("hoof",         "hooves");
		_dictionary.Add("housewife",    "housewives");
		_dictionary.Add("hypothesis",   "hypotheses");
		_dictionary.Add("index",        "indices");
		_dictionary.Add("jackknife",    "jackknives");
		_dictionary.Add("knife",        "knives");
		_dictionary.Add("labium",       "labia");
		_dictionary.Add("larva",        "larvae");
		_dictionary.Add("leaf",         "leaves");
		_dictionary.Add("life",         "lives");
		_dictionary.Add("loaf",         "loaves");
		_dictionary.Add("louse",        "lice");
		_dictionary.Add("magus",        "magi");
		_dictionary.Add("man",          "men");
		_dictionary.Add("memorandum",   "memoranda");
		_dictionary.Add("midwife",      "midwives");
		_dictionary.Add("millennium",   "millennia");
		_dictionary.Add("moose",        "moose");
		_dictionary.Add("mouse",        "mice");
		_dictionary.Add("nebula",       "nebulae");
		_dictionary.Add("neurosis",     "neuroses");
		_dictionary.Add("nova",         "novas");
		_dictionary.Add("nucleus",      "nuclei");
		_dictionary.Add("oesophagus",   "oesophagi");
		_dictionary.Add("offspring",    "offspring");
		_dictionary.Add("ovum",         "ova");
		_dictionary.Add("ox",           "oxen");
		_dictionary.Add("papyrus",      "papyri");
		_dictionary.Add("passerby",     "passersby");
		_dictionary.Add("penknife",     "penknives");
		_dictionary.Add("person",       "people");
		_dictionary.Add("phenomenon",   "phenomena");
		_dictionary.Add("placenta",     "placentae");
		_dictionary.Add("pocketknife",  "pocketknives");
		_dictionary.Add("process",      "processes");
		_dictionary.Add("pupa",         "pupae");
		_dictionary.Add("radius",       "radii");
		_dictionary.Add("reindeer",     "reindeer");
		_dictionary.Add("retina",       "retinae");
		_dictionary.Add("rhinoceros",   "rhinoceros");
		_dictionary.Add("roe",          "roe");
		_dictionary.Add("salmon",       "salmon");
		_dictionary.Add("scarf",        "scarves");
		_dictionary.Add("self",         "selves");
		_dictionary.Add("seraph",       "seraphim");
		_dictionary.Add("series",       "series");
		_dictionary.Add("sheaf",        "sheaves");
		_dictionary.Add("sheep",        "sheep");
		_dictionary.Add("shelf",        "shelves");
		_dictionary.Add("species",      "species");
		_dictionary.Add("spectrum",     "spectra");
		_dictionary.Add("status",       "status");
		_dictionary.Add("stimulus",     "stimuli");
		_dictionary.Add("stratum",      "strata");
		_dictionary.Add("supernova",    "supernovas");
		_dictionary.Add("swine",        "swine");
		_dictionary.Add("terminus",     "termini");
		_dictionary.Add("thesaurus",    "thesauri");
		_dictionary.Add("thesis",       "theses");
		_dictionary.Add("thief",        "thieves");
		_dictionary.Add("trout",        "trout");
		_dictionary.Add("vulva",        "vulvae");
		_dictionary.Add("wife",         "wives");
		_dictionary.Add("wildebeest",   "wildebeest");
		_dictionary.Add("wolf",         "wolves");
		_dictionary.Add("woman",        "women");
		_dictionary.Add("yen",          "yen");
	}
	
	#endregion //Constructors

	#region Methods
	
	/// <summary>
	/// Call this method to get the properly pluralized 
	/// English version of the word.
	/// </summary>
	/// <param name="word">The word needing conditional pluralization.</param>
	/// <param name="count">The number of items the word refers to.</param>
	/// <returns>The pluralized word</returns>
	static public string ToPlural(string word)
	{
		word = word.ToLower();
	
		if (_dictionary.ContainsKey(word)) 
		//it's an irregular plural, use the word from the dictionary
		{
			return _dictionary[word];
		}
		
		if (TestIsPlural(word) == true)
		{
			return word; //it's already a plural
		}
		
		if (word.Length <= 2)
		{
			return word; //not a word that can be pluralised!
		}
		
		////1. If the word ends in a consonant plus -y, change the -y into
		///-ie and add an -s to form the plural 
		///e.g. enemy--enemies baby--babies
		switch (word.Substring(word.Length - 2))
		{
			case "by":
			case "cy":
			case "dy":
			case "fy":
			case "gy":
			case "hy":
			case "jy":
			case "ky":
			case "ly":
			case "my":
			case "ny":
			case "py":
			case "ry":
			case "sy":
			case "ty":
			case "vy":
			case "wy":
			case "xy":
			case "zy":
				{
					return word.Substring(0, word.Length - 1) + "ies";
				}

			//2. For words that end in -is, change the -is to -es to make the plural form.
			//synopsis--synopses 
			//thesis--theses 
			case "is":
				{
					return word.Substring(0, word.Length - 1) + "es";
				}

			//3. For words that end in a "hissing" sound (s,z,x,ch,sh), add an -es to form the plural.
			//box--boxes 
			//church--churches
			case "ch":
			case "sh":
				{
					return word + "es";
				}
			default:
				{
					switch (word.Substring(word.Length - 1))
					{
						case "s":
						case "z":
						case "x":
							{
								return word + "es";
							}
						default:
							{
								//4. Assume add an -s to form the plural of most words.
								return word + "s";
							}
					}
				}
		}
	}
	
	/// <summary>
	/// Call this method to get the singular 
	/// version of a plural English word.
	/// </summary>
	/// <param name="word">The word to turn into a singular</param>
	/// <returns>The singular word</returns>
	static public string ToSingular(string word)
	{
		word = word.ToLower();

		if (_dictionary.ContainsKey(word))
			return word;

		if (_dictionary.ContainsValue(word))
		{
			foreach (KeyValuePair<string, string> kvp in _dictionary)
			{
				if (kvp.Value == word) return kvp.Key;
			}
		}

		if (word.Substring(word.Length - 1) != "s")
		{
			return word; // not a plural word if it doesn't end in S
		}

		if (word.Length <= 2)
		{
			return word; // not a word that can be made singular if only two letters!
		}

		if (word.Length >= 4)
		{
			// 1. If the word ends in a consonant plus -y, change the -y into -ie and add an -s to form the plural – so reverse engineer it to get the singular
			// e.g. enemy--enemies baby--babies family--families
			switch (word.Substring(word.Length - 4))
			{
				case "bies":
				case "cies":
				case "dies":
				case "fies":
				case "gies":
				case "hies":
				case "jies":
				case "kies":
				case "lies":
				case "mies":
				case "nies":
				case "pies":
				case "ries":
				case "sies":
				case "ties":
				case "vies":
				case "wies":
				case "xies":
				case "zies":
					{
						return word.Substring(0, word.Length - 3) + "y";
					}
				//3. For words that end in a "hissing" sound (s,z,x,ch,sh), add an -es to form the plural.
				//church--churches
				case "ches":
				case "shes":
					{
						return word.Substring(0, word.Length - 2);
					}
			}
		}

		if (word.Length >= 3)
		{
			switch (word.Substring(word.Length - 3))
			{
				//box--boxes 
				case "ses":
				//NOTE some false positives here - For words that end in -is, change the -is to -es to make the plural form.
				//synopsis--synopses 
				//thesis--theses 
				case "zes":
				case "xes":
					{
						return word.Substring(0, word.Length - 2);
					}
			}
		}

		if (word.Length >= 3)
		{
			switch (word.Substring(word.Length - 2))
			{
				case "es":
					{
						return word.Substring(0, word.Length - 1); // + "is";
					}
				//4. Assume add an -s to form the plural of most words.
				default:
					{
						return word.Substring(0, word.Length - 1);
					}
			}
		}

		return word;
	}

	/// <summary>
	/// test if a word is plural
	/// </summary>
	/// <param name="word">word to test</param>
	/// <returns>true if a word is plural</returns>
	static public bool TestIsPlural(string word)
	{
		word = word.ToLower();

		if (word.Length <= 2)
		{
			return false; // not a word that can be made singular if only two letters!
		}

		if (_dictionary.ContainsValue(word))
		{
			return true; //it's definitely already a plural
		}

		if (word.Length >= 4)
		{
			//1. If the word ends in a consonant plus -y, change the -y into -ie and add an -s to form the plural 
			// e.g. enemy--enemies baby--babies family--families
			switch (word.Substring(word.Length - 4))
			{
				case "bies":
				case "cies":
				case "dies":
				case "fies":
				case "gies":
				case "hies":
				case "jies":
				case "kies":
				case "lies":
				case "mies":
				case "nies":
				case "pies":
				case "ries":
				case "sies":
				case "ties":
				case "vies":
				case "wies":
				case "xies":
				case "zies":
				case "ches":
				case "shes":
					{
						return true;
					}
			}
		}

		if (word.Length >= 3)
		{
			switch (word.Substring(word.Length - 3))
			{
				//box--boxes 
				case "ses":
				case "zes":
				case "xes":
					{
						return true;
					}
			}
		}

		if (word.Length >= 3)
		{
			switch (word.Substring(word.Length - 2))
			{
				case "es":
					{
						return true;
					}
			}
		}

		if (word.Substring(word.Length - 1) != "s")
		{
			return false; // not a plural word if it doesn't end in S
		}

		return true;
	}

	#endregion
}

#>