using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Ionic.Zip;
using System.Windows.Controls;
using System.Linq;

namespace co_zpracování
{
    public class Soubor : INotifyPropertyChanged
    {

        #region Test ProperyChanged
        private string _Testt;

        public string Testt
        {
            get { return _Testt; }
            set
            {
                if (value != _Testt)
                {
                    _Testt = value;
                    OnPropertyChanged();
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Raises this object's PropertyChanged event.
        /// </summary>
        /// <param name="propertyName">The property that has a new value.</param>
        protected void OnPropertyChanged([CallerMemberName]string propertyName = null)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null)
            {
                var e = new PropertyChangedEventArgs(propertyName);
                handler(this, e);
            }
        }
        #endregion

        public String AdrZdroj { get; set; } // Adresář zdroje se slo soubory
        public String AdrTemp { get; set; } // Adresář dočasný, kde se bude provádět zpracování
        public String AdrZprac { get; set; } // Adresář pro ukládání zpracovaných souborů
        public String AdrNezprac { get; set; } // Adresář pro ukládání nezpracovaných souborů, kdy došlo k chybě nebo přerušení uživatelem
        public String AdrSouboru { get; set; } // Při zpracování se zde ukládá adresa právě zpracovávaného souboru


        public Soubor()
        {
            AdrZdroj = null;
            AdrTemp = null;
            AdrZprac = null;
            AdrNezprac = null;
            AdrSouboru = "";
        }
        // Testovací konstruktor
        public Soubor(string AdrZdroj)
        {
            this.AdrZdroj = AdrZdroj;
            this.AdrTemp = null;
            this.AdrZprac = null;
            this.AdrNezprac = null;
            this.AdrSouboru = "";
        }
        public Soubor(string AdrZdroj, string AdrTemp, string AdrZprac, string AdrNezprac)
        {
            this.AdrZdroj = AdrZdroj;
            this.AdrTemp = AdrTemp;
            this.AdrZprac = AdrZprac;
            this.AdrNezprac = AdrNezprac;
            this.AdrSouboru = "";
        }

        #region HledejSoubor

        public string ProhledejZdroj()
        {
            string posledniNejnovejsi;
            String[] slogcrSoubory = Directory.GetFiles(AdrZdroj, "*.slogcr");
            if (slogcrSoubory.Length > 0)
            {
                posledniNejnovejsi = slogcrSoubory[0];
                foreach (string slogcr in slogcrSoubory)
                {
                    if (GetDatum(slogcr) > GetDatum(posledniNejnovejsi))
                        posledniNejnovejsi = slogcr;
                }
                return posledniNejnovejsi;
            }
            else
            {
                String[] slogSoubory = Directory.GetFiles(AdrZdroj, "*.slog");
                if (slogSoubory.Length > 0)
                {
                    posledniNejnovejsi = slogSoubory[0];
                    foreach (string slog in slogSoubory)
                    {
                        if (GetDatum(slog) > GetDatum(posledniNejnovejsi))
                            posledniNejnovejsi = slog;
                    }
                    return posledniNejnovejsi;
                }
                else
                {
                    String[] sloSoubory = Directory.GetFiles(AdrZdroj, "*.slo");
                    if (sloSoubory.Length > 0)
                    {
                        posledniNejnovejsi = sloSoubory[0];
                        foreach (string slo in sloSoubory)
                        {
                            if (GetDatum(slo) > GetDatum(posledniNejnovejsi))
                                posledniNejnovejsi = slo;
                        }
                        return posledniNejnovejsi;
                    }
                }
            }
            throw new FileNotFoundException("Nebyl nalezen žádný soubor ke zpracování.");
        }

        public string ProhledejNezprac()
        {
            string posledniNejnovejsi;
            String[] slogcrSoubory = Directory.GetFiles(AdrNezprac, "*.slogcr");
            if (slogcrSoubory.Length > 0)
            {
                posledniNejnovejsi = slogcrSoubory[0];
                foreach (string slogcr in slogcrSoubory)
                {
                    if (GetDatum(slogcr) > GetDatum(posledniNejnovejsi))
                        posledniNejnovejsi = slogcr;
                }
                return posledniNejnovejsi;
            }
            else
            {
                String[] slogSoubory = Directory.GetFiles(AdrNezprac, "*.slog");
                if (slogSoubory.Length > 0)
                {
                    posledniNejnovejsi = slogSoubory[0];
                    foreach (string slog in slogSoubory)
                    {
                        if (GetDatum(slog) > GetDatum(posledniNejnovejsi))
                            posledniNejnovejsi = slog;
                    }
                    return posledniNejnovejsi;
                }
                else
                {
                    String[] sloSoubory = Directory.GetFiles(AdrNezprac, "*.slo");
                    if (sloSoubory.Length > 0)
                    {
                        posledniNejnovejsi = sloSoubory[0];
                        foreach (string slo in sloSoubory)
                        {
                            if (GetDatum(slo) > GetDatum(posledniNejnovejsi))
                                posledniNejnovejsi = slo;
                        }
                        return posledniNejnovejsi;
                    }
                }
            }
            throw new FileNotFoundException("Nebyl nalezen žádný soubor ke zpracování.");
        }       
        /// <summary>
        /// Hlavní metoda, která vyhledává slo osubory podle priority slogcr > slog > slo a podle nejnovětšího data v nzávu souboru. Prohledává prioritně nezpracované (nedokončené) soubory, avšak ignoruje soubory v kterých se vyskytla chyba (tedy mají u sebe .slot soubory s textem chybové hlášky)
        /// </summary>
        /// <returns> Vrací celou adresu souboru </returns>
        public string HledejSoubor()
        {
            if(Directory.GetFiles(AdrNezprac).Length == 0)
            {
                return this.ProhledejZdroj();
            }
            else
            {
                if(Directory.GetFiles(AdrNezprac, "*.slot").Length == 0)
                {
                    return this.ProhledejNezprac();
                }
                else
                {
                    string posledni;
                    String[] slogcrSoubory = Directory.GetFiles(AdrNezprac, "*.slogcr");
                    if(slogcrSoubory.Length > 0)
                    {
                        posledni = slogcrSoubory[0];
                        foreach(string slogcr in slogcrSoubory)
                        {
                            if (GetDatum(slogcr) > GetDatum(posledni) && !File.Exists(Path.Combine(AdrNezprac, String.Format(Path.GetFileNameWithoutExtension(slogcr) + ".slot"))))
                                posledni = slogcr;
                        }
                        if(File.Exists(Path.Combine(AdrNezprac, String.Format(Path.GetFileNameWithoutExtension(posledni) + ".slot"))))
                        {
                            String[] slogSoubory = Directory.GetFiles(AdrNezprac, "*.slog");
                            if(slogSoubory.Length > 0)
                            {
                                posledni = slogSoubory[0];
                                foreach (string slog in slogSoubory)
                                {
                                    if (GetDatum(slog) > GetDatum(posledni) && !File.Exists(Path.Combine(AdrNezprac, String.Format(Path.GetFileNameWithoutExtension(slog) + ".slot"))))
                                        posledni = slog;
                                }
                                if (File.Exists(Path.Combine(AdrNezprac, String.Format(Path.GetFileNameWithoutExtension(posledni) + ".slot"))))
                                {
                                    String[] sloSoubory = Directory.GetFiles(AdrNezprac, "*.slo");
                                    if(sloSoubory.Length > 0)
                                    {
                                        posledni = sloSoubory[0];
                                        foreach(string slo in sloSoubory)
                                        {
                                            if (GetDatum(slo) > GetDatum(posledni) && !File.Exists(Path.Combine(AdrNezprac, String.Format(Path.GetFileNameWithoutExtension(slo) + ".slot"))))
                                                posledni = slo;
                                        }
                                        if (File.Exists(Path.Combine(AdrNezprac, String.Format(Path.GetFileNameWithoutExtension(posledni) + ".slot"))))
                                        {
                                            return this.ProhledejZdroj();
                                        }
                                        else
                                        {
                                            return posledni;
                                        }
                                    }
                                    else
                                    {
                                        return this.ProhledejZdroj();
                                    }
                                }
                                else
                                {
                                    return posledni;
                                }
                            }
                            else
                            {
                                String[] sloSoubory = Directory.GetFiles(AdrNezprac, "*.slo");
                                if (sloSoubory.Length > 0)
                                {
                                    posledni = sloSoubory[0];
                                    foreach (string slo in sloSoubory)
                                    {
                                        if (GetDatum(slo) > GetDatum(posledni) && !File.Exists(Path.Combine(AdrNezprac, String.Format(Path.GetFileNameWithoutExtension(slo) + ".slot"))))
                                            posledni = slo;
                                    }
                                    if (File.Exists(Path.Combine(AdrNezprac, String.Format(Path.GetFileNameWithoutExtension(posledni) + ".slot"))))
                                    {
                                        return this.ProhledejZdroj();
                                    }
                                    else
                                    {
                                        return posledni;
                                    }
                                }
                                else
                                {
                                    return this.ProhledejZdroj();
                                }
                            }
                        }
                        else
                        {
                            return posledni;
                        }
                    }
                    else
                    {
                        String[] slogSoubory = Directory.GetFiles(AdrNezprac, "*.slog");
                        if (slogSoubory.Length > 0)
                        {
                            posledni = slogSoubory[0];
                            foreach (string slog in slogSoubory)
                            {
                                if (GetDatum(slog) > GetDatum(posledni) && !File.Exists(Path.Combine(AdrNezprac, String.Format(Path.GetFileNameWithoutExtension(slog) + ".slot"))))
                                    posledni = slog;
                            }
                            if (File.Exists(Path.Combine(AdrNezprac, String.Format(Path.GetFileNameWithoutExtension(posledni) + ".slot"))))
                            {
                                String[] sloSoubory = Directory.GetFiles(AdrNezprac, "*.slo");
                                if (sloSoubory.Length > 0)
                                {
                                    posledni = sloSoubory[0];
                                    foreach (string slo in sloSoubory)
                                    {
                                        if (GetDatum(slo) > GetDatum(posledni) && !File.Exists(Path.Combine(AdrNezprac, String.Format(Path.GetFileNameWithoutExtension(slo) + ".slot"))))
                                            posledni = slo;
                                    }
                                    if (File.Exists(Path.Combine(AdrNezprac, String.Format(Path.GetFileNameWithoutExtension(posledni) + ".slot"))))
                                    {
                                        return this.ProhledejZdroj();
                                    }
                                    else
                                    {
                                        return posledni;
                                    }
                                }
                                else
                                {
                                    return this.ProhledejZdroj();
                                }
                            }
                            else
                            {
                                return posledni;
                            }
                        }
                        else
                        {
                            String[] sloSoubory = Directory.GetFiles(AdrNezprac, "*.slo");
                            if (sloSoubory.Length > 0)
                            {
                                posledni = sloSoubory[0];
                                foreach (string slo in sloSoubory)
                                {
                                    if (GetDatum(slo) > GetDatum(posledni) && !File.Exists(Path.Combine(AdrNezprac, String.Format(Path.GetFileNameWithoutExtension(slo) + ".slot"))))
                                        posledni = slo;
                                }
                                if (File.Exists(Path.Combine(AdrNezprac, String.Format(Path.GetFileNameWithoutExtension(posledni) + ".slot"))))
                                {
                                    return this.ProhledejZdroj();
                                }
                                else
                                {
                                    return posledni;
                                }
                            }
                            else
                            {
                                return this.ProhledejZdroj();
                            }
                        }
                    }
                //}
            }
            throw new FileNotFoundException("Nebyl nalezen žádný soubor ke zpracování.");
        }       

        #endregion

        #region GetSlozkyUlohy souboru
        /// <summary>
        /// Celý název souboru "{0}_{1}_{2}_{3}_{4}.{5}" rozloží na:
        /// [0] Název úlohy
        /// [1] Obdobi
        /// [2] Měsíč sloučení
        /// [3] Tazatelský soubor
        /// [4] Datum
        /// [5] Přípona
        /// </summary>
        /// <param name="soubor"></param>
        /// <returns></returns>
        public static string[] GetSlozkyUlohy(string soubor)
        {
            if (soubor.Contains("\\"))
                return GetSoubor(soubor).Split('_', '.');
            else
                return soubor.Split('_', '.');
        }

        public static string GetTazSoubor(string soubor)
        {
                return GetSlozkyUlohy(soubor)[3];
        }

        public static string GetUloha(string soubor)
        {
                return GetSlozkyUlohy(soubor)[0];
        }

        public static string GetObdobi(string soubor)
        {
            return GetSlozkyUlohy(soubor)[1];
        } 

        public static int GetRok(string soubor)
        {
            return Convert.ToInt32(GetSlozkyUlohy(soubor)[1].Substring(0, 4));
        }

        public static byte GetKvartal(string soubor)
        {
            return Convert.ToByte(GetSlozkyUlohy(soubor)[1].Substring(5, 1));
        }

        public static string GetSoubor(string adresář)
        {
            return Path.GetFileName(adresář);
        }
        
        public RoleEnum GetRole()
        {
            return GetRole(GetSlozkyUlohy(this.AdrZdroj)[5]);
        }
        public static RoleEnum GetRole(string soubor)
        {
            string pripona = GetSlozkyUlohy(soubor)[5];
            switch (pripona)
            {
                case "slo":
                    return RoleEnum.Tazatel;
                case "slog":
                    return RoleEnum.Garant;
                case "slogcr":
                    return RoleEnum.SprávceČR;
                default:
                    throw new Exception(string.Format("Přípona souboru {0} není definována.", pripona));
            }
        }    
        
        public static DateTime GetDatum(string soubor)
        {
            string DatumStr = GetSlozkyUlohy(soubor)[4];
            return DateTime.ParseExact(DatumStr, "yyyyMMddHHmmss", null);
        }    

        public static Kraje GetKraj(string soubor)
        {
            return (Kraje) Enum.Parse(typeof(Kraje), GetTazSoubor(soubor).Substring(0, 2), true);
        }
        #endregion

        #region Zip
        /// <summary>
        /// popis metody
        /// </summary>
        /// <param name="fileName">popis parametru</param>
        /// <param name="zipName"></param>
        public void Zip(string fileName, string zipName)
        {
            using(ZipFile zip = new ZipFile())
            {
                zip.AddFile(Path.Combine(AdrZdroj,fileName));
                zip.Save(Path.Combine(AdrZdroj,zipName));
            }
        }

        /// <summary>
        /// Rozzipování souboru, rozzipuje do stejného adresáře za použití názvu souboru bez přípony jako nového adresáře rozippovaného souboru
        /// </summary>
        /// <param name="zipName"></param>
        public void Unzip(string zipName)
        {
            using (ZipFile zf = ZipFile.Read(Path.Combine(AdrZdroj, zipName)))
            {
                string[] nazev = zipName.Split('.');
                zf.ExtractAll(Path.Combine(AdrZdroj, nazev[0]), ExtractExistingFileAction.OverwriteSilently);
            }
        }

        /// <summary>
        /// Rozzipování souboru za použití hesla, rozzipuje do stejného adresáře za použití názvu souboru bez přípony jako nového adresáře rozippovaného souboru
        /// </summary>
        /// <param name="zipName">Celá adresa zazipovaného souboru</param>
        /// <param name="password">Heslo</param>
        public void Unzip(string zipName, string password)
        {
            using (ZipFile zf = ZipFile.Read(Path.Combine(AdrZdroj, zipName)))
            {
                string[] nazev = zipName.Split('.');
                zf.Password = password;
                zf.ExtractAll(Path.Combine(AdrZdroj, nazev[0]), ExtractExistingFileAction.OverwriteSilently);
            }
        }

        /// <summary>
        /// Rozzipování souboru za použití hesla, rozzipuje do uvedené složky za použití jména souboru bez přípony pro novou složku rozzipovaného souboru
        /// </summary>
        /// <param name="zipName">Celá adresa zazipovaného souboru</param>
        /// <param name="fileAdress">Název nového adresáře, kam se soubor rozzipuje</param>
        /// <param name="password">Heslo</param>
        public void Unzip(string zipName, string fileAdress, string password)
        {
            if (!Directory.Exists(this.AdrTemp))
            {
                Directory.CreateDirectory(this.AdrTemp);
            }
            using (ZipFile zf = ZipFile.Read(Path.Combine(AdrZdroj, zipName)))
            {
                zf.Password = password;
                zf.ExtractAll(fileAdress, ExtractExistingFileAction.OverwriteSilently);
            }
        }
        #endregion

        #region Přesun Slo Souboru
        /// <summary>
        /// Metoda přesunující soubor v případě, že bylo zpracvání přerušeno uživatelem.
        /// </summary>
        /// <param name="AdresaSouboru"></param>
        /// <param name="Progress"></param>
        public void MoveFile(string AdresaSouboru, IProgress<Status> Progress)
        {
            new FileInfo(Path.Combine(this.AdrNezprac, Soubor.GetSoubor(AdresaSouboru))).Directory.Create();
            File.Move(AdresaSouboru, Path.Combine(this.AdrNezprac, Soubor.GetSoubor(AdresaSouboru)));
            Progress.Report(new Status(String.Format("{0} - přerušuji zpracování, přesouvám do {1}.", Soubor.GetSoubor(AdresaSouboru), this.AdrNezprac), "blue"));
        }
        /// <summary>
        /// Zarchivování souboru po úpsěšném zpracování souboru, smazání temp složky do které byl soubor rozzipován.
        /// </summary>
        /// <param name="AdresaSouboru"></param>
        /// <param name="Progress"></param>
        public void Dokonceno(string AdresaSouboru, IProgress<Status> Progress)
        {
            new FileInfo(Path.Combine(this.AdrZprac, Soubor.GetSlozkyUlohy(AdresaSouboru)[1], Soubor.GetUloha(AdresaSouboru), Soubor.GetSoubor(AdresaSouboru))).Directory.Create();
            File.Move(AdresaSouboru, Path.Combine(this.AdrZprac, Soubor.GetSlozkyUlohy(AdresaSouboru)[1], Soubor.GetUloha(AdresaSouboru), Soubor.GetSoubor(AdresaSouboru)));
            Progress.Report(new Status(String.Format("{0} - zpracování dokončeno, přesouvám do {1}.", Soubor.GetSoubor(AdresaSouboru), this.AdrZprac), "green"));
        }
        /// <summary>
        /// Přesunutí souboru do nezpracované složky a přidáním textového souboru .slot popisující přesnou hlášku, datum a čas chyby.
        /// </summary>
        /// <param name="AdresaSouboru"></param>
        /// <param name="Progress"></param>
        /// <param name="ex"></param>
        public void NedokončenoChyba(string AdresaSouboru, IProgress<Status> Progress, Exception ex)
        {
            new FileInfo(Path.Combine(this.AdrNezprac, Soubor.GetSoubor(AdresaSouboru))).Directory.Create();
            if (File.Exists(Path.Combine(this.AdrNezprac, Soubor.GetSoubor(AdresaSouboru))))
            {
                if (!(AdresaSouboru == Path.Combine(this.AdrNezprac, Soubor.GetSoubor(AdresaSouboru))) /* Mělo by být ochráněné jinde, ale pro jistotu -> */ && AdresaSouboru != "")
                {
                    File.Delete(Path.Combine(this.AdrNezprac, Soubor.GetSoubor(AdresaSouboru)));
                    File.Move(AdresaSouboru, Path.Combine(this.AdrNezprac, Soubor.GetSoubor(AdresaSouboru)));
                }            
            }
            else
            {
                if(!(AdresaSouboru == Path.Combine(this.AdrNezprac, Soubor.GetSoubor(AdresaSouboru))) /* Mělo by být ochráněné jinde, ale pro jistotu -> */ && AdresaSouboru != "")
                    File.Move(AdresaSouboru, Path.Combine(this.AdrNezprac, Soubor.GetSoubor(AdresaSouboru)));
            }                
            using(var tw = new StreamWriter(Path.Combine(this.AdrNezprac, string.Format(Path.GetFileNameWithoutExtension(AdresaSouboru)+".slot")), true))
            {
                tw.WriteLine(String.Format("({0}) nastala chyba: {1}", DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss"), ex.Message));
            }
            Progress.Report(new Status(String.Format("{0} - při zpracování došlo k chybě (" + ex.Message + "), přesouvám do {1}.", Soubor.GetSoubor(AdresaSouboru), this.AdrNezprac), "red"));
        }

        #endregion
    }
}
