using System;
using System.Text;
using System.IO;
using System.Configuration;
using System.Data;
using System.Diagnostics;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Data.SqlClient;
using Amib.Threading;
using System.Threading;
using PDFGenerator.BusinessLayer;
using PDFGenerator;

using ContrattoSei.Utilities;
using DataAccessLayer;

namespace GestorePDF.Logic {
    public class GestoreThread {

        private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();


        // public GestoreThread(DataThread dataThread)
        //{
        ///_tabelleSessione = tabelleSessione;
        //_dataThread = dataThread;
        //_tabelleSessione = new List<SessionStruct>();
        //       }

        public GestoreThread()
        {
           

        }
    

        public void DoWork(DataThread dataThread)
        {
            try { 
            logger.Debug("Constructing {0}:{1}:{2}:{3}", dataThread.CodiceFiscale, dataThread.Rete, dataThread.TipoContratto.ToString(), arrayToString(dataThread.ReportsType));
            }
            catch { }
            DataThread _dataThread = dataThread;
            List<SessionStruct> _tabelleSessione = new List<SessionStruct>();
            try
           {
                _dataThread.TipoReport = "DIAGNOSI";

               ReportType reportTypeDiagnosi = _dataThread.ReportsType.Find(delegate(ReportType r)
               {
                   return r.Descrizione.ToUpper() == "DIAGNOSI";
               });
               if (reportTypeDiagnosi != null)
               {
                   MakePDF(_tabelleSessione, _dataThread);
               }

               ReportType reportTypeMonitoraggio = _dataThread.ReportsType.Find(delegate(ReportType r)
               {
                   return r.Descrizione.ToUpper() == "MONITORAGGIO";
               });
               if (reportTypeMonitoraggio != null)
               {
                   _dataThread.TipoReport = "MONITORAGGIO";
                   MakePDF(_tabelleSessione, _dataThread);                
               }

                if (ConfigurationManager.AppSettings.Get("SavePDFtoDISK") == "2")
                {
                    using (DataAccessDE de = new DataAccessDE(DBProvider.SqlServerStampeC6))
                    {
                        //string sql = "update C6MartPeriodico.controllo_trimestrale set stato_report = 4 where cod_fiscale='" + _dataThread.CodiceFiscale + "' and rete = '"+ _dataThread.Rete +"'";
                        //de.ExecuteNonQuery(CommandType.Text, sql);
                        de.ExecuteNonQueryStoredProcedure(DBProvider.SqlServerStampeC6, "c6martPeriodico.UpdateStatoReport",
                            new List<Parametro>()
                            {
                            new Parametro() { ParameterName= "FiscalCode", Value = _dataThread.CodiceFiscale } ,
                            new Parametro() { ParameterName= "Rete", Value = _dataThread.Rete }
                            }
                            );
                    }
                }

                try { 
                logger.Debug("Constructing {0}:{1}:{2}:{3} finished", dataThread.CodiceFiscale, dataThread.Rete, dataThread.TipoContratto.ToString(), arrayToString(dataThread.ReportsType));
                }
                catch { } 
            }
            catch (Exception ex)
           {
                try { 
                logger.Debug("Constructing {0}:{1}:{2}:{3}:{4} does not finished due to the error", dataThread.CodiceFiscale, dataThread.Rete, dataThread.TipoContratto.ToString(), arrayToString(dataThread.ReportsType), ex.Message);                
                logger.Error(ex.Message);
                if (ex.InnerException != null)
                    logger.Error(ex.InnerException.Message);
                }
                catch { }
                //FixDocumentStatus(_dataThread.CodiceFiscale, _dataThread.Rete);
                string message = ex.Message;
               message += "Cliente: " + _dataThread.CodiceFiscale + "; PB_Rete: " + _dataThread.Rete + _dataThread.Agente;
               ScriviErroreNelDB(-00001, "Errore nel Gestore PDF: " + message + getException(ex), -292929, "Gestore PDF", "Gestore PDF");
               string reportType;
               if (_dataThread.TipoReport == TipoReport.DIAGNOSI.ToString())
               {
                   reportType = "D";
               }
               else
               {
                   reportType = "M";
                   string saveToDisk = UtilityManager.getAppSetting("SavePDFtoDISK");
                   string sAppoNomeFile;
                   string sSuffissoDiagnosi = "_DP.pdf";
                   string targetFolder = UtilityManager.getAppSetting("SavePDFtoDISK_Folder");
                   switch (saveToDisk)
                   {
                       case "1":
                               // Report Campione stampato su file sistem
                               sAppoNomeFile = targetFolder + _dataThread.NomeFileReport + sSuffissoDiagnosi;
                               if (File.Exists(sAppoNomeFile))
                                  File.Delete(sAppoNomeFile);
                               break;
                       case "2":
                                // stampa report gestione trimestrale
                               sAppoNomeFile = targetFolder + _dataThread.NomeFileReport + sSuffissoDiagnosi;
                               if (File.Exists(sAppoNomeFile))
                                   File.Delete(sAppoNomeFile);
                               break;
                       default :
                           break;                    
                   }            
               }
               InsertFaultCustomer(_dataThread.Rete, _dataThread.CodiceFiscale, reportType, ex.Message);
           }
        }


        public static bool FixDocumentStatus(string codiceFiscale, string rete)
        {

            bool res = false;
            try { 
            logger.Debug("fixing document status for {0}", codiceFiscale);
            }
            catch { }
            try
            {
                SqlParameter[,] p = new SqlParameter[1, 2];
                    p[0, 0] = new SqlParameter() { ParameterName = "CODE_FISCALE", Value = codiceFiscale };
                    p[0, 1] = new SqlParameter() { ParameterName = "RETE", Value = rete };
                
                DataAccess.ExecuteNonQueryStoredProcedure(DBProvider.SqlServerStampeC6, "test.GESTIONE_PDF_PREPARE_TEST_SAMPLE", p);
                res = true;
            }
            catch (Exception ex)
            {
                try { 
                logger.Error("fixing document status for {0} caused an error {1}", codiceFiscale, ex.Message);
                logger.Debug("fixing document status for {0} caused an error {1}", codiceFiscale, ex.Message);
                }
                catch { }
                string z = ex.Message;
                res = false;
            }
            return res;
        }


        private void MakePDF(List<SessionStruct> tabelleSessione, DataThread dataThread)
        {
                PDFGenerator.PDFGenerator generator = new PDFGenerator.PDFGenerator(tabelleSessione, dataThread);
                generator.Create();
        }

        private static string InizioElaborazionePDF()
        {// metodo solo quando scrive sul File System

            if (!((UtilityManager.getAppSetting("SavePDFtoDISK") == "0") && (UtilityManager.getAppSetting("Periodico") == "0")))
            {
                //inserisco la data inizio elaborazione
                Int16 iIDGestore;
                iIDGestore = CodificaQueryContratti(ConfigurationManager.AppSettings["QueryContratti"]);

                List<Parametro> parametri = new List<Parametro>();
                Parametro p = new Parametro();

                p.ParameterName = "TipoDataScrittura";
                p.DbType = DbType.Boolean;
                p.Value = 0;
                parametri.Add(p);

                p = new Parametro();
                p.ParameterName = "IDGestore";
                p.DbType = DbType.Int16;
                p.Value = iIDGestore;
                parametri.Add(p);

                IDataReader reader = DataAccess.ExecuteDataReaderStoredProcedure(DBProvider.SqlServerStampeC6, ConfigurationManager.AppSettings["SP_GESTIONE_UPDATE_ELABORAZIONE_PDF"], parametri);
                reader.Read();

                return reader["IDElaborazionePDF"].ToString();
            }
            return string.Empty;
        }

        private static void FineElaborazionePDF(string IDElaborazionePDF)
        {// metodo solo quando scrive sul File System

            if (!((UtilityManager.getAppSetting("SavePDFtoDISK") == "0") && (UtilityManager.getAppSetting("Periodico") == "0")))
            {
                if (!string.IsNullOrEmpty(IDElaborazionePDF))
                {
                    List<Parametro> parametri = new List<Parametro>();
                    Parametro p = new Parametro();

                    p.ParameterName = "TipoDataScrittura";
                    p.DbType = DbType.Boolean;
                    p.Value = 1;
                    parametri.Add(p);

                    p = new Parametro();
                    p.ParameterName = "IDElaborazionePDF";
                    p.DbType = DbType.Int32;
                    p.Value = Convert.ToInt32(IDElaborazionePDF);
                    parametri.Add(p);

                    DataAccess.ExecuteScalarStoredProcedure(DBProvider.SqlServerStampeC6, ConfigurationManager.AppSettings["SP_GESTIONE_UPDATE_ELABORAZIONE_PDF"], parametri);
                }
            }
        }

        private static Int16 CodificaQueryContratti(string sQuery)
        {
            Int16 iAppo = 0;
            switch (sQuery)
            {
                case "GESTIONE_SELECT_PDF_GETDATATHREADS":
                    iAppo = 1;
                    break;
                case "GESTIONE_SELECT_PDF_GETDATATHREADS_BIS":
                    iAppo = 2;
                    break;
                case "GESTIONE_SELECT_PDF_GETDATATHREADS_TER":
                    iAppo = 3;
                    break;
                case "GESTIONE_SELECT_PDF_GETDATATHREADS_QUATER":
                    iAppo = 4;
                    break;
                case "GESTIONE_SELECT_PDF_GETDATATHREADS_QUINTO":
                    iAppo = 5;
                    break;
                case "GESTIONE_SELECT_PDF_GETDATATHREADS_SESTO":
                    iAppo = 6;
                    break;
                case "GESTIONE_SELECT_PDF_GETDATATHREADS_SETTIMO":
                    iAppo = 7;
                    break;
                case "GESTIONE_SELECT_PDF_GETDATATHREADS_OTTAVO":
                    iAppo = 8;
                    break;
                case "GESTIONE_SELECT_PDF_GETDATATHREADS_NONO":
                    iAppo = 9;
                    break;
                case "GESTIONE_SELECT_PDF_GETDATATHREADS_DECIMO":
                    iAppo = 10;
                    break;
                case "GESTIONE_SELECT_PDF_GETDATATHREADS_UNDICESIMO":
                    iAppo = 11;
                    break;
                case "GESTIONE_SELECT_PDF_GETDATATHREADS_DODICESIMO":
                    iAppo = 12;
                    break;
                case "GESTIONE_SELECT_PDF_GETDATATHREADS_TREDICESIMO":
                    iAppo = 13;
                    break;
                case "GESTIONE_SELECT_PDF_GETDATATHREADS_QUATTORDICESIMO":
                    iAppo = 14;
                    break;
                case "GESTIONE_SELECT_PDF_GETDATATHREADS_QUINDICESIMO":
                    iAppo = 15;
                    break;
                default:
                    //test
                    iAppo = 0;
                    break;
            }
            return iAppo;
        }

        // Marian Zaki add those functions to handle insert the exceptions into the DB here for each customer and continue with others.
        #region Handle Exception

        private static void UnlockDocument(string rete, string clientID, string reportType)
        {

            int scriviErroreNelDB = int.Parse(ConfigurationManager.AppSettings["scriviErroreNelDB"]);
            if (scriviErroreNelDB == 1)
            {
                try
                {
                    List<Parametro> parametri = new List<Parametro>();
                    Parametro parametro = new Parametro();
                    parametro.DbType = DbType.String;
                    parametro.ParameterName = "rete";
                    parametro.Value = rete;
                    parametri.Add(parametro);

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

                    parametro = new Parametro();
                    parametro.DbType = DbType.String;
                    parametro.ParameterName = "tipoReport";
                    parametro.Value = reportType;
                    parametri.Add(parametro);
                   
                    DataAccess.ExecuteNonQueryStoredProcedure(DBProvider.SqlServerStampeC6, "[C6MartPeriodico].[GESTIONE_INSERT_CUSTOMER_ERROR]", parametri);


                }
                catch (Exception ex)
                {
                    DataBaseException dataBaseException = (DataBaseException)ex;
                    Console.WriteLine(dataBaseException.Message);
                }
            }
        }

        private static void InsertFaultCustomer(string rete, string clientID, string reportType, string errorDescription)
        {
            int scriviErroreNelDB = int.Parse(ConfigurationManager.AppSettings["scriviErroreNelDB"]);
            if (scriviErroreNelDB == 1)
            {
                try
                {
                    List<Parametro> parametri = new List<Parametro>();
                    Parametro parametro = new Parametro();
                    parametro.DbType = DbType.String;
                    parametro.ParameterName = "rete";
                    parametro.Value = rete;
                    parametri.Add(parametro);

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

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

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

                    DataAccess.ExecuteNonQueryStoredProcedure(DBProvider.SqlServerStampeC6, "[C6MartPeriodico].[GESTIONE_INSERT_CUSTOMER_ERROR]", parametri);


                }
                catch (Exception ex)
                {
                    DataBaseException dataBaseException = (DataBaseException)ex;
                    Console.WriteLine(dataBaseException.Message);
                }
            }
        }
        
        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(ConfigurationManager.AppSettings["scriviErroreNelDB"]);
            if (scriviErroreNelDB == 1)
            {
                try
                {
                    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);
                }
                catch (Exception ex)
                {
                    DataBaseException dataBaseException = (DataBaseException)ex;
                    Console.WriteLine(dataBaseException.Message);
                }
            }
        }

        /// <summary>
        ///  Marian Zaki: need to 
        ///  
        /// that it is needed with the Italian team. The reason of using it.
        /// </summary>
        /// <param name="ambiente"></param>
        /// <param name="cawTo_Bin"></param>
        /// <param name="argomentiCaw"></param>
        private static void StartTng(string ambiente, string cawTo_Bin, string argomentiCaw)
        {
            if (!ambiente.Equals("SVILUPPO"))
            {
                Process processTng = new Process();
                try
                {
                    processTng = Process.Start(cawTo_Bin, argomentiCaw);
                    while (!processTng.HasExited) ;
                }
                catch (Exception ex)
                {
                    throw new Exception("cawTo_Bin: Non riesco ad eseguire " + cawTo_Bin + " sulla macchina " + System.Environment.MachineName + ":" + ex.Message);
                }
                finally
                {
                    processTng.Close();
                    processTng.Dispose();
                }
            }
        }

        #endregion

        private string arrayToString(List<ReportType> array)
        {
            string res = "";
            foreach (var s in array)
                res = string.Concat(res,",", s.TipoReport);
            return res;
        }
    }

    
}