using System;
using System.IO;
using System.Net;
using System.Text;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Xml;
using System.Xml.Serialization;
using System.ComponentModel;

namespace Consulenza.ReportCommon
{
    /// <summary>
    /// Classe di Helper
    /// </summary>
    public static class Helper
    {
        public static string orizzonteTemporale(string valore)
        {
            string orzTempMesiString = valore;
            switch (orzTempMesiString)
            {
                case "6":

                    return "sei mesi";

                case "1":
                case "12":
                    return "un anno";
                case "3": //aò decidiamoci da fe sono anni, qui sono mesi...ricordarsi di controllarlo
                case "36":
                    return "tre anni";
                case "5":
                case "60":

                    return "cinque anni";
                case "7":
                case "84":

                    return "sette anni";
                case "9":
                case "108":
                    return "nove anni";
                case "10":
                case "120":
                    return "dieci anni";

                default:
                    return "sette anni";
            }
        }
        /// <summary>
        /// Recupera la larghezza proporzionale in funzione dei parametri passati in input.
        /// La larghezza restituita è la proporzione matematica (width : value = x : maxvalue)
        /// </summary>
        /// <param name="value">valore da rappresentare</param>
        /// <param name="maxvalue">Valore massimo</param>
        /// <param name="width">larghezza</param>
        /// <returns></returns>
        public static float GetWidthProportional(float value, float maxvalue, float width)
        {
            return (width * value) / maxvalue;
        }

        public static string FirstCharToUpper(string input)
        {
            if (string.IsNullOrEmpty(input))
            {
                return input;
            }
            return input.Substring(0, 1).ToUpper() + input.Substring(1, input.Length - 1).ToLower();
        }

        public static int GetNumericStringWidth(string number)
        {
            int width = 0;
            foreach (char s in number)
            {
                if (s == '.' || s == ',' || s == 'i')
                {
                    width += 1;
                }
                else if (s == '%')
                {
                    width += 8;
                }
                else
                {
                    width += 5;
                }
            }
            return width;
        }

        /// <summary>
        /// Controlla se il valore passato in input è in formato numerico e ne restituisce la sua conversione in formato valuta con 2 decimali.
        /// Se il controllo a numerico fallisce, viene restituita la stringa passata in input.
        /// </summary>
        /// <param name="value">Valore da formattare</param>
        /// <returns></returns>
        public static string FormatCurrency(string value)
        {
            decimal decimalValue;
            var stringReturn = value;

            if (Decimal.TryParse(value, NumberStyles.Number, null, out decimalValue))
                stringReturn = Convert.ToDecimal(value).ToString("#,##0.00");

            return stringReturn;
        }

        /// <summary>
        /// Controlla se il valore passato in input è in formato numerico e ne restituisce la sua conversione in formato valuta con 2 decimali ed il simbolo € alla fine.
        /// Se il controllo a numerico fallisce, viene restituita la stringa passata in input.
        /// </summary>
        /// <param name="value">Valore da formattare</param>
        /// <returns></returns>
        public static string FormatCurrencyWithSymbol(string value)
        {
            return string.Format("{0} €", FormatCurrency(value));
        }

        /// <summary>
        /// Controlla se il valore passato in input è in formato numerico e ne restituisce la sua conversione in formato valuta con 2 decimali.
        /// Se il controllo a numerico fallisce, viene restituita la stringa passata in input.
        /// </summary>
        /// <param name="value">Valore da formattare</param>
        /// <returns></returns>
        public static string FormatInteger(string value)
        {
            decimal decimalValue;
            string stringReturn = value;

            if (Decimal.TryParse(value, NumberStyles.Number, null, out decimalValue))
                stringReturn = Convert.ToDecimal(value).ToString("#,##0");

            return stringReturn;
        }

        /// <summary>
        /// Controlla se il valore passato in input è in formato numerico e ne restituisce la sua conversione in formato valuta con tot decimali a seconda del parametro int decimals.
        /// Se il controllo a numerico fallisce, viene restituita la stringa passata in input.
        /// </summary>
        /// <param name="value">Valore da formattare</param>
        /// <param name="decimals">numero di decimali</param>
        /// <returns></returns>
        public static string FormatDecimal(string value, int decimals)
        {
            decimal decimalValue;
            var stringReturn = value;
            var sdecimals = new string('0', decimals);

            if (!Decimal.TryParse(value, NumberStyles.Number, null, out decimalValue)) return stringReturn;
            var stringFormat = "{0:0." + String.Format("{0}", sdecimals) + "}";

            stringReturn = String.Format(stringFormat, decimalValue);
            return stringReturn;
        }
        /// <summary>
        /// Formatta il valore passato in input in una stringa formato percentuale con un solo decimale.
        /// </summary>
        /// <param name="value">Valore da formattare</param>
        /// <param name="decimals">Numero di decimali da restituire,1 o 2 unici valori ammessi.</param>
        /// <returns></returns>
        public static string FormatPercentage(decimal value, int decimals)
        {
            return (value / 100).ToString(string.Format("P{0}", decimals), new CultureInfo("it-IT"));
        }

        /// <summary>
        /// Formatta il valore passato in input in una stringa formato percentuale con un solo decimale.
        /// </summary>
        /// <param name="value">Valore da formattare</param>
        /// <param name="decimals">Numero di decimali da restituire,1 o 2 unici valori ammessi.</param>
        /// <returns></returns>
        public static string FormatPercentage(double value, int decimals)
        {
            decimal returnValue = Convert.ToDecimal(value);
            string returnString = FormatPercentage(returnValue, decimals);

            return returnString;
        }

        /// <summary>
        /// Formatta il valore passato in input in una stringa formato percentuale con un solo decimale.
        /// </summary>
        /// <param name="value">Valore da formattare</param>
        /// <param name="decimals">Numero di decimali da restituire,1 o 2 unici valori ammessi.</param>
        /// <returns></returns>
        public static string FormatPercentage(string value, int decimals)
        {
            decimal decimalValue;
            string stringReturn = string.Empty;

            if (Decimal.TryParse(value, NumberStyles.Number, null, out decimalValue))
                stringReturn = FormatPercentage(decimalValue, decimals);

            return stringReturn;
        }

        /// <summary>
        /// Formatta la data passata in input nel fomat DD MMMM YYYY dove MMMM è il nome per esteso del mese.
        /// </summary>
        /// <param name="date">Valore da formattare</param>
        /// <returns></returns>
        public static string FormatDateMonthName(DateTime date)
        {
            var strDay = date.Day.ToString();
            var strMonth = date.ToString("MMMM");
            var strYear = date.Year.ToString();

            var returnValue = strDay + " " + strMonth + " " + strYear;

            return returnValue;

        }
        public static string resultValueVariousString(string value)
        {
            decimal decimalValue;
            string stringReturn = string.Empty;

            if (Decimal.TryParse(value, NumberStyles.Number, null, out decimalValue))
                stringReturn = decimalValue.ToString();
            else
            {
                if (value.ToLower().Contains("n.c.") || value.ToLower().Contains("n.a.") || value.ToLower().Contains("n.d."))
                    stringReturn = value.ToLower();
                else
                    stringReturn = CapitalizeWords(value);
            }
            return stringReturn;
        }
        /// <summary>
        /// Formatta il valore passato in input in una stringa con la prima lettera maiuscolo.
        /// Se il valore in input è nullo o vuoto viene restituita una stringa vuota.
        /// </summary>
        /// <param name="value">Valore da formattare</param>
        /// <returns></returns>
        public static string CapitalizeWords(string value)
        {
            if (string.IsNullOrEmpty(value))
                return string.Empty;

            value = value.ToLower();

            var result = new StringBuilder(value);
            result[0] = char.ToUpper(result[0]);
            for (int i = 1; i < result.Length; ++i)
            {
                if (char.IsWhiteSpace(result[i - 1]) || result[i - 1].ToString() ==  "'")
                    result[i] = char.ToUpper(result[i]);
            }
            return result.ToString();
        }

        /// <summary>
        /// Sostituisce le variabili presenti nel testo (indicate con $/...../$ con il valore corrispondente
        /// </summary>
        /// <param name="value">testo da rimpiazzare</param>
        /// <param name="reportenvironment">ReportEnvironment</param>
        /// <returns></returns>
        public static string ReplaceVariables(string value, ReportEnvironment reportenvironment)
        {
            if (reportenvironment.PrivateBanker.CodiceRete == "F")
                value = value.Replace("$/Banca/$", "Fideuram");
            if (reportenvironment.PrivateBanker.CodiceRete == "S")
                value = value.Replace("$/Banca/$", "Sanpaolo Invest");

            return value;
        }

        /// <summary>
        /// Rimuove i tag html dal testo passato in input.
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string Strip_Tags(string value)
        {
            return Regex.Replace(value, @"<[^>]*>", String.Empty);
        }

        /// <summary>
        /// Ritorna il datatable passto in input con ordine righe invertito. 
        /// </summary>
        /// <param name="inputTable"></param>
        /// <returns></returns>
        public static DataTable ReverseDataTable(DataTable inputTable)
        {
            var outputTable = inputTable.Clone();

            for (int i = inputTable.Rows.Count - 1; i >= 0; i--)
            {
                outputTable.ImportRow(inputTable.Rows[i]);
            }

            return outputTable;
        }


        /// <summary>
        /// Funzione per arrotondare in eccesso il valore passato in input
        /// </summary>
        /// <param name="valore">Valore da arrotondare</param>        
        /// <returns>Restituisce un double</returns>
        public static double Round(double valore, bool secondMethod = false)
        {
            if (!secondMethod)
            {
                double tempValue;
                double results;
                int pesoArrotondamento;
                bool neg = false;

                if (valore == 0)
                    return 0;

                if (valore < 0)
                {
                    neg = true;
                    valore = Math.Abs(valore);
                }

                int ordineGrandezza = Convert.ToString(Math.Truncate(Math.Abs(valore))).Length;

                if (ordineGrandezza >= 2)
                {
                    pesoArrotondamento = Convert.ToInt32(Math.Pow(10.0, Convert.ToDouble(ordineGrandezza - 1)));
                    tempValue = valore / Convert.ToDouble(pesoArrotondamento);
                }
                else
                {
                    pesoArrotondamento = 1;
                    tempValue = valore;
                }


                if (tempValue == 1)
                    results = Math.Round(tempValue, MidpointRounding.AwayFromZero) * pesoArrotondamento;
                else
                    results = Math.Round((tempValue + 0.6) * pesoArrotondamento, MidpointRounding.AwayFromZero);

                if (neg)
                    return results * (-1);

                return results;
            }
            else
            {
                //int negative = valore < 0 ? -1 : 1;
                //string tmp = Math.Truncate(Math.Abs(valore)).ToString();
                //double multiplier = tmp.Length > 2 ? Math.Pow(10, tmp.Length - 2) : Double.Parse(tmp);
                //string twoFirstDigits = tmp.Length > 2 ? tmp.Substring(0,2) : tmp;
                //double result = multiplier * (int.Parse(twoFirstDigits) + 1) * negative;
                //return result;
                int negative = 1;
                if (valore < 0)
                {
                    negative *= -1;
                    valore *= -1;
                }

                if (valore < 1)
                {
                    return 0;
                }

                if (valore < 25)
                {
                    return Math.Truncate((valore + 1) * negative);
                }

                if (valore < 70)
                {
                    double valoreIncreased = valore * 105 / 100; // value * 115%
                    double valoreRest = valoreIncreased % 5;
                    double result = valoreIncreased - valoreRest;
                    if (result < valore)
                    {
                        result += 5;
                    }
                    return Math.Truncate(result * negative);
                }

                if (valore <= 100)
                {
                    double valoreIncreased = valore * 110 / 100; // value * 110%
                    double valoreRest = valoreIncreased % 10;
                    double result = valoreIncreased - valoreRest;
                    if (result < valore)
                    {
                        result += 10;
                    }
                    return Math.Truncate(result * negative);
                }
                else // valore > 100
                {
                    string tmp = Math.Truncate(Math.Abs(valore)).ToString();
                    double multiplier = tmp.Length > 2 ? Math.Pow(10, tmp.Length - 2) : Double.Parse(tmp);
                    string twoFirstDigits = tmp.Length > 2 ? tmp.Substring(0, 2) : tmp;
                    double result = multiplier * (int.Parse(twoFirstDigits) + 1) * negative;
                    return result;
                }
            }
        }

        /// <summary>
        /// Arrotonda in eccesso l'intero passato in input
        /// </summary>
        /// <param name="toRound"></param>
        /// <returns></returns>
        public static int RoundUp(int toRound)
        {
            return (10 - toRound % 10) + toRound;
        }

        /// <summary>
        /// Arrotonda in difetto l'intero passato in input
        /// </summary>
        /// <param name="toRound"></param>
        /// <returns></returns>
        public static int RoundDown(int toRound)
        {
            return toRound - toRound % 10;
        }


        /// <summary>
        /// Classe che centralizza e gestisce tutte le Decodifiche.
        /// </summary>
        public static class Decodifiche
        {
            /// <summary>
            /// Decodifica il valore stimato pro quota dell'immobile.
            /// -100 = "usufrutto".
            /// -0 = "-".
            /// 88 = piu' diritti
            /// </summary>
            /// <param name="valore"></param>
            /// <returns></returns>
            public static string DecodificaValoreStimatoProQuota(decimal valore)
            {

                if (valore == 0)
                    return "-";
                return valore == -100 ? "usufrutto" : FormatCurrency(valore.ToString());
            }

            public static string DecodificaQuotaProprieta(decimal valore)
            {
                if (valore == 0)
                    return "-";
                return valore == -100 ? "usufrutto" : FormatPercentage(valore, 2);
            }
        }



        /// <summary>
        /// Converte l'immagine in input in Stream
        /// </summary>
        /// <param name="image"></param>
        /// <param name="format"></param>
        /// <returns></returns>
        public static Stream ToStream(this Image image, ImageFormat format)
        {
            var stream = new MemoryStream();
            image.Save(stream, format);
            stream.Position = 0;
            return stream;
        }

        /// <summary>
        /// Recupera un' immagine a partire dall'URL passata in input
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public static Image GetImage(string url)
        {

            var request = (HttpWebRequest)WebRequest.Create(url);
            request.Timeout = 300000;
            var response = (HttpWebResponse)request.GetResponse();

            return Image.FromStream(response.GetResponseStream());
        }


        /// <summary>
        /// Serializza un oggetto in stringa formato XML
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string SerializeXml<T>(T obj)
        {
            var xsSubmit = new XmlSerializer(typeof(T));

            var sww = new StringWriter();
            var writer = XmlWriter.Create(sww);
            xsSubmit.Serialize(writer, obj);

            return sww.ToString();

        }

        /// <summary>
        /// Ritorna il Type della classe a partire da typeName passato.
        /// </summary>
        /// <param name="typeName"></param>
        /// <returns></returns>
        public static Type GetType(string typeName)
        {
            var type = Type.GetType(typeName);
            if (type != null) return type;
            foreach (var a in AppDomain.CurrentDomain.GetAssemblies())
            {
                type = a.GetType(typeName);
                if (type != null)
                    return type;
            }
            return null;
        }


    }

    /// <summary>
    /// Classe di utility per gli Enum.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public static class HelperEnum<T>
    {
        /// <summary>
        /// Ritorna la Description aggiunta all'Enum come tag DescriptionAttribute.
        /// </summary>
        /// <param name="enumValue"></param>
        /// <returns></returns>
        public static string GetDescription(T enumValue)
        {
            var fi = enumValue.GetType().GetField(enumValue.ToString());

            if (null == fi) return string.Empty;

            object[] attrs = fi.GetCustomAttributes(typeof(DescriptionAttribute), true);

            return attrs.Length > 0 ? ((DescriptionAttribute)attrs[0]).Description : string.Empty;
        }
    }

}
