using System;
using System.Collections.Generic;
using System.Text;

using Medivators.Common;
using Medivators.Data.Queries;

namespace Medivators.Reporting
{
	public class pwd
	{

		#region declarations

		private static bool _init;
		private static string _pwd;
		private static byte[] _bd = null;

		public enum VerifyResult
		{
			Valid,
			Malformed,
			Invalid,
			InvalidConfirmation,
			Exception
		}

		private class ConfirmationFails : ArgumentException { }
		private class Malformed : ArgumentException { }

		#endregion

		static public bool Set(string OldPwd, string NewPwd, string ConfirmNewPwd)
		{
			bool rtnVal = false;
			try
			{
				if (!_init)
					Initialize();

				ValidateChange(OldPwd, NewPwd, ConfirmNewPwd);
				using (UpdateAdmin update = new UpdateAdmin(Hash(NewPwd)))
				{
					rtnVal = (update.Update() != 0);
				}
			}
			catch (Exception ex)
			{
				ErrorHandler.GetInstance().LogException("pwd.Set", ex);
				rtnVal = false;
			}
			return rtnVal;
		}
		static public VerifyResult Verify(string Pwd)
		{
			VerifyResult rtnVal = VerifyResult.Invalid;
			try
			{
				if (!_init)
					Initialize();
				if (!Validate(Pwd))
					rtnVal = VerifyResult.Malformed;
				else
					if (Pwd.Equals(_pwd))
						rtnVal = VerifyResult.Valid;
					else
						if (Utilities.ByteArrayToString(_bd).Equals(Pwd))
							rtnVal = VerifyResult.Valid;
			}
			catch (Malformed)
			{
				rtnVal = VerifyResult.Malformed;
			}
			catch (ConfirmationFails)
			{
				rtnVal = VerifyResult.InvalidConfirmation;
			}

			catch (Exception ex)
			{
				ErrorHandler.GetInstance().LogException("pwd.Verify", ex);
				rtnVal = VerifyResult.Exception;
			}
			return rtnVal;
		}
		public static VerifyResult ValidateChange(string currentPwd, string newPwd, string confirmPwd)
		{
			VerifyResult rtnVal = VerifyResult.Invalid;
			try
			{
				if (Verify(currentPwd) == VerifyResult.Valid)
					if (Validate(newPwd, confirmPwd))
						rtnVal = VerifyResult.Valid;
			}
			catch (Malformed)
			{
				rtnVal = VerifyResult.Malformed;
			}
			catch (ConfirmationFails)
			{
				rtnVal = VerifyResult.InvalidConfirmation;
			}

			catch (Exception ex)
			{
				ErrorHandler.GetInstance().LogException("pwd.Verify", ex);
				rtnVal = VerifyResult.Exception;
			}
			return rtnVal;
		}

		private static void Initialize()
		{
			using (SelectAdmin select = new SelectAdmin())
			{
				string raw = select.Select();
				if ( raw != null && raw.Length > 0 )
					_pwd = Dehash(raw);
			}
			if (_bd == null)
				_bd = new byte[] {65,99,104,105,108,108,101,115};
			_init = true;
		}
		private static string Hash(string value)
		{ 
			string hash = string.Empty;
			if (value != null && value.Length > 0)
			{
				byte[] buffer = Utilities.StringToByteArray(value);
				for (int ctr = 0; ctr < buffer.Length; ctr++)
				{
					buffer[ctr] = (byte)((int)buffer[ctr] - 13);
					hash += buffer[ctr].ToString("000");
				}
			}
			return hash;
		}
		private static string Dehash(string value)
		{
			string rtnVal = string.Empty;
			if (value != null && value.Length > 0)
			{
				string[] values = new string[value.Length / 3];
				for (int ctr = 0; ctr < value.Length; ctr += 3)
					values[ctr / 3] = value.Substring(ctr, 3);
				byte[] buffer = new byte[values.Length];
				for (int ctr = 0; ctr < values.Length; ctr++)
				{
					buffer[ctr] = Convert.ToByte(values[ctr]);
					buffer[ctr] = (byte)((int)buffer[ctr] + 13);
				}
				rtnVal = Utilities.ByteArrayToString(buffer);
			}
			return rtnVal;
		}
		private static bool Validate(string pwd)
		{
			if (pwd.Length < 6 || pwd.Length > 10)
				throw new Malformed();
			return true;
		}
		private static bool Validate(string pwd, string confirmPwd)
		{
			if (pwd.Equals(confirmPwd))
				return Validate(pwd);
			else
				throw new ConfirmationFails();
		}
	}
}
