using System;
using mgaia.Utils.Security;

namespace mgaia.Utils.Persistence
{
	/// <summary>
	/// Post processor que criptografa e descriptografa valores de uma interface de persistência
	/// </summary>
	/// <owner>Victor</owner>
	public class SafePersistenceManagerPostProcessor : IPersistenceManagerPostProcessor
	{
		private ICryptoProcessor mCryptoProcessor;

		public SafePersistenceManagerPostProcessor(ICryptoProcessor cryptoProcessor)
		{
			mCryptoProcessor = cryptoProcessor;
		}

		/// <summary>
		/// Processa o valor que vem da interface de persistência e descriptografa ele
		/// </summary>
		public object ProcessFromInterface(string key, object defaultValue, Type typeOfValue, IPersistenceFileInterface persistenceFileInterface)
		{
			string stringValue = GetStringValue(key, defaultValue, persistenceFileInterface);
			object returnValue = defaultValue;

			if (typeOfValue.Equals(typeof(float)))
			{
				float floatValue;
				if (float.TryParse(stringValue, out floatValue))
				{
					returnValue = floatValue;
				}
			}
			else if (typeOfValue.Equals(typeof(int)))
			{
				int intValue;
				if (int.TryParse(stringValue, out intValue))
				{
					returnValue = intValue;
				}
			}
			else if (typeOfValue.Equals(typeof(string)))
			{
				returnValue = stringValue;
			}
			else
			{
				Assert.AssertTrue(false, "Tipo desconhecido! Tipo : " + typeOfValue.Name);
			}

			return returnValue;
		}

		/// <summary>
		/// Processa o valor e encripta ele para salvá-lo na interface de persistência
		/// </summary>
		public void SaveToInterface(string key, object value, Type typeOfValue, IPersistenceFileInterface persistenceFileInterface)
		{
			if (typeOfValue.Equals(typeof(float)) || typeOfValue.Equals(typeof(int)) || typeOfValue.Equals(typeof(string)))
			{
				SetStringValue(key, value, persistenceFileInterface);
			}
			else
			{
				Assert.AssertTrue(false, "Tipo desconhecido! Tipo : " + typeOfValue.Name);
			}
		}

		/// <summary>
		/// Tenta buscar o valor em string na chave, caso não exista ou se a integridade estiver violada, retorna o valor padrão
		/// </summary>
		private string GetStringValue(string key, object defaultValue, IPersistenceFileInterface persistenceFileInterface)
		{
			string defaultValueString = defaultValue.ToString();
			string defaultEncryptedValue = EncryptValue(defaultValueString);
			string fileEncryptedValue = persistenceFileInterface.GetString(key, defaultEncryptedValue);

			try
			{
				string decryptedValue = mCryptoProcessor.Decrypt(fileEncryptedValue);
				return decryptedValue;
			}
			catch (UnableToDecryptException)
			{
				return defaultValueString;
			}
		}

		/// <summary>
		/// Converte o valor do objeto enviado para string, criptografa ele e salva no arquivo na chave enviada
		/// </summary>
		private void SetStringValue(string key, object value, IPersistenceFileInterface persistenceFileInterface)
		{
			string encryptedValue = EncryptValue(value.ToString());
			persistenceFileInterface.SetString(key, encryptedValue);
		}

		/// <summary>
		/// Criptograda um valor em string 
		/// </summary>
		private string EncryptValue(string value)
		{
			return mCryptoProcessor.Encrypt(value);
		}
	}
}