using System;
using System.Collections.Generic;
using System.Text;
using SEILoader.SendEmail;
using log4net;

namespace SEILoader
{
    class TracingManager
    {
        private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        private static String dataInizioElaborazione;
        private static String dataFineElaborazione;
        private static int contatoreClientiCaricati = 0; //indipendentemente dall'esito ottenuto
        private static int contatoreClientiTotali = 0;
        private static SortedDictionary<String, int> errorMap = new SortedDictionary<string, int>();

        private static SortedDictionary<String, String> mappaCodici = new SortedDictionary<string, string>();
        
        public static void Inizializza(string id_elab, int numeroClienti)
        {
            dataInizioElaborazione = "" + DateTime.Now;
            contatoreClientiTotali = numeroClienti;
            log.Debug("Iniziato " + id_elab + " " + dataInizioElaborazione);
            mappaCodici.Add("-3", "richiesta cancellata");
            mappaCodici.Add("-2" , "richiesta da elaborare");
            mappaCodici.Add("-1"," richiesta in corso di elaborazione");
            mappaCodici.Add("0","elaborazione terminata con esito ok");
            mappaCodici.Add("1", "errore generico nell'elaborazione");
            mappaCodici.Add("2","versione simpb cambiata");
            mappaCodici.Add("3","errore nella chiamata ai ws simpb");
            mappaCodici.Add("4", "prodotto non trovato");
            mappaCodici.Add("5", "richiesta non elaborata per errore di connessione al ws");

        }

        /*
         * Metodo che conta quanti clienti sono stati processati, indipendentemente dall'esito del
         * caricamento.
         * */
        public static void addNewClienteInListaCaricati()
        {
            contatoreClientiCaricati += 1;
        }


        public static void TracciaStatisticheIntermedie(string id_elab)
        {
         
            if (contatoreClientiCaricati % 100 == 0)
            {
                string messaggioLog = getStatistiche4Log();                
                log.Info("statistiche intermedie esecuzione:\r\n" + messaggioLog);
                log.Info("numero clienti caricati "+contatoreClientiCaricati+ " di " + contatoreClientiTotali);
            }
            
        }

        
        public static void TracciaStatistiche(string id_elab,bool sendmail) {
            
            dataFineElaborazione = "" + DateTime.Now;
            log.Debug("TracciaStatistiche " + id_elab + " " + dataFineElaborazione);

            string messaggioEmail = getStatistiche4EMail();
            // Invio Email
            if (sendmail)
            {
                SendEMail sender = new SendEMail();
                string mailSender = Properties.Settings.Default.mailSender;
                string mailTo = Properties.Settings.Default.mailTo;
                sender.SendMailWithoutAttach(mailSender, mailTo, null, null, "SeiLoader Elaborazione del " + dataInizioElaborazione, messaggioEmail);
            }
            log.Info("statistiche esecuzione:\r\n" + getStatistiche4Log());
        }

        public static void TracciaErrore(CaricamentoClienteData cd, string msg, string id_elab)
        {
            double milliseconds = (DateTime.Now.Subtract(cd.dataInizio)).TotalMilliseconds;
            log.Warn("TracciaErrore("+contatoreClientiCaricati+ " di "+contatoreClientiTotali+") " + id_elab + " cliente("+cd.ToString()+") messaggio: "+ msg);


            increaseErrorInMap(msg);
        }

        

        public static string getStatistiche4EMail()
        {
            String messaggioEmail = "";

            int clientiKO = 0;
            int clientiOK = 0;
            foreach (String key in errorMap.Keys)            
            {
                int app = 0;
                errorMap.TryGetValue(key, out app);
                clientiKO += app;
                
            }
            clientiOK = contatoreClientiCaricati - clientiKO;
             

            messaggioEmail = "Data inizio elaborazione: " + dataInizioElaborazione + "</br>"
                            + " Clienti processati: " + contatoreClientiCaricati + "</br>"
                            + " Clienti con esito positivo: " + clientiOK + "</br>"
                            + " Clienti con esito negativo: " + clientiKO + "</br>"; 
                        
            foreach(String key in errorMap.Keys)            
            {
                int app=0;                
                errorMap.TryGetValue(key, out app);
                String descr = null;
                mappaCodici.TryGetValue(key, out descr);
                messaggioEmail += "<dir> clienti con codice errore " + key + "("+descr+"):" + app + "</dir>";
            }
            messaggioEmail += "Data fine elaborazione: " + dataFineElaborazione;

            
            return messaggioEmail;
        }

        public static string getStatistiche4Log()
        {
            String messaggioLog = "";

            int clientiKO = 0;
            int clientiOK = 0;
            foreach (String key in errorMap.Keys)
            {
                int app = 0;
                errorMap.TryGetValue(key, out app);
                clientiKO += app;

            }
            clientiOK = contatoreClientiCaricati - clientiKO;


            messaggioLog= "Data inizio elaborazione: " + dataInizioElaborazione + "\r\n"
                            + "\t Clienti processati: " + contatoreClientiCaricati + "\r\n"
                            + "\t Clienti con esito positivo: " + clientiOK + "\r\n"
                            + "\t Clienti con esito negativo: " + clientiKO + "\r\n";

            foreach (String key in errorMap.Keys)
            {
                int app = 0;
                errorMap.TryGetValue(key, out app);
                String descr = null;
                mappaCodici.TryGetValue(key, out descr);
                messaggioLog += "\t\t clienti con codice errore " + key + "("+descr+"):" + app + "\r\n";
            }
            messaggioLog += "Data fine elaborazione: " + dataFineElaborazione;


            return messaggioLog;
        }

        private static void increaseErrorInMap(String key)
        {
            int oldValue = 0;
            errorMap.TryGetValue(key, out oldValue);
            errorMap.Remove(key);
            errorMap.Add(key, oldValue + 1);
        }

        public static string getDataBaseException(DataBaseException ecc)
        {
            const string aCapo = "/r/n";
            string ritorno = "";
            ritorno += aCapo;
            ritorno += "  Informazioni Comando SQL:" + aCapo;
            ritorno += "    sql file name: " + ecc.SqlFileName + aCapo;
            ritorno += "    connection string: " + ecc.ConnectionStringWithoutCredentials + aCapo;
            //ritorno += "    command text: " + ecc.CommandText + aCapo;
            //controllo se ci sono i parametri
            if (ecc.Parameters != null)
            {
                foreach (Parametro parametro in ecc.Parameters)
                {
                    ritorno += aCapo;
                    ritorno += "     parametro: " + parametro.ParameterName + aCapo;
                    ritorno += "     dimensione: " + parametro.Size.ToString() + aCapo;
                    ritorno += "     direzione: " + parametro.Direction.ToString() + aCapo;
                    ritorno += "     tipo: " + parametro.DbType.ToString() + aCapo;

                    if (parametro.Value == null)
                        ritorno += "     valore: null" + aCapo;
                    else
                    {
                        string valoreParametro = "";
                        if (parametro.Size > 500)
                        {
                            valoreParametro = "     valore: null(sono visualizzati solo i primi 500 bytes): " + parametro.Value.ToString().Substring(0, 500);
                        }
                        else
                        {
                            valoreParametro = "     valore: " + parametro.Value.ToString();
                        }
                        ritorno += valoreParametro + aCapo;
                    }
                }
            }
            ritorno += aCapo;
            ritorno += "    tipo: DataBaseException" + aCapo;
            ritorno += "    descrizione: " + ecc.Eccezione.Message + aCapo;
            ritorno += "    sorgente: " + ecc.Eccezione.Source + aCapo;
            ritorno += "    traccia: " + FormattaErrore(ecc.StackTrace) + aCapo;

            return ritorno;

        }
        public static string getException(Exception ecc)
        {
            const string aCapo = "\r\n";
            string ritorno = "";
            ritorno += aCapo;
            ritorno += "    tipo: " + ecc.GetType().ToString() + aCapo;
            ritorno += "    descrizione: " + ecc.Message + aCapo;
            ritorno += "    sorgente: " + ecc.Source + aCapo;
            if (ecc.InnerException != null)
            {
                ritorno += "    descrizione Inner: " + ecc.InnerException.Message + aCapo;
                ritorno += "    sorgente Inner: " + ecc.InnerException.Source + aCapo;
            }
            ritorno += "    traccia: " + FormattaErrore(ecc.StackTrace) + aCapo;
            return ritorno;

        }
        private static string FormattaErrore(string errore)
        {
            const string aCapo = "\r\n";
            const string spazio = "      ";
            string separatore1 = " at ";
            string separatore2 = " in ";
            string separatore3 = ":line ";
            string erroreInterno = errore.Replace(separatore1, "@");
            string ritorno = aCapo;


            //nome metodo e tutto il resto
            string[] messaggioErrore = erroreInterno.Split('@');
            string messaggioSenzaSpazi;
            string[] messaggioInterno;

            foreach (string messaggio in messaggioErrore)
            {
                messaggioSenzaSpazi = messaggio.Trim();

                if (messaggioSenzaSpazi != "")
                {
                    messaggioSenzaSpazi = messaggioSenzaSpazi.Replace(separatore2, "@");
                    messaggioInterno = messaggioSenzaSpazi.Split('@');
                    if (messaggioInterno.GetUpperBound(0) == 1)
                    {
                        ritorno += spazio + "metodo: " + messaggioInterno[0] + aCapo;
                        string fileLineaSingolo = messaggioInterno[1].Replace(separatore3, "@");
                        string[] fileLinea = fileLineaSingolo.Split('@');
                        ritorno += spazio + "percorsoFile: " + fileLinea[0] + aCapo;
                        ritorno += spazio + "linea: " + fileLinea[1] + aCapo;
                        ritorno += aCapo;
                    }
                    else
                    {
                        ritorno += spazio + "metodo: " + messaggioInterno[0] + aCapo;
                    }
                }
            }

            return ritorno;
        }

        public static void terminaElaborazione(int esito) {

            int n_ok=0;
            int n_error=0;
            int n_cancel=0;
            foreach (String key in errorMap.Keys)
            {
                int app = 0;
                errorMap.TryGetValue(key, out app);
                n_error += app;

            }
            n_ok = contatoreClientiCaricati - n_error;
            n_cancel = contatoreClientiTotali - contatoreClientiCaricati;           

            DbManager.fineElaborazione( esito, n_ok, n_error, n_cancel);


        }
 
    }
}