using System;
using System.Text;
using System.Text.RegularExpressions;

namespace CodeSmith.BaseTemplates
{
	/// <summary>
	/// Various string utility methods.
	/// </summary>
	public class StringUtility
	{
		
		private static readonly Regex _singleRegex1 = new Regex("(?<keep>[^aeiou])y$", RegexOptions.Compiled);
		private static readonly Regex _singleRegex2 = new Regex("(?<keep>[aeiou]y)$", RegexOptions.Compiled);
		private static readonly Regex _singleRegex3 = new Regex("(?<keep>[sxzh])$", RegexOptions.Compiled);
		private static readonly Regex _singleRegex4 = new Regex("(?<keep>[^sxzhy])$", RegexOptions.Compiled);
	
		private static readonly Regex _pluralRegex1 = new Regex("(?<keep>[^aeiou])ies$", RegexOptions.Compiled);
		private static readonly Regex _pluralRegex2 = new Regex("(?<keep>[aeiou]y)s$", RegexOptions.Compiled);
		private static readonly Regex _pluralRegex3 = new Regex("(?<keep>[sxzh])es$", RegexOptions.Compiled);
		private static readonly Regex _pluralRegex4 = new Regex("(?<keep>[^sxzhy])s$", RegexOptions.Compiled);

		private static readonly Regex _splitNameRegex = new Regex(@"[\W_]+", RegexOptions.Compiled);

		private StringUtility()
		{
		}
		
		/// <summary>
		/// Determines if a string is in plural form based on some simple rules.
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		public static bool IsPlural(string value)
		{		
			if (_pluralRegex1.IsMatch(value) || _pluralRegex2.IsMatch(value) || _pluralRegex3.IsMatch(value) || _pluralRegex4.IsMatch(value))
			{
				return true;
			}
			else
			{
				return false;
			}
		}
		
		/// <summary>
		/// Determines if a string is in singular form based on some simple rules.
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		public static bool IsSingular(string value)
		{
			return !IsPlural(value);
		}
		
		/// <summary>
		/// Converts a string to plural based on some simple rules.
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		public static string ToPlural(string value)
		{
			if (!IsSingular(value)) return value;
					
			if (_singleRegex1.IsMatch(value))
			{
				return _singleRegex1.Replace(value, "${keep}ies");
			}
			else if (_singleRegex2.IsMatch(value))
			{
				return _singleRegex2.Replace(value, "${keep}s");
			}
			else if (_singleRegex3.IsMatch(value))
			{
				return _singleRegex3.Replace(value, "${keep}es");
			}
			else if (_singleRegex4.IsMatch(value))
			{
				return _singleRegex4.Replace(value, "${keep}s");
			}
			
			return value;
		}
		
		/// <summary>
		/// Converts a string to singular based on some simple rules.
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		public static string ToSingular(string value)
		{
			if (!IsPlural(value)) return value;
					
			if (_pluralRegex1.IsMatch(value))
			{
				return _pluralRegex1.Replace(value, "${keep}y");
			}
			else if (_pluralRegex2.IsMatch(value))
			{
				return _pluralRegex2.Replace(value, "${keep}");
			}
			else if (_pluralRegex3.IsMatch(value))
			{
				return _pluralRegex3.Replace(value, "${keep}");
			}
			else if (_pluralRegex4.IsMatch(value))
			{
				return _pluralRegex4.Replace(value, "${keep}");
			}
			
			return value;
		}
		
		/// <summary>
		/// Converts a string to use camelCase.
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		public static string ToCamelCase(string value)
		{
			if (value == null || value.Length == 0)
				return value;
			
			string output = ToPascalCase(value);
			if (output.Length > 2)
				return char.ToLower(output[0]) + output.Substring(1);
			else
				return output.ToLower();
		}
		
		/// <summary>
		/// Converts a string to use PascalCase.
		/// </summary>
		/// <param name="value">Text to convert</param>
		/// <returns></returns>
		public static string ToPascalCase(string value)
		{
			if (value == null || value.Length == 0)
				return value;

			string[] names = _splitNameRegex.Split(value);
			StringBuilder output = new StringBuilder();
	
			if (names.Length > 1) 
			{
				foreach(string name in names)
				{
					if (name.Length > 1)
					{
						output.Append(char.ToUpper(name[0]));
						output.Append(name.Substring(1).ToLower());
					}						
					else
					{
						output.Append(name);
					}
				}	
			}
			else if (value.Length > 1)
			{
				output.Append(char.ToUpper(value[0]));
				output.Append(value.Substring(1));
			}
			else
			{
				output.Append(value.ToUpper());
			}

			return output.ToString();
		}

		/// <summary>
		/// Takes a NameIdentifier and spaces it out into words "Name Identifier".
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		public static string ToSpacedWords(string value)
		{
			StringBuilder spacedName = new StringBuilder();
			
			for (int i = 0; i < value.Length; i++)
			{
				if (i > 0 && i < value.Length - 1 && Char.IsUpper(value[i]))
				{
					spacedName.Append(" ");
				}
				spacedName.Append(value[i]);
			}
			
			return spacedName.ToString();
		}
	}
}
