using System;
using System.Text.RegularExpressions;

namespace Orciid.Core
{
	/// <summary>
	/// IP address
	/// </summary>
	/// <remarks>
	/// This utility class provides methods to check and compare IP addresses.
	/// </remarks>
	public class IPAddress
	{
		private const string pattern = 
			@"^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\." +
			@"(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\." + 
			@"(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\." +
			@"(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";

		private static Regex regex = new Regex(pattern);

		/// <summary>
		/// Check IP address for validity
		/// </summary>
		/// <remarks>
		/// An IP address is accepted as valid if it consists of four integers (base 10) 
		/// separated by periods,
		/// with each integer being in the range 0 through 255.  No whitespace is allowed.
		/// </remarks>
		/// <param name="address">The IP address to check</param>
		/// <returns><c>true</c> if the provided address is valid, <c>false</c> otherwise.</returns>
		public static bool IsValid(string address)
		{
			return regex.IsMatch(address);
		}

		/// <summary>
		/// Check if an IP address is in a certain range of addresses
		/// </summary>
		/// <remarks>
		/// This method checks if a specified address is in a certain range of addresses,
		/// defined by a subnet address and net mask.
		/// </remarks>
		/// <example>
		/// <code>IPAddress.IsInSubnet("192.168.1.101", "192.168.0.0", "255.255.0.0") == true</code>
		/// <code>IPAddress.IsInSubnet("192.168.1.101", "192.168.2.0", "255.255.255.0") == false</code>
		/// </example>
		/// <param name="address">The address to check</param>
		/// <param name="subnet">The subnet/range address</param>
		/// <param name="mask">The net mask</param>
		/// <returns><c>true</c> if the specified address is in the specified range,
		/// <c>false</c> if not or if any parameter is not a valid IP address.</returns>
		public static bool IsInSubnet(string address, string subnet, string mask)
		{
			Match a = regex.Match(address);
			Match s = regex.Match(subnet);
			Match m = regex.Match(mask);
			if (a.Success && s.Success && m.Success)
			{
				for (int i = 1; i <= 4; i++)
				{
					int aa = Int32.Parse(a.Groups[i].Value);
					int ss = Int32.Parse(s.Groups[i].Value);
					int mm = Int32.Parse(m.Groups[i].Value);
					if ((ss & mm) != (aa & mm))
						return false;
				}
				return true;
			}
			else
				return false;
		}
	}
}
