using System;
using System.IO;
using System.Data;
using System.Text;
using System.Diagnostics;
using System.Collections.Generic;
using Amib.Threading;
using PDFGenerator.BusinessLayer;
using PipelineLib;
using ContrattoSei.Utilities;
using System.Threading;
using System.Configuration;
using System.Linq;
using PDFGenerator.Presentation.TemplateGenerator;

namespace GestorePDF.Logic
{
    public class ThreadManager
    {

        private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
        Thread[] pdfGenerationThreads;
        private void ProcessPdfDocuments(int volThreads)
        {

            // Daily FIX20180313: questa nuova pubblicazione generava record multipli su ReportManager e Gestione_PDF_FTP, a causa dell'introduzione della gestione
            //  multithread per la trimestrale in questa parte comune del software.
            //  Abbiamo risolto il problema condizionando il riciclo di riaccodamento solo alla reportistica trimestrale.
            //  Per quella giornaliera, basta un unico accodamento iniziale dei datathread.

            logger.Debug("ProcessPdfDocuments (int volThreads) {0}", volThreads.ToString());

            // Daily FIX20180313
            string sPeriodico = ConfigurationManager.AppSettings["Periodico"];
            // --Daily FIX20180313

            UtilityBusinessLayer ubl = new UtilityBusinessLayer();
            logger.Debug("ProcessPdfDocuments richiama getDataThreads(volThreads * 2 = {0}", (volThreads * 2).ToString());
            List<DataThread> _dataThreads = ubl.getDataThreads(volThreads * 2);
            //TemplateGeneratorFactory.LettoreNota = _dataThreads; // ***** Aggiunta Data Thread per Nota dinamica 23022022 Andrea Pino **** //
            logger.Debug("Creazione di un array di {0} threads", volThreads.ToString());
            pdfGenerationThreads = new Thread[volThreads];
            logger.Debug("Aggiunta della lista di {0} threads nella coda di thread", _dataThreads.Count.ToString());
            AddDataThreadsToQueue(_dataThreads);

            logger.Debug("Inizio ciclo for da 0 a {0}", (volThreads - 1).ToString());
            for (int i = 0; i < volThreads; i++)
            {
                logger.Debug("pdfGenerationThreads[{0}] = new Thread(MasterThread.ProcessDataInSingleThread) { IsBackground = true };", i.ToString());
                pdfGenerationThreads[i] = new Thread(MasterThread.ProcessDataInSingleThread) { IsBackground = true };
                logger.Debug("Sto per lanciare il thread id. {0}",pdfGenerationThreads[i].ManagedThreadId.ToString());
                pdfGenerationThreads[i].Start();
            }

            // Daily FIX20180313
            if (sPeriodico == "1")
            {
            // --Daily FIX20180313
                //logger.Debug("Inizio while (_dataThreads != null && _dataThreads.Count > 0)");
                while (_dataThreads != null && _dataThreads.Count > 0)
                {
                    logger.Debug("if (MasterThread.ThreadsQueue.Count < volThreads * 2)");
                    if (MasterThread.ThreadsQueue.Count < volThreads * 2)
                    {
                        logger.Debug("MasterThread.ThreadsQueue.Count = {0}; volThreads * 2 = {1}", MasterThread.ThreadsQueue.Count.ToString(), (volThreads * 2).ToString());
                        _dataThreads = ubl.getDataThreads(volThreads);
                        logger.Debug("AddDataThreadsToQueue(_dataThreads)");
                        AddDataThreadsToQueue(_dataThreads);
                    }
                    Thread.Sleep(500);
                }
            }

            while (true)
            {
                int threadsRunning = pdfGenerationThreads.Where(x => x.IsAlive).Count();
                if (threadsRunning == 0)
                {
                    return;
                }
                Thread.Sleep(500);
            }
        }

        private void AddDataThreadsToQueue(List<DataThread> dataThreads)
        {
            if (dataThreads != null)
            {
                foreach (DataThread t in dataThreads)
                {
                    //logger.Debug("Accodo datathread {0}", t.CodiceFiscale);
                    MasterThread.ThreadsQueue.Enqueue(t);
                }
            }
        }
        public int Main(int _volThreads = 0)
        {

            //logger.Debug("Main (int _volThreads = 0) {0}", _volThreads);

            Console.WriteLine("Start GestorePdf");
            string ambiente = UtilityManager.getAppSetting("ambiente");
            string funzione = "GESTORE PDF";
            //Invio il flusso giornaliero se il report � periodico e se � abilitato l'invio a host nell'appconfig
            bool inviaFlussoGiornaliero = (UtilityManager.getAppSetting("Periodico") == "0") && Convert.ToBoolean(UtilityManager.getAppSetting("INVIO_HOST")) ? true : false;
            int _maxActiveThreads = Convert.ToInt32(UtilityManager.getAppSetting("maxGestoreThreads"));
            int multiT = int.Parse(UtilityManager.getAppSetting("multiThreadingGestoreThreads"));
            int volThreads = Int32.Parse(ConfigurationManager.AppSettings["maxGestoreThreads"]);

            if (_volThreads > 0) volThreads = _volThreads;

            logger.Debug("volThreads vale {0}", volThreads);

            string sCulture = UtilityManager.getAppSetting("CultureToUse");

            try
            {
                System.Globalization.CultureInfo.CreateSpecificCulture(sCulture);
                //logger.Debug("Main richiama ProcessPdfDocuments(volThreads={0})", volThreads);
                ProcessPdfDocuments(volThreads);
                if (inviaFlussoGiornaliero)
                {
                    funzione = "SmartFTPThread.Program.GestioneFlussoGiornaliero";
                    #region iFeelGuilty
                    SmartFTPThread.Logic.FtpProcessSeparated.GestioneFlussoGiornaliero();
                    #endregion
                    inviaFlussoGiornaliero = false;
                }
                return 0;
            }
            catch (DataBaseException ex)
            {

                try
                {
                    logger.Error(ex.Message);
                    logger.Debug(ex.InnerException);
                    if (inviaFlussoGiornaliero)
                    {
                        funzione = "SmartFTPThread.Program.GestioneFlussoGiornaliero";
                        #region iFeelGuilty
                        SmartFTPThread.Logic.FtpProcessSeparated.GestioneFlussoGiornaliero();
                        #endregion iFeelGuilty
                        inviaFlussoGiornaliero = false;
                    }
                    funzione = "ScriviErroreNelDB";
                    ScriviErroreNelDB(-00002, "Errore nel Gestore PDF: " + getDataBaseException(ex), -292929, "Gestore PDF", "Gestore PDF");
                    funzione = "GESTORE PDF";
                }
                catch (Exception exc)
                {
                    funzione += "-ERRORE-" + exc.Message + "-ERRORE-";
                    try
                    {
                        logger.Error(funzione);
                    }
                    catch { }
                }
                try
                {
                    logger.Error(funzione);
                }
                catch { }
                return -1;
            }
            catch (Exception ex)
            {
                try
                {
                    logger.Error(ex.Message);
                    logger.Debug(ex.InnerException);
                }
                catch { }
                try
                {
                    if (inviaFlussoGiornaliero)
                    {
                        funzione = "SmartFTPThread.Program.GestioneFlussoGiornaliero";
                        #region iFeelGuilty
                        SmartFTPThread.Logic.FtpProcessSeparated.GestioneFlussoGiornaliero();
                        #endregion
                        inviaFlussoGiornaliero = false;
                    }
                    funzione = "ScriviErroreNelDB";
                    ScriviErroreNelDB(-00003, "Errore nel Gestore PDF: " + getException(ex), -292929, "Gestore PDF", "Gestore PDF");
                    funzione = "GESTORE PDF";
                }
                catch (Exception exc)
                {
                    funzione += "-ERRORE-" + exc.Message + "-ERRORE-";
                    try
                    {
                        logger.Error(funzione);
                    }
                    catch { }
                }
                try
                {
                    logger.Error(funzione);
                }
                catch { }
                return -1;
            }
        }

        private static void Start()
        {

        }



        private static string getDataBaseException(DataBaseException ecc)
        {
            const string aCapo = "#/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;

        }

        private static string getException(Exception ecc)
        {
            const string aCapo = "#/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 = "#/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;
        }

        private static void ScriviErroreNelDB(int codiceErrore, string descrizioErrore, int localeId, string nomePackage, string descrizionePackage)
        {
            int scriviErroreNelDB = int.Parse(UtilityManager.getAppSetting("scriviErroreNelDB"));
            if (scriviErroreNelDB == 1)
            {

                List<Parametro> parametri = new List<Parametro>();
                Parametro parametro = new Parametro();
                parametro.DbType = DbType.Int32;
                parametro.ParameterName = "codiceErrore";
                parametro.Value = codiceErrore;
                parametri.Add(parametro);

                parametro = new Parametro();
                parametro.DbType = DbType.String;
                parametro.ParameterName = "descrizioErrore";
                parametro.Value = descrizioErrore;
                parametri.Add(parametro);

                parametro = new Parametro();
                parametro.DbType = DbType.DateTime;
                parametro.ParameterName = "dataTime";
                parametro.Value = DateTime.Now;
                parametri.Add(parametro);

                parametro = new Parametro();
                parametro.DbType = DbType.String;
                parametro.ParameterName = "localeID";
                if (localeId == 0)
                    parametro.Value = System.DBNull.Value;
                else
                    parametro.Value = localeId;
                parametri.Add(parametro);

                parametro = new Parametro();
                parametro.DbType = DbType.String;
                parametro.ParameterName = "descrizionePackage";
                parametro.Value = descrizionePackage;
                parametri.Add(parametro);

                parametro = new Parametro();
                parametro.DbType = DbType.String;
                parametro.ParameterName = "nomePackage";
                parametro.Value = nomePackage;
                parametri.Add(parametro);

                DataAccess.ExecuteNonQueryStoredProcedure(DBProvider.SqlServerStampeC6, "[C6Mart].[UT_INSERT_ERROR]", parametri);

            }
        }

    }


}