using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace EstrazioneAnagrafica
{
    public abstract class ProgramLogic
    {

        //global variables, we love them!
        private System.ComponentModel.BackgroundWorker backgroundWorker1;
        private System.ComponentModel.BackgroundWorker backgroundWorker2;
        private bool done;

        //that's a mess ;)
        public ProgramLogic()
        {
           
            // 
            // backgroundWorker1
            // 
            backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
            this.backgroundWorker1.WorkerReportsProgress = true;
            this.backgroundWorker1.WorkerSupportsCancellation = true;
            this.backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);
            this.backgroundWorker1.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(this.backgroundWorker1_ProgressChanged);
            this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);
            // 
            // backgroundWorker2
            // 
            backgroundWorker2 = new System.ComponentModel.BackgroundWorker();
            this.backgroundWorker2.WorkerReportsProgress = true;
            this.backgroundWorker2.WorkerSupportsCancellation = true;
            this.backgroundWorker2.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker2_DoWork);
            this.backgroundWorker2.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(this.backgroundWorker2_ProgressChanged);
            this.backgroundWorker2.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker2_RunWorkerCompleted);
        }

        //running console application
        public void StartConsole(){

            try
            {
                done = false;//since we are using threads we need to keep our console alive
                backgroundWorker1.RunWorkerAsync();
                
                    while (!done)
                    {
                        Thread.Sleep(100); //dont kill the console please!
                    }

            }
            catch (Exception ex)
            {
                PushErrorStatus(ex.Message);
            }
        }

        //running windows forms application
        public void StartForm()
        {
            
            try
            {

                backgroundWorker1.RunWorkerAsync(); //no need to keep anything alive. Form never dies
                
                  
            }
            catch (Exception ex)
            {
                PushErrorStatus(ex.Message);
            }
        }
      
        #region notificators

        public abstract void PushStatus(string message); //those we use to show messages to the User. 
        public abstract void PushErrorStatus(string message); //implementation depedns on mode in which we run the software
        public abstract void PushSuccessStatus(string message);

        #endregion

        #region worker2

        private void backgroundWorker2_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
        {
            done = true;
            PushSuccessStatus(null);
            //System.Threading.Thread.Sleep(5000);//this codes make your application waiting for 5 seconds
            //sistemo i pulsanti e la label
            //TODO
            //lblAttendere.Visible = false;
            //button1.Enabled = true;

        }

        private void backgroundWorker2_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
        {
            if (e.ProgressPercentage == 10)
            {
                PushStatus("Rinomino il file sulla macchina target (Bolsena)......");
                //lblAttendere.Text = "Rinomino il file sulla macchina target (Bolsena)......";
                //lblAttendere.Visible = true;
            }
            else if (e.ProgressPercentage == 40)
            {
                PushStatus("Invio il file via FTP......");
                //lblAttendere.Text = "Invio il file via FTP......";
            }
            else if (e.ProgressPercentage == 100)
            {
                PushStatus("Invio terminato!!!");
                //lblAttendere.Text = "Invio terminato!!!";
            }
        }

        private void backgroundWorker2_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {

            try
            {
                //prima di inviare il nuovo flusso, rinomino il vecchio con la data attuale
                backgroundWorker2.ReportProgress(10);
                rinominaFileFtp();

                //lancio ftp verso la macchina condivisa \\bolsena
                backgroundWorker2.ReportProgress(40);
                inviaFlussoHostFTP();

                //fine
                backgroundWorker2.ReportProgress(100);
            }
            catch (Exception ex)
            {
                PushErrorStatus(ex.Message);
                done = true;
            }

        }

        #endregion
        //voodoo made by 2nd worker

        #region worker1

        private void backgroundWorker1_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
        {
            if (!done)
            {
                PushSuccessStatus("background worker1 job finished");
                backgroundWorker2.RunWorkerAsync();
            }
            else
                PushErrorStatus("Process cancelled due to the errors");
            //lblAttendere.Visible = false;
        }

        private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
        {
            if (e.ProgressPercentage == 20)
            {
                PushStatus( "Estraggo gli indirizzi dal db.......");
                //lblAttendere.Text = "Estraggo gli indirizzi dal db.......";
            }
            else if (e.ProgressPercentage == 40)
            {
                PushStatus( "Creo il file txt......");
                //lblAttendere.Text = "Creo il file txt......";
            }

            else if (e.ProgressPercentage == 80)
            {
                PushStatus("Creazione TXT terminata!!!");
                //lblAttendere.Text = "Creazione TXT terminata!!!";
            }
        }

        private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            try
            {
                Log.ScriviLog("Preparo estrazione indirizzi");
                //-----------------------------------------------------lancio la sp 'Estrazione_Indirizzi_CO'
                backgroundWorker1.ReportProgress(20);
                DataTable tabellaIndirizzi = LanciaEstrazioneIndirizzi();

                if (tabellaIndirizzi.Rows.Count == 0)
                {
                    //System.Windows.Forms.Application.Exit();
                    Log.ScriviLog("Fine procedura - Nessun indirizzo estratto");
                    throw new Exception("no data");
                }

                //prima di scrivere il txt rinomino l'eventuale esistente
                ControllaErinomina();

                //-----------------------------------------------------dalla tabella scrivo un txt
                backgroundWorker1.ReportProgress(40);
                CreaTxt(tabellaIndirizzi);


                //fine
                backgroundWorker1.ReportProgress(80);
            }
            catch (Exception ex)
            {
                PushErrorStatus(ex.Message);
                done = true;
            }
        }

        #endregion
        //voodoo made by 1st worker
        //then it will start worker2

        #region helpers 

        //se c'è un altro file txt target nella directory lo rinomino con la data del giorno (es: EstrazioneIndirizziCO_20151111.txt)
        private void ControllaErinomina()
        {
            PushStatus("Reading configuration");
            Log.ScriviLog("ControllaErinomina... Start ");
            string pathOut = UtilityManager.getAppSetting("Application_Folder");
            PushStatus("Application Folder " + pathOut);
            string estensioneFile = "." + ConfigurationManager.AppSettings["EstensioneFileHost"];
            PushStatus("Estensione File Host " + estensioneFile);
            string nomeFile = ConfigurationManager.AppSettings["NomeFileHost"];
            PushStatus("Nome File Host " + nomeFile);
            string ftpServerHost = ConfigurationManager.AppSettings["FTPServerHost"];
            PushStatus("FTP Server host " + ftpServerHost);

            string nomeFileOut = nomeFile + estensioneFile;
            string extensionFilter = nomeFileOut;

            string[] filePaths = Directory.GetFiles(pathOut, extensionFilter);
            if (filePaths.Length > 0)
            {
                try
                {
                    //il file è stato trovato, lo rinomino
                    string nuovoNomeFile = nomeFile + "_" + DateTime.Now.ToString("yyyyMMdd") + estensioneFile;
                    string oldPath = pathOut + "\\" + nomeFileOut;
                    string newPath = pathOut + "\\" + nuovoNomeFile;
                    System.IO.File.Move(oldPath, newPath);
                }
                catch (Exception e)
                {
                    PushErrorStatus(e.Message);
                    //probabilmente il file già esiste non faccio nulla;
                }
            }

            PushSuccessStatus("Reading configuration completed ");
            Log.ScriviLog("ControllaErinomina... Fine ");
        }

        private void CreaTxt(DataTable tabellaIndirizzi)
        {

            Log.ScriviLog("CreaTxt... Start ");
           
            string pathOut = UtilityManager.getAppSetting("Application_Folder");
          
            string estensioneFile = "." + ConfigurationManager.AppSettings["EstensioneFileHost"];

            string nomeFile = ConfigurationManager.AppSettings["NomeFileHost"];

            string nomeFileOut = nomeFile + estensioneFile;
            //StreamWriter outFile = new StreamWriter(pathOut + @"\EstrazioneIndirizziCO.txt");
            StreamWriter outFile = new StreamWriter(pathOut + @"\" + nomeFileOut);
            //scrivo il record iniziale
            outFile.WriteLine("FLUSSOANAGRAFICA" + DateTime.Now.ToString("yyyyMMdd"));
            //ciclo sulla tabella
            Anagrafica anagagrafica = new Anagrafica();
            foreach (DataRow dr in tabellaIndirizzi.Rows)
            {
                anagagrafica.codiceFiscale = Convert.ToString(dr["codiceFiscale"]);
                anagagrafica.codiceContratto = Convert.ToString(dr["contratto"]);
                anagagrafica.indirizzo = Convert.ToString(dr["indirizzo"]);
                anagagrafica.provincia = Convert.ToString(dr["provincia"]);
                anagagrafica.citta = Convert.ToString(dr["citta"]);
                anagagrafica.cap = Convert.ToString(dr["cap"]);
                anagagrafica.presso = Convert.ToString(dr["presso"]);
                anagagrafica.nazione = Convert.ToString(dr["nazione"]);
                anagagrafica.email = Convert.ToString(dr["email"]);

                string riga = anagagrafica.codiceFiscale + anagagrafica.codiceContratto + anagagrafica.indirizzo + anagagrafica.provincia +
                    anagagrafica.citta + anagagrafica.cap + anagagrafica.presso + anagagrafica.nazione + anagagrafica.email;

                outFile.WriteLine(riga);
            }


            outFile.WriteLine("ZZZZZZZZZZZZZZZZ99999999999");
            outFile.Close();

            Log.ScriviLog("CreaTxt... Fine ");

        }

        private DataTable LanciaEstrazioneIndirizzi()
        {
            Log.ScriviLog("LanciaEstrazioneIndirizzi... Start ");

            List<Parametro> parametri = new List<Parametro>();
            DataTable tabellaIndirizzi = DataAccess.ExecuteDataTableStoredProcedure(DBProvider.SqlServerStampeC6, "[dbo].[Estrazione_Indirizzi_CO]", parametri);
            Log.ScriviLog(tabellaIndirizzi.Rows.Count + " righe estratte");

            Log.ScriviLog("LanciaEstrazioneIndirizzi... Fine ");

            return tabellaIndirizzi;
        }

        private void rinominaFileFtp()
        {
            Log.ScriviLog("rinominaFileFtp... Start ");
            //preso qui: https://social.msdn.microsoft.com/Forums/en-US/8c541130-b571-4b1a-9117-ac610f3e8b34/ftpwebrequestrenameto-property?forum=netfxnetcom
            string estensioneFile = "." + ConfigurationManager.AppSettings["EstensioneFileHost"];
            string nomeFile = ConfigurationManager.AppSettings["NomeFileHost"];
            string nomeFileHost = nomeFile + estensioneFile;
            string FileUri = ConfigurationManager.AppSettings["FTPServerHost"] + nomeFileHost;

            //string FileUri = "ftp://someftp/somedir/test.tmp"; 

            FtpWebRequest ftp = (FtpWebRequest)WebRequest.Create(FileUri);

            ftp.Method = WebRequestMethods.Ftp.Rename;
            ftp.Credentials = new NetworkCredential(ConfigurationManager.AppSettings["FTPUserHost"], ConfigurationManager.AppSettings["FTPPasswordHost"]);
            //ftp.Credentials = new NetworkCredential(UserName, Password);

            //Don't include the path
            string nuovoNomeFile = nomeFile + "_" + DateTime.Now.ToString("yyyyMMdd") + estensioneFile;
            ftp.RenameTo = nuovoNomeFile;

            FtpWebResponse r = (FtpWebResponse)ftp.GetResponse();
            Log.ScriviLog("rinominaFileFtp... Fine response {0} " + r.StatusDescription);

        }

        private void inviaFlussoHostFTP()
        {
            Log.ScriviLog("inviaFlussoHostFTP... Start ");

            string estensioneFile = "." + ConfigurationManager.AppSettings["EstensioneFileHost"];
            string nomeFile = ConfigurationManager.AppSettings["NomeFileHost"];
            string nomeFileBackup = nomeFile + estensioneFile;
            //string pathFileBackup = ConfigurationManager.AppSettings["PathFileHostBackup"];
            //if (!pathFileBackup.EndsWith("\\"))
            //    pathFileBackup += "\\";

            //pathFileBackup += nomeFileBackup;

            string nomeFileHost = nomeFile + estensioneFile;

            //StringBuilder flussoHost = new StringBuilder();
            //flussoHost.Append(pathFileBackup.ToString() + "\r\n");

            string pathFileStream = ConfigurationManager.AppSettings["Application_Folder"] + "\\" + nomeFileHost;
            Log.ScriviLog("inviaFlussoHostFTP... invio il file" + pathFileStream);
            StreamReader sourceStream = new StreamReader(pathFileStream);
            //byte[] flussoInByte = StrToByteArray(flussoHost.ToString());
            byte[] flussoInByte = Encoding.UTF8.GetBytes(sourceStream.ReadToEnd());


            FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ConfigurationManager.AppSettings["FTPServerHost"] + nomeFileHost);
            request.Method = WebRequestMethods.Ftp.UploadFile;
            request.ContentLength = flussoInByte.Length;
            request.Credentials = new NetworkCredential(ConfigurationManager.AppSettings["FTPUserHost"], ConfigurationManager.AppSettings["FTPPasswordHost"]);

            byte[] buffer = new byte[4096];
            using (Stream writer = request.GetRequestStream())
            using (MemoryStream ms = new MemoryStream(flussoInByte))
            {
                int bytesRead = 0;
                int totalBytes = 0;

                do
                {
                    bytesRead = ms.Read(buffer, 0, buffer.Length);
                    if (bytesRead > 0)
                    {
                        writer.Write(buffer, 0, bytesRead);
                        totalBytes += bytesRead;
                    }
                } while (bytesRead > 0);
            }

            FtpWebResponse response = (FtpWebResponse)request.GetResponse();
            //V
            //LogFTP(response);
            //
            response.Close();

            //File.WriteAllBytes(pathFileBackup, flussoInByte);
            Log.ScriviLog("inviaFlussoHostFTP... Fine, status {0} " + response.StatusDescription);


        }

        #endregion
        //not helping the User tho, just for us
    }
}