using System;

namespace ExtensionMethods
{
	/// <summary>
	/// <para>Add extensions to <c><see cref="String"/></c></para>
	/// </summary>
	public static class StringExtensions
	{
		/// <summary>
		/// <para>Determines whether the specified <see cref="String"/> is null or an <see cref="String.Empty"/> string</para>
		/// </summary>
		/// <param name="str"></param>
		/// <returns><see cref="bool"/>. True: String is null or empty. False: String is not null and not empty</returns>
		public static bool IsEmpty(this string str)
		{
			return String.IsNullOrEmpty(str);
		}

		/// <summary>
		/// <para>Determines whether the specified <see cref="String"/> is null or an <see cref="String.Empty"/> string or does match the specified string <paramref name="alsoEmpty"/></para>
		/// </summary>
		/// <param name="str"></param>
		/// <param name="alsoEmpty">When the <see cref="String"/> matches this <see cref="String"/> it is also considered as "empty"</param>
		/// <returns><see cref="bool"/>. True: String is null or empty. False: String is not null and not empty</returns>
		public static bool IsEmptyOr(this string str, string alsoEmpty)
		{
			return String.IsNullOrEmpty(str) || str == alsoEmpty;
		}
		/// <summary>
		/// <para>Determines whether the specified <see cref="String"/> is null or an <see cref="String.Empty"/> string or does match the specified strings <paramref name="alsoEmpty1"/> or <paramref name="alsoEmpty2"/></para>
		/// </summary>
		/// <param name="str"></param>
		/// <param name="alsoEmpty1">When the <see cref="String"/> matches this <see cref="String"/> it is also considered as "empty"</param>
		/// <param name="alsoEmpty2">When the <see cref="String"/> matches this <see cref="String"/> it is also considered as "empty"</param>
		/// <returns><see cref="bool"/>. True: String is null or empty. False: String is not null and not empty</returns>
		public static bool IsEmptyOr(this string str, string alsoEmpty1, string alsoEmpty2)
		{
			return String.IsNullOrEmpty(str) || str == alsoEmpty1 || str == alsoEmpty2;
		}
		/// <summary>
		/// <para>Determines whether the specified <see cref="String"/> is null or an <see cref="String.Empty"/> string or any of the specified strings (<paramref name="alsoEmpty"/></para>
		/// </summary>
		/// <param name="str"></param>
		/// <param name="alsoEmpty">When the <see cref="String"/> matches this <see cref="String"/> it is also considered as "empty"</param>
		/// <returns><see cref="bool"/>. True: String is null or empty. False: String is not null and not empty</returns>
		public static bool IsEmptyOr(this string str, params string[] alsoEmpty)
		{
			if (String.IsNullOrEmpty(str))
				return true;

			foreach (string also in alsoEmpty)
				if (str == also)
					return true;

			return false;
		}

		/// <summary>
		/// <para>Determines whether the specified <see cref="String"/> is not null and not an <see cref="String.Empty"/> string</para>
		/// </summary>
		/// <param name="str"></param>
		/// <returns><see cref="bool"/>. True: String is not null and not empty. False: String is null or empty</returns>
		public static bool IsNotEmpty(this string str)
		{
			return !String.IsNullOrEmpty(str);
		}

		/// <summary>
		/// <para>Determines whether the specified <see cref="String"/> is not null, not an <see cref="String.Empty"/> string and does not match the specified string <paramref name="alsoEmpty"/></para>
		/// </summary>
		/// <param name="str"></param>
		/// <param name="alsoEmpty">When the <see cref="String"/> matches this <see cref="String"/> it is also considered as "empty"</param>
		/// <returns><see cref="bool"/>. True: String is not null, not empty and not equal to <paramref name="alsoEmpty"/>. False: String is null or empty</returns>
		public static bool IsNeitherEmptyNor(this string str, string alsoEmpty)
		{
			return !String.IsNullOrEmpty(str) && str != alsoEmpty;
		}
		/// <summary>
		/// <para>Determines whether the specified <see cref="String"/> is not null, not an <see cref="String.Empty"/> string and does not match the specified strings <paramref name="alsoEmpty1"/> or <paramref name="alsoEmpty2"/></para>
		/// </summary>
		/// <param name="str"></param>
		/// <param name="alsoEmpty1">When the <see cref="String"/> matches this <see cref="String"/> this function also returns false</param>
		/// <param name="alsoEmpty2">When the <see cref="String"/> matches this <see cref="String"/> this function also returns false</param>
		/// <returns><see cref="bool"/>. True: String is not null, not empty and not equal to <paramref name="alsoEmpty1"/> or <paramref name="alsoEmpty2"/>.</returns>
		public static bool IsNeitherEmptyNor(this string str, string alsoEmpty1, string alsoEmpty2)
		{
			return !String.IsNullOrEmpty(str) && str != alsoEmpty1 && str != alsoEmpty2;
		}
		/// <summary>
		/// <para>Determines whether the specified <see cref="String"/> is not null, not an <see cref="String.Empty"/> string and does not match any of the specified strings <paramref name="alsoEmpty"/></para>
		/// </summary>
		/// <param name="str"></param>
		/// <param name="alsoEmpty">When the <see cref="String"/> matches one of these <see cref="String"/>s this function returns false</param>
		/// <returns><see cref="bool"/>ean. True: String is not null, not empty and not equal to <paramref name="alsoEmpty"/>.</returns>
		public static bool IsNeitherEmptyNor(this string str, params string[] alsoEmpty)
		{
			if (String.IsNullOrEmpty(str))
				return false;

			foreach (string also in alsoEmpty)
				if (str == also)
					return false;

			return true;
		}

		/// <summary>
		/// <para>Join this array with the delimiter <paramref name="end"/>+<paramref name="begin"/> and begin and end at the beginning and at the end respectively</para>
		/// <para>Example: Begin: "B", End: "E-" --> B1E-B2E-B3E-</para>
		/// </summary>
		/// <example><para>Example: Begin: "B", End: "E-" --> B1E-B2E-B3E-</para></example>
		/// <param name="strs"></param>
		/// <param name="begin"></param>
		/// <param name="end"></param>
		/// <returns></returns>
		public static string Join(this string[] strs, string begin, string end)
		{
			string ret = begin;
			ret += String.Join(end + begin, strs);
			ret += end;
			return ret;
		}
		/// <summary>
		/// <para>Join this array with the delimiter <paramref name="end"/>+<paramref name="begin"/> and begin and end at the beginning and at the end respectively</para>
		/// <para>Example: Begin: "B", End: "E-" --> B1E-B2E-B3E</para>
		/// </summary>
		/// <example><para>Example: Begin: "B", Delimiter "-", End: "E" --> B1E-B2E-B3E</para></example>
		/// <param name="strs"></param>
		/// <param name="begin"></param>
		/// <param name="delimiter"></param>
		/// <param name="end"></param>
		/// <returns></returns>
		public static string Join(this string[] strs, string begin, string delimiter, string end)
		{
			string ret = begin;
			ret += String.Join(end + delimiter + begin, strs);
			ret += end;
			return ret;
		}
		/// <summary>
		/// <para>Concatenates a specified separator <see cref="String"/> between each element of a specified <see cref="String"/> array, yielding a single concatenated string</para>
		/// </summary>
		/// <param name="strs"></param>
		/// <param name="delimiter"><see cref="String"/> between the array elements</param>
		/// <returns>A single concatenated string</returns>
		public static string Join(this string[] strs, string delimiter)
		{
			return String.Join(delimiter, strs);
		}

		/// <summary>
		/// <para>Retrieves a substring from this instance. The substring starts at a specified character position and has a specified <paramref name="length"/>.</para>
		/// <para>If the length of the instance is shorter than the specified <paramref name="length"/> the <paramref name="str"/>ing itself is returned</para>
		/// </summary>
		/// <param name="str"><see cref="String"/></param>
		/// <param name="startIndex">Character position where substring shall start, beginning at 0</param>
		/// <param name="length">The (maximum) length of the substring</param>
		/// <returns>Substring</returns>
		public static string SafeSubstring(this string str, int startIndex, int length)
		{
			if (str.Length <= length)
				return str;
			else if (startIndex + length <= str.Length)
				return str.Substring(startIndex, length);
			else
				return str.Substring(startIndex, str.Length - startIndex);
		}

		/// <summary>
		/// <para>Returns the value of this <see cref="String"/> or <see cref="DBNull"/>.Value if the string <see cref="IsEmpty"/> or matches <paramref name="considerEmpty"/></para>
		/// </summary>
		/// <param name="str"></param>
		/// <param name="considerEmpty">When the <see cref="String"/> matches this <see cref="String"/> it is also considered as "empty"</param>
		/// <returns>The <see cref="String"/> or <see cref="DBNull"/></returns>
		public static object DBValue(this string str, string considerEmpty)
		{
			if (str.IsEmptyOr(considerEmpty))
				return DBNull.Value;
			else
				return str;
		}
	}
}