using System;
using System.Data;
using System.Globalization;

namespace LLNet.Utils
{
	/// <summary>
	/// Clase que contiene métodos de ayuda para el programador
	/// </summary>
	public class Helpers
    {
        public static string psocio;
        public static string pdocumento;
        public static string pFactCredito;

		/// <summary>
		/// Devuelve 0 si el bool es falso y 1 en caso contrario
		/// </summary>
		/// <param name="Flag">valor a convertir</param>
		/// <returns>objeto convertido a entero</returns>
		public static int BoolToInt(bool Flag)
		{
			return (Flag ? 1 : 0);
		}

        public static bool IntToBool(int i)
        {
            return (i == 1);
        }
        
        public static string InitCap(string sValue)
		{
            return InitCap(sValue,false);
		}

		public static string InitCap(string sValue, bool keepUnderscore)
		{
			string result;
			TextInfo jd =new CultureInfo("en-US",false).TextInfo ;
			
			if (keepUnderscore)
				result = jd.ToTitleCase(jd.ToLower(sValue));
			else
				result = jd.ToTitleCase(jd.ToLower(sValue)).Replace("_"," ");

			return result;
		}

		/// <summary>
		/// Devuelve el valor enviado por default en caso el objeto sea nulo
		/// </summary>
		/// <param name="objData">valor original</param>
		/// <param name="objData">valor predeterminado</param>
		/// <returns>valor establecido según el valor original</returns>
		public static object Nvl(object objData, object objDefault)
		{
			// Declaracion de variables
			object objRet = objData;

			if ((objData == null) || (objData == System.DBNull.Value) || (objData.Equals(System.Single.NaN)) )
				objRet = objDefault;

			return objRet;
		}

		/// <summary>
		/// Devuelve nulo en caso ambos valores sean iguales
		/// </summary>
		/// <param name="value1">valor a comparar</param>
		/// <param name="value2">valor a comparar</param>
		/// <returns>valor establecido según la comparación</returns>
		public static object NullIf(object value1, object value2)
		{
			object tmp = value1;

			try 
			{
				if ( value1.Equals(value2) ) tmp = null;
				if ( value1 == value2 )		 tmp = null;
			}
			catch {	}
			return tmp;
		}

		/// <summary>
		/// Devuelve el valor enviado por default en caso ambos valores sean iguales
		/// </summary>
		/// <param name="value1">valor a comparar</param>
		/// <param name="value2">valor a comparar</param>
		/// <param name="returnValue">valor predeterminado</param>
		/// <returns>valor establecido según la comparación</returns>
		public static object IfEqualValue(object value1, object value2, object returnValue)
		{
			object tmp = value1;

			try 
			{
				if ( value1.Equals(value2) ) tmp = returnValue;
				if ( value1 == value2 )		 tmp = returnValue;
			}
			catch {	}
			return tmp;
		}

		public static string dcm(string info)
		{
			return Nvl(info, "").ToString().Replace("\"", "\"\"");
		}
		public static string sdcm(string info)
		{
			return "\"" + dcm(info) + "\"";
		}
		public static string cm(string info)
		{
			return Nvl(info, "").ToString().Replace("'", "''");
		}
		public static string scm(string info, bool allowempty)
		{
			string tmp = info;
			tmp = (!allowempty && (tmp == "")) ? "null" : "'" + cm(tmp) + "'";
			return tmp;
		}
		public static string scm(string info)
		{
			return scm(info, false);
		}

		public static bool IsNull(object objData)
		{
			return ( (objData == null) || (objData == System.DBNull.Value) || (objData.Equals(System.Single.NaN)) );
		}

		/// <summary>
		/// Devuelve el porcentaje que representa el valor respecto al total según la base
		/// </summary>
		/// <param name="Base">base de conversión, por lo regular es 100 (i.e. 100%) </param>
		/// <param name="Valor">número a convertir a porcentaje</param>
		/// <param name="Total">número que representa el todo (100%)</param>
		/// <returns>porcentaje representado</returns>
		public static double Porcentaje(double Base, double Valor, double Total)
		{
			double percent = 0;

			if (Total == 0)
			{
				percent = Valor;
			}
			else
			{
				percent = (Valor * Base / Total);
			}
			return percent;
		}

		/// <summary>
		/// Devuelve el porcentaje que representa el valor respecto al total
		/// </summary>
		/// <param name="Valor">número a convertir a porcentaje</param>
		/// <param name="Total">número que representa el todo (100%)</param>
		/// <returns>porcentaje representado</returns>
		public static double Porcentaje(double Valor, double Total)
		{
			return Porcentaje(100, Valor, Total);
		}

		/// <summary>
		/// Devuelve un string vacío si es nulo, si no devuelve el objeto convertido a string
		/// </summary>
		/// <param name="s">objeto a convertir en string</param>
		/// <returns>objeto convertido a string o string vacío</returns>
		public static string ObjToStr(object s)
		{
			return (s == null) ? "" : s.ToString();
		}

        /// <summary>
        /// Devuelve null si se manda un string vacío, si no devuelve el objeto nuevamente
        /// </summary>
        /// <param name="s">objecto a validar</param>
        /// <returns></returns>
		public static object BlankToNull(object s)
		{
			return ((ObjToStr(s).Trim() == "") ? null : s);
		}

		public static string ObjToNullStr(object s)
		{
			return (s == null || s.ToString() == "") ? "NULL" : s.ToString();		
		}

		public static long ObjToInt64(object s)
		{
			return (s == null) ? -1 : Int64.Parse(s.ToString());		
		}

		public static bool IsQuoted(System.Data.DataColumn col)
		{
			
			if (col.DataType == typeof(Char) ||
				col.DataType == typeof(String) ||
				col.DataType == typeof(DateTime) )
			{	
				return true;
			}
			else
			{
				return false;	
			}
		}

		public static void Merge(DataSet source, DataSet target)
		{
			bool validateConstraints = target.EnforceConstraints;

			if (validateConstraints)
			{
				target.EnforceConstraints = false;
			}

			foreach (DataTable dt in target.Tables)
			{
				foreach (DataRow dr in dt.Select("","",DataViewRowState.Added))
				{
					dt.Rows.Remove(dr);
				}
			}

			target.Merge(source);
			target.AcceptChanges();			

			if (validateConstraints)
			{
				try
				{
					target.EnforceConstraints = true;
				} 
				catch (Exception e)
				{
					Console.WriteLine(e.Message);
				}
			}
		}

		public static void Merge(DataRow[] source, DataSet target)
		{
			bool validateConstraints = target.EnforceConstraints;

			if (validateConstraints)
			{
				target.EnforceConstraints = false;
			}

			target.Merge(source);
			target.AcceptChanges();			

			if (validateConstraints)
			{
				try
				{
					target.EnforceConstraints = true;
				} 
				catch (Exception e)
				{
					Console.WriteLine(e.Message);
				}
			}
		}

		public static String[] ArrayListToStrList(System.Collections.ArrayList array)
		{
			String[] result = new String[array.Count];

			int i = 0;
			foreach(object obj in array)
			{
				result[i] = obj.ToString();
				i++;
			}	
			return result;
		}

		#region Conversion de numeros a letras

			private static string IntegerToLetters(int Number, bool Caption)
			{
				//-- Declaracion de variables
				string strLetras = "";
				string strTmp = "";
				bool bShow = true;
				int iUnidades = 0;
				int iDecenas = 0;
				int iCentenas = 0;
				int iPos = 0;
				int iTotPos = 0;
				//-- Declaracion de constantes
				string[] unidades = { "cero", "uno", "dos", "tres", "cuatro", "cinco", "seis", "siete", "ocho", "nueve"};
				string[] decenas = { "diez", "veinte", "treinta", "cuarenta", "cincuenta", "sesenta", "setenta", "ochenta", "noventa" };
				string[] centenas = { "cien", "ciento", "doscientos", "trescientos", "cuatrocientos", "quinientos", "seiscientos", "setecientos", "ochocientos", "novecientos" };
				string[] unidadesespeciales = { "un" } ;
				string[] decenasespeciales = { "dieci", "veinti"};
				string[] especiales10 = {"once", "doce", "trece", "catorce", "quince"};
				string[] millares = { "mil", "millón", "billón", "trillón" };
				string[] millaresespeciales = { "mil", "millones", "billones", "trillones" };
				//-- Convertimos el número a string
				string strNumber = Number.ToString("#0");
				int toPad = ( strNumber.Length  % 3 );
				//-- Reformateamos el string
				if (toPad > 0)
					strNumber = strNumber.PadLeft( strNumber.Length + ( 3 - toPad ), Convert.ToChar("0") );
				//-- Establecemos posiciones
				iTotPos = strNumber.Length / 3;
				//-- Validación Inicial
				if ( iTotPos > 8 )
					throw new Exception("El número es demasiado grande");
				//-- Establecemos el significado de la parte entera
				for ( int i = strNumber.Length - 1; i >= 0; i -= 3 )
				{
					//-- Obtenemos los valores
					strTmp = "";
					iUnidades = Convert.ToInt32( strNumber.Substring(i, 1) );
					iDecenas  = Convert.ToInt32( strNumber.Substring(i - 1, 1) );
					iCentenas = Convert.ToInt32( strNumber.Substring(i - 2, 1) );
					iPos = iTotPos - ( (i + 1) / 3 );
					//-- Establecemos el nombre de las centenas
					if (iCentenas > 0)
					{
						switch (iCentenas)
						{
							case 1:
								strTmp += centenas[ (iDecenas + iUnidades == 0) ? 0 : 1 ] + " ";
								break;
							default:
								strTmp += centenas[iCentenas] + " ";
								break;
						}
					}
					//-- Establecemos el nombre de las decenas
					if (iDecenas > 0)
					{
						switch ( iDecenas )
						{
							case 1:
								if ( iUnidades == 0 )		{	strTmp += decenas[iDecenas-1] + " ";	}
								else if ( iUnidades <= 5 )	{	strTmp += especiales10[iUnidades - 1] + " "; }
								else {	strTmp += decenasespeciales[0] + unidades[iUnidades] + " ";	}
								break;
							case 2:
								if ( iUnidades == 0 )		
								{	
									strTmp += decenas[iDecenas-1];	
								}
								else
								{
									strTmp += decenasespeciales[1];
									strTmp += ( ((iPos == 0) && !Caption) || (iUnidades != 1)) ? unidades[iUnidades] : unidadesespeciales[0];
								}
								strTmp += " ";
								break;
							default:
								strTmp += decenas[iDecenas - 1];
								strTmp += (iUnidades > 0) ? " y " : " ";
								break;
						}
					}
					//-- Establecemos el nombre de las unidades
					if ( (iDecenas == 0) || (iDecenas > 2) )
					{
						switch ( iUnidades )
						{
							case 0:
								strTmp += ( (iTotPos == 1) && (iDecenas + iCentenas == 0) ) ? unidades[iUnidades] + " " : "";
								break;
							case 1:
								strTmp += ((iPos == 0) && !Caption) ? unidades[iUnidades] : unidadesespeciales[0];
								strTmp += " ";
								break;
							default:
								strTmp += unidades[iUnidades] + " ";
								break;
						}
					}
					//-- Establecemos el nombre de los millares
					bShow = true;
					switch( iPos )
					{
						case 1:	case 3:	case 5:	case 7:
							if ( (iUnidades + iDecenas + iCentenas) != 0)
								strTmp += millares[0] + " ";
							break;
						case 2: case 4:	case 6:
							bShow = true;
							if ( (iPos + 1) < iTotPos )
								bShow = Convert.ToInt32( strNumber.Substring( i-5, 3 ) ) > 0;
							if ( bShow )
							{ 
								strTmp += (iUnidades == 1) ? millares[ iPos/2 ] : millaresespeciales[ iPos/2 ];
								strTmp += " ";
							}
							break;
						default:
							break;
					}
					strLetras = String.Concat( strTmp, strLetras );
				}
				return strLetras;
			}

			public static string IntegerToLetters(int Number, string Desc)
			{
				//-- Obtenemos la traduccion
				string strNumber = IntegerToLetters( Number, Desc.Trim().Length != 0 );
				//-- Establecemos la descripcion
				string strLetras = String.Concat( strNumber, Desc).Trim();
				//-- Regresamos el resultado
				return strLetras;
			}

			public static string CurrencyToLetters(double Number, string CurrencyDesc, string CentsDesc, NtoLFormats fnFormat)
			{
				//-- Convertimos el número a string
				string strLetras = "";
				string strNumber = Number.ToString("#0.00");
				int iEnteros = Convert.ToInt32( strNumber.Substring( 0, strNumber.Length - 3) ); 
				int iDecimales = Convert.ToInt32( strNumber.Substring( strNumber.Length - 2, 2) );
				//-- Obtenemos las descripciones
				string strEnteros = IntegerToLetters( iEnteros, String.Concat(CurrencyDesc.Trim(),CentsDesc.Trim()).Length != 0 );
				string strDecimales = "";
				if (fnFormat == NtoLFormats.AllLetterFormat)
				{
					strDecimales = IntegerToLetters( iDecimales,  CentsDesc.Trim().Length != 0 );;
				}
				else
				{
					strDecimales = String.Format("{0:#00}/100 ", iDecimales );
				}
				//-- Establecemos la descripcion
				strLetras = String.Concat( strEnteros, CurrencyDesc, " ", strDecimales, CentsDesc).Trim();
				//-- Regresamos el resultado
				return strLetras;
			}

		#endregion
	}

    

	public enum NtoLFormats
	{
		CentsFormat,
		AllLetterFormat
	}
}