// Created with MonoDevelop
//
//    QuickStep: Acquire, view and identify spectra 
//    Copyright (C) 2018 Thomas Klose & Torsten Schache, Hiperscan GmbH Dresden, Germany
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using Gtk;
using Glade;
using Hiperscan.Unix;
using Hiperscan.FileIO;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading;

namespace Hiperscan.Extensions.ApoIdent
{
    public class DataBackupDialog
    {
        
        private enum ExportMode
        {
            Backup,
            OnlyLogFiles,
            CustomerSupport,
        }

        [Widget] Gtk.FileChooserDialog backup_filechooserdialog = null;
        [Widget] Gtk.RadioButton backup_radiobutton             = null;
        [Widget] Gtk.RadioButton support_radiobutton            = null;
        [Widget] Gtk.Label day_label                            = null;
        [Widget] Gtk.SpinButton day_spinbutton                  = null;                    

        public DataBackupDialog(FinderWindow finder_window)
        {
			this.Config = finder_window.Config;
            this.Init(finder_window.GtkWindow);
         
            this.IdentServer = finder_window.IdentServerClient;
            this.Host = finder_window.host;

            this.backup_filechooserdialog.IconList = ApoIdentStock.FinderIcons;

            if (this.backup_filechooserdialog.Run() == (int)ResponseType.Accept)
                this.SaveData();
            
            this.backup_filechooserdialog.Destroy();
        }

        private void Init(Gtk.Window parent)
        {
            Glade.XML gui = new Glade.XML(null, "Backup.glade", "backup_filechooserdialog", "Hiperscan");
            gui.Autoconnect(this);

            this.backup_filechooserdialog.SetWmclass(Plugin.name.ToLower(), 
                                                   Plugin.name.ToLower());

            this.backup_filechooserdialog.TransientFor = parent;
           
            this.support_radiobutton.Group  = this.backup_radiobutton.Group;
            this.backup_radiobutton.Active = true;
            this.day_spinbutton.Value = -1;
            this.OnDataExportOptionToggled(this.backup_radiobutton, EventArgs.Empty);

            FileFilter filter = new FileFilter();
            filter.Name = Catalog.GetString("Archive");
            filter.AddPattern("*.zip");

            this.backup_filechooserdialog.AddFilter(filter);

            List<Gtk.ComboBox> boxes = new List<ComboBox>();
            this.FindComboBox(this.backup_filechooserdialog, boxes);
            boxes[0].Visible = false;

            this.backup_filechooserdialog.SetCurrentFolder(FilesAndDirs.DefaultDataExportDir);
            this.backup_filechooserdialog.DoOverwriteConfirmation = true;
        }

        private void FindComboBox(Gtk.Widget widget, List<ComboBox> boxes)
        {
            if (widget is Gtk.ComboBox)
            {
                boxes.Add(widget as Gtk.ComboBox);
                return;
            }

            Container container = widget as Gtk.Container;
            if (container == null)
                return;

            foreach (Widget child in container.Children)
                this.FindComboBox(child, boxes);
        }

        void OnDataExportOptionToggled(object sender, EventArgs e)
        {
            if (sender == this.support_radiobutton)
            {
                this.day_label.Sensitive        = true;
                this.day_spinbutton.Sensitive   = true;
                this.Mode                       = ExportMode.CustomerSupport;

                if ((int)this.day_spinbutton.Value == 0)
                    this.Mode = ExportMode.OnlyLogFiles;
                else
                    this.Mode = ExportMode.CustomerSupport;
            }
            else
            {
                this.day_label.Sensitive        = false;
                this.day_spinbutton.Sensitive   = false;              
				this.Mode = ExportMode.Backup;
            }

            this.SetFileName();
            this.SetSpinButtonToolTip();
        }

        private void OnDaySpinbuttonValueCjanged(object sender, EventArgs  e)
        {
            if (this.support_radiobutton.Active == true)
            {
                if((int)this.day_spinbutton.Value == 0)
                    this.Mode = ExportMode.OnlyLogFiles;
                else
                    this.Mode = ExportMode.CustomerSupport;
            }
            this.SetFileName();
            this.SetSpinButtonToolTip();
        }

        private void SetSpinButtonToolTip()
        {
            switch ((int)this.day_spinbutton.Value)
            {
                case -1:
                    this.day_spinbutton.TooltipText =
                            Catalog.GetString("All data will be exported.");
                    break;

                case 0:
                    this.day_spinbutton.TooltipText =
                            Catalog.GetString("Only the log files will be exported.");
                    break;

                default:
                    this.day_spinbutton.TooltipText = String.Format(
                            Catalog.GetPluralString("The data of the last day will be exported.",
                                                    "The data of the last {0} days will be exported.",
                                                    (int)this.day_spinbutton.Value),
                        (int)this.day_spinbutton.Value);
                    break;
            }
        }

        private void SetFileName()
        {
            string name = String.Empty;

            switch(this.Mode)
            {
                case ExportMode.Backup:
                    name = "apo_ident_backup_";
                    break;
               
                case ExportMode.OnlyLogFiles:
                    name = "apo_ident_log_files_";
                    break;

                case ExportMode.CustomerSupport:
                    name = "apo_ident_service_";
                    break;

                default:
                    break;
            }

            this.backup_filechooserdialog.CurrentName = name + DateTime.Now.ToString("yyyy-MM-dd_HH-mm") + ".zip";
        }

		private void ZipConfiguration(Zip zip)
		{
			zip.AddToArchiveCondition = this.ZipCompleteConfigCondition;
            zip.Add(FilesAndDirs.ConfigDir, Catalog.GetString(".Configurations"));
		}

        private void ZipLogData(Zip zip)
        {
			zip.AddToArchiveCondition = null;
            if (File.Exists(this.Config.ConfigFile) == true)
                zip.Add(this.Config.ConfigFile);

            if (File.Exists(this.Config.BackupConfigFile) == true)
                zip.Add(this.Config.BackupConfigFile);

            this.ZipLogFiles(zip, false);
            this.ZipLogFiles(zip, true);
        }

        private void ZipLogFiles(Zip zip, bool ident_server)
        {
            string tmp_dir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());

            try
            {               
                if (Directory.Exists(tmp_dir) == false)
                    Directory.CreateDirectory(tmp_dir);

                string zip_file = Path.Combine(tmp_dir, "data.zip");

                if (ident_server == false)
                {
                    LogWriter.Current.ZipLogFiles(zip_file, true);
                }
                    
                else
                {
                    ParameterizedThreadStart pts = new ParameterizedThreadStart(this.DoLoadIdentModulData);
                    Thread t = new Thread(pts);
                    t.Start(zip_file);
                    t.Join();
                }

                Zip.Decompress(zip_file, tmp_dir);
                System.Threading.Thread.Sleep(100); 

                foreach (string file in Directory.GetFiles(tmp_dir))
                {
                    if (Path.GetExtension(file).ToLower() == ".zip")
                        continue;
                    
                    zip.Add(file);
                }
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex);
            }
            finally
            {
                try
                {
                    Directory.Delete(tmp_dir, true);
                }
                catch(Exception){};
            }
        }

        private void ZipSpectraArchives(Zip zip)
        {
            Dictionary<string, string> spectra_folder = new Dictionary<string, string>();

            zip.AddToArchiveCondition = this.ZipSpectraCondition;

            foreach (Profile profile in this.Config.Profiles.Values)
                spectra_folder.Add(profile.Name, profile.Archive); 

            HashSet<string> compressed_items = new HashSet<string>();

            foreach(string profile_name in spectra_folder.Keys)
            {
                if (compressed_items.Add(spectra_folder[profile_name]) == false)
                    continue;

                string dir = spectra_folder[profile_name];
                if (Directory.Exists(dir) == false)
                    continue;

                string zip_target = "_" + FileIOHelper.ConvertToValidFilename(profile_name);
                
                foreach (string sub_dir in Directory.GetDirectories(dir))
                {
                    string sub_target = Path.Combine(zip_target, Path.GetFileName(sub_dir));
                    zip.Add(sub_dir, sub_target);
                }
                    

                foreach (string file in Directory.GetFiles(dir))
                {
                    string sub_target = Path.Combine(zip_target, Path.GetFileName(file));
                    zip.Add(file, sub_target);
                }
                   
            }
        }



        private void SaveData()
        {            
            try
            {
                this.backup_filechooserdialog.GdkWindow.Cursor = new Gdk.Cursor(Gdk.CursorType.Watch);
                this.backup_filechooserdialog.Sensitive = false;
                this.Host.ProcessEvents();

                Zip zip = new Zip(this.backup_filechooserdialog.Filename, true);

                switch(this.Mode)
                {
                    case ExportMode.Backup:
						this.ZipConfiguration(zip);
                        this.ZipSpectraArchives(zip);

                        break;
                  
                    case ExportMode.OnlyLogFiles:
                        this.ZipLogData(zip);
                        break;

                    case ExportMode.CustomerSupport:
                        this.ZipLogData(zip);
                        this.ZipSpectraArchives(zip);
                        break;

                    default:
                        break;
                }

                zip.Finish();
            }
            catch (Exception ex)
            {
                this.Host.ShowInfoMessage(this.backup_filechooserdialog, Catalog.GetString("Cannot export data: {0}"), ex.Message);
            }
            finally
            {
                this.backup_filechooserdialog.GdkWindow.Cursor = new Gdk.Cursor(Gdk.CursorType.Arrow);
                this.backup_filechooserdialog.Sensitive = true;
            }
        }

        private bool ZipSpectraCondition(string file)
        {
            bool is_time_stamp_file = true;

            if (Path.GetExtension(file).ToLower() != ".pdf" && 
                Path.GetExtension(file).ToLower() != ".csv" &&
                Path.GetExtension(file).ToLower() != ".xml")
                is_time_stamp_file = false;

            Match match = null;
            if (is_time_stamp_file == true)
            {
                Regex regex = new Regex("[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]_[0-9][0-9]-[0-9][0-9]-[0-9][0-9]");
                match = regex.Match(Path.GetFileName(file));
                is_time_stamp_file = match.Success;
            }

            if (is_time_stamp_file == true)
            { 
                int day = this.support_radiobutton.Active == true ? (int)this.day_spinbutton.Value : -1;
                TimeSpan span = DateTime.Now - DateTime.ParseExact(match.Value, "yyyy-MM-dd_HH-mm-ss", null);
                if (day > -1 && span.Days > day)
                    return false;
            }

            return true;
        }

        private bool ZipCompleteConfigCondition(string file)
        {
            if (Path.GetExtension(file).ToLower() == ".txt")
            {
                Console.WriteLine(file);
                return false;
            }

            return true;
        }

        private void DoLoadIdentModulData(object zip_file)
        {
            try
            {
                File.WriteAllBytes((string)zip_file, this.IdentServer.GetLogfile());
            }
            catch
            {
                
            }
        }

        private IdentServerClient IdentServer   {get; set;}
        private Configurations Config           {get; set;}    
        private ExportMode Mode                 {get; set;}
        private IHost Host                      {get; set;}
    }
}