// Created with MonoDevelop
//
//    QuickStep: Acquire, view and identify spectra 
//    Copyright (C) 2017 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 Hiperscan.Common;
using Hiperscan.Common.I18n;
using Hiperscan.Unix;
using Hiperscan.ApoIdentCore;
using Hiperscan.ApoIdentCore.Misc;
using System.Collections.Generic;
using Hiperscan.ApoIdentCommon.ApoConfig.Enums;
using Hiperscan.ApoIdentCommon.ApoConfig.ThirdPartyDataExchange;
using ProtocolType = Hiperscan.ApoIdentCommon.ApoConfig.ThirdPartyDataExchange.ProtocolType;
using Hiperscan.ApoIdentCommon.ApoConfig;
using Hiperscan.ApoIdentCommon.ApoConfig.Internationalization;

namespace Hiperscan.Extensions.ApoIdent
{
    public partial class Preferences
    {
        public static Preferences Start(Gtk.Window parent, AppControl control)
        {
            return new Preferences(parent, control);
        }

        private Preferences(Gtk.Window parent, AppControl control)
        {
            this.Control = control;

            this.Control.StashSettings();
            this.ParentWindow = parent;

            WaitWindow wait_window = new WaitWindow(this.ParentWindow,
                                            Catalog.GetString("Loading settings. Please wait..."),
                                             600);
            Glade.XML gui = new Glade.XML(null, "ApoIdent.Resources.Glade.FinderWindow.glade", "preferences_dialog", "Hiperscan");
            gui.Autoconnect(this);

            ApoIdent.ApoIdentApplication.SetWmcClassName(this.preferences_dialog);

            this.preferences_dialog.TransientFor = this.ParentWindow;

            this.InitializeDialog();
            this.preferences_dialog.Shown += this.OnDialogShown;


            wait_window.Destroy();

            this.preferences_dialog.IconList = ApoIdentStock.FinderIcons;

            bool check = false;

            GuiDesigner.SetSchema(this.preferences_dialog);

            do
            {
                this.preferences_dialog.Run();
                check = this.Check();
            }
            while (check == false);

            this.Close();
        }

        private void InitializeDialog()
        {
            this.preferences_dialog.Title = ApoIdentInfo.NAME + " " + Catalog.GetString("Preferences");
            this.InitProtocolManagmentComboBox();
            this.InitReportCountryComboBox();
            this.InitializeRegexEntries();
            this.InitLabelPrinter();
            this.SetInitialScrolledWindow();
            this.device_expander.Expanded = false;
            this.identmodule_expander.Expanded = false;
            this.quantifiermodule_expander.Expanded = false;
            this.Update(PreferencesUpdateStatus.InitWindow);
        }

        private void InitProtocolManagmentComboBox()
        {
            ListStore store = new ListStore(typeof(string));
            CellRendererText text = new CellRendererText();

            this.report_management_combo.Clear();
            this.report_management_combo.PackStart(text, false);
            this.report_management_combo.SetAttributes(text, "text", 0);
            this.report_management_combo.Model = store;

            foreach (ProtocolType protocol_type in Enum.GetValues(typeof(ProtocolType)))
                this.report_management_combo.AppendText(StringEnum.GetStringValue(protocol_type));
        }

        private void InitReportCountryComboBox()
        {
            ListStore store = new ListStore(typeof(string));
            CellRendererText text = new CellRendererText();

            this.country_combobox.Clear();
            this.country_combobox.PackStart(text, false);
            this.country_combobox.SetAttributes(text, "text", 0);
            this.country_combobox.Model = store;

            this.CountryEntries.Clear();
            List<string> report_countries = I18n.GetRelevantReportCountryNames();


            for (int i = 0; i < report_countries.Count; i++)
                this.CountryEntries.Add(report_countries[i], i);

            foreach (string value in this.CountryEntries.Keys)
                this.country_combobox.AppendText(value);
        }


        private void AddChangeEvents()
        {
            this.config_combo.Changed += this.OnConfigComboChanged;

            this.customer_number_regexentry.Entry.Changed += this.OnCustomerNumberEntryChanged;
            this.name_info_regexentry.Entry.Changed += this.OnCompanyEntryChanged;
            this.street_info_regexentry.Entry.Changed += this.OnStreetEntryChanged;
            this.town_info_regexentry.Entry.Changed += this.OnTownEntryChanged;
            this.archive_entry.Changed += this.OnArchiveEntryChanged;

            this.default_filename_start_combo.Changed += this.OnDefaultFileNameStartComboChanged;
            this.report_management_combo.Changed += this.OnReportManagementComboChanged;
            this.country_combobox.Changed += this.OnCountryComboBoxChanged;
            this.bak_checkbutton.Toggled += this.OnBAKCheckbittonToggled;
            this.show_difference_checkbutton.Toggled += this.OnShowDifferenceCheckbittonToggled;
            this.mandatory_checkbutton.Toggled += this.OnMandatoryCheckButtonToggled;
            this.print_validation_checkbutton.Toggled += this.OnPrintValidationCheckButtonToggled;
            this.certification_control_checkbutton.Toggled += this.CertificationControlToggled;


            this.AddDeviceEvents();
            this.AddIdentModuleEvents();
            this.AddQuantifierModuleEvents();
            this.AddSoftwareEvents();

            this.label_printer_combo.Changed += this.OnLabelPrinterComboChanged;
            this.page_size_combo.Changed += this.OnPageSizeComboChanged;

            this.label_orientation_combo.Changed += this.OnPrinterValueChanged;
            this.label_width_spin.Changed += this.OnPrinterValueChanged;
            this.label_height_spin.Changed += this.OnPrinterValueChanged;
            this.label_x_offset_spin.Changed += this.OnPrinterValueChanged;
            this.label_y_offset_spin.Changed += this.OnPrinterValueChanged;
            this.label_scale_factor_spin.Changed += this.OnPrinterValueChanged;
        }

        private void RemoveChangedEvents()
        {
            this.config_combo.Changed -= this.OnConfigComboChanged;

            this.customer_number_regexentry.Entry.Changed -= this.OnCustomerNumberEntryChanged;
            this.name_info_regexentry.Entry.Changed -= this.OnCompanyEntryChanged;
            this.street_info_regexentry.Entry.Changed -= this.OnStreetEntryChanged;
            this.town_info_regexentry.Entry.Changed -= this.OnTownEntryChanged;
            this.archive_entry.Changed -= this.OnArchiveEntryChanged;

            this.default_filename_start_combo.Changed -= this.OnDefaultFileNameStartComboChanged;
            this.report_management_combo.Changed -= this.OnReportManagementComboChanged;
            this.country_combobox.Changed -= this.OnCountryComboBoxChanged;
            this.bak_checkbutton.Toggled -= this.OnBAKCheckbittonToggled;
            this.show_difference_checkbutton.Toggled -= this.OnShowDifferenceCheckbittonToggled;
            this.mandatory_checkbutton.Toggled -= this.OnMandatoryCheckButtonToggled;
            this.print_validation_checkbutton.Toggled -= this.OnPrintValidationCheckButtonToggled;
            this.certification_control_checkbutton.Toggled -= this.CertificationControlToggled;

            this.RemoveDeviceEvents();
            this.RemoveIdentModuleEvents();
            this.RemoveQuantifierModuleEvents();
            this.RemoveSoftwareEvents();

            this.label_printer_combo.Changed -= this.OnLabelPrinterComboChanged;
            this.page_size_combo.Changed -= this.OnPageSizeComboChanged;

            this.label_orientation_combo.Changed -= this.OnPrinterValueChanged;
            this.label_width_spin.Changed -= this.OnPrinterValueChanged;
            this.label_height_spin.Changed -= this.OnPrinterValueChanged;
            this.label_x_offset_spin.Changed -= this.OnPrinterValueChanged;
            this.label_y_offset_spin.Changed -= this.OnPrinterValueChanged;
            this.label_scale_factor_spin.Changed -= this.OnPrinterValueChanged;
        }


        #region config managment section

        private void FillConfigCombo()
        {
            ListStore store = new ListStore(typeof(string));

            if (this.config_combo.Model == null)
            {
                CellRendererText text = new CellRendererText();

                this.config_combo.Clear();
                this.config_combo.PackStart(text, false);
                this.config_combo.SetAttributes(text, "text", 0);
                this.config_combo.Model = store;
            }
            else
            {
                store = (ListStore) this.config_combo.Model;
            }

            store.Clear();
            foreach (string profile_name in this.Control.ProfileManager.AllProfiles.Keys)
                this.config_combo.AppendText(profile_name);
        }


        private void OnConfigComboChanged(object o, EventArgs e)
        {
            this.Control.ProfileManager.CurrentProfile = this.Control.ProfileManager.AllProfiles[this.config_combo.ActiveText];
            this.Update(PreferencesUpdateStatus.UserConfigComboChanged);
        }

        private void UpdateConfigComboSection()
        {
            if (this.Control.ProfileManager.CurrentProfile == null)
            {
                this.config_combo.Sensitive = false;
                this.add_config_button.Sensitive = true;
                this.remove_config_button.Sensitive = false;
                this.rename_config_button.Sensitive = false;
            }
            else
            {
                this.config_combo.Sensitive = true;
                this.add_config_button.Sensitive = true;
                this.remove_config_button.Sensitive = this.Control.ProfileManager.AllProfiles.Count > 1;
                this.rename_config_button.Sensitive = this.Control.ProfileManager.IsDemoVersion == false;

                this.config_combo.Active = this.Control.ProfileManager.CurrentIndex(this.Control.ProfileManager.CurrentProfile);
            }
        }

        #endregion config managment section


        #region profile settings

        private void OnCustomerNumberEntryChanged(object sender, EventArgs e)
        {
            this.Control.ProfileManager.CurrentProfile.CustomerNumber = StringHelper.CleanUserInputString(this.customer_number_regexentry.Entry.Text);
        }

        private void OnCompanyEntryChanged(object sender, EventArgs e)
        {
            this.Control.ProfileManager.CurrentProfile.Company = StringHelper.CleanUserInputString(this.name_info_regexentry.Entry.Text);
        }

        private void OnStreetEntryChanged(object sender, EventArgs e)
        {
            this.Control.ProfileManager.CurrentProfile.Street = StringHelper.CleanUserInputString(this.street_info_regexentry.Entry.Text);
        }

        private void OnTownEntryChanged(object sender, EventArgs e)
        {
            this.Control.ProfileManager.CurrentProfile.Town = StringHelper.CleanUserInputString(this.town_info_regexentry.Entry.Text);
        }

        private void OnDefaultFileNameStartComboChanged(object sender, EventArgs e)
        {
            this.Control.ProfileManager.CurrentProfile.FileNameStart = (FilenameStartTypes)this.default_filename_start_combo.Active;
        }

        private void OnArchiveEntryChanged(object sender, EventArgs e)
        {
            this.Control.ProfileManager.CurrentProfile.Archive = this.archive_entry.Text;
        }

        private void OnArchiveEntryMouseOver(object sender, EnterNotifyEventArgs e)
        {
            this.archive_entry.TooltipText = this.archive_entry.Text;
        }

        private void OnArchiveButtonClicked(object sender, EventArgs e)
        {
            using (Gtk.FileChooserDialog chooser = new Gtk.FileChooserDialog(
                Catalog.GetString("Select Archive Directory"),
                this.preferences_dialog,
                FileChooserAction.SelectFolder))
            {
                chooser.AddButton(Gtk.Stock.Apply, Gtk.ResponseType.Ok);
                chooser.AddButton(Gtk.Stock.Cancel, Gtk.ResponseType.Cancel);
                chooser.DoOverwriteConfirmation = true;
                chooser.SetCurrentFolder(this.archive_entry.Text);

                chooser.Modal = true;
                chooser.IconList = ApoIdentStock.FinderIcons;

                if ((ResponseType)chooser.Run() == ResponseType.Ok)
                    this.archive_entry.Text = chooser.Filename;

                chooser.Destroy();
            }
        }


        private void OnReportManagementComboChanged(object sender, EventArgs e)
        {
            this.Control.ProfileManager.CurrentProfile.ExchangeData = DataExchange.Create((ProtocolType)this.report_management_combo.Active);
            this.Control.ProfileManager.CurrentProfile.AdditionalTest.IsThirdPartyProtocol = 
                this.Control.ProfileManager.CurrentProfile.ExchangeData.ProtocolType != ProtocolType.ApoIdent;
            this.Update(PreferencesUpdateStatus.ReportMangementChanged);
        }

        private void OnCountryComboBoxChanged(object sender, EventArgs e)
        {
            string text = this.country_combobox.ActiveText;
            ReportCountryTypes country_type = (ReportCountryTypes)text.xParseToI18nEnum(typeof(ReportCountryTypes));
            this.Control.ProfileManager.CurrentProfile.ReportCountry = country_type;
            this.Update(PreferencesUpdateStatus.ReportCountryChanged);
        }

        private void OnBAKCheckbittonToggled(object sender, EventArgs e)
        {
            this.Control.ProfileManager.CurrentProfile.BakMarking.IsActive = this.bak_checkbutton.Active;
        }

        private void OnShowDifferenceCheckbittonToggled(object sender, EventArgs e)
        {
            this.Control.ProfileManager.CurrentProfile.ShowDifference = this.show_difference_checkbutton.Active;
        }

        private void OnMandatoryCheckButtonToggled(object sender, EventArgs e)
        {
            this.Control.ProfileManager.CurrentProfile.AdditionalTest.IsMandatoryForComplementaryTest = this.mandatory_checkbutton.Active;
        }

        private void OnPrintValidationCheckButtonToggled(object sender, EventArgs e)
        {
            this.Control.ProfileManager.CurrentProfile.PrintValidationWhitinProtocol = this.print_validation_checkbutton.Active;
        }

        private void CertificationControlToggled(object sender, EventArgs e)
        {
            this.Control.ProfileManager.CurrentProfile.CertificationControl = this.certification_control_checkbutton.Active;
        }

        private void OnReportManagementButtonClicked(object sender, EventArgs e)
        {
            try
            {
                new DataExchangeSettingsDialog(this.Control.ProfileManager.CurrentProfile.ExchangeData, this.preferences_dialog);
            }
            catch (Exception ex)
            {
                string message = String.Format(Catalog.GetString("Cannot open settings dialogue for data exchange options: {0}"), ex.Message);
                Plugin.host.ShowInfoMessage(this.preferences_dialog, message);
            }
        }

        private void UpdateProfileSection()
        {
            this.customer_number_regexentry.Entry.Text = String.Empty;
            this.name_info_regexentry.Entry.Text = String.Empty;
            this.street_info_regexentry.Entry.Text = String.Empty;
            this.town_info_regexentry.Entry.Text = String.Empty;
            this.default_filename_start_combo.Active = (int)FilenameStartTypes.SubstanceName;
            this.archive_entry.Text = String.Empty;
            this.report_management_combo.Active = (int)ProtocolType.ApoIdent;
            this.show_difference_checkbutton.Active = false;
            this.mandatory_checkbutton.Active = false;
            this.archive_entry.Text = String.Empty;
            this.bak_checkbutton.Active = false;

            string default_country = I18n.GetReportCountryName(I18n.GetDefaultReportCountry());
            this.country_combobox.Active = this.CountryEntries[default_country];

            if (this.Control.ProfileManager.CurrentProfile != null)
            {
                this.customer_number_regexentry.Entry.Text = this.Control.ProfileManager.CurrentProfile.CustomerNumber;
                this.name_info_regexentry.Entry.Text = this.Control.ProfileManager.CurrentProfile.Company;
                this.street_info_regexentry.Entry.Text = this.Control.ProfileManager.CurrentProfile.Street;
                this.town_info_regexentry.Entry.Text = this.Control.ProfileManager.CurrentProfile.Town;

                this.default_filename_start_combo.Active = (int)this.Control.ProfileManager.CurrentProfile.FileNameStart;
                this.archive_entry.Text = this.Control.ProfileManager.CurrentProfile.Archive;
                this.report_management_combo.Active = (int)this.Control.ProfileManager.CurrentProfile.ExchangeData.ProtocolType;

                string current_country = I18n.GetReportCountryName(this.Control.ProfileManager.CurrentProfile.ReportCountry);
                this.country_combobox.Active = this.CountryEntries[current_country];
               
                this.bak_checkbutton.Active = this.Control.ProfileManager.CurrentProfile.BakMarking.IsActive;
                this.show_difference_checkbutton.Active = this.Control.ProfileManager.CurrentProfile.ShowDifference;
                this.mandatory_checkbutton.Active = this.Control.ProfileManager.CurrentProfile.AdditionalTest.IsMandatoryForComplementaryTest;
                this.print_validation_checkbutton.Active = this.Control.ProfileManager.CurrentProfile.PrintValidationWhitinProtocol;
                this.certification_control_checkbutton.Active = this.Control.ProfileManager.CurrentProfile.CertificationControl;
                this.archive_entry.Text = this.Control.ProfileManager.CurrentProfile.Archive;

                bool bak_marking_is_usable = this.Control.ProfileManager.CurrentProfile.IsBakMarkingUsable;
                bak_marking_is_usable = bak_marking_is_usable && this.Control.GlobalStates.IsOnlyQuantifierModuleAvailable ==false;
                this.bak_label.Sensitive = bak_marking_is_usable;
                this.bak_checkbutton.Sensitive = bak_marking_is_usable;
                this.show_bak_linkbutton.Sensitive = bak_marking_is_usable;

                bool mandatory_is_usable = this.Control.ProfileManager.CurrentProfile.ExchangeData.ProtocolType == ProtocolType.ApoIdent;
                this.mandatory_label.Sensitive = mandatory_is_usable;
                this.mandatory_checkbutton.Sensitive = mandatory_is_usable;
                this.show_deactive_mandatory_linkbutton.Sensitive = mandatory_is_usable;

                bool print_validation_is_usable = this.Control.ProfileManager.CurrentProfile.ReportCountry != ReportCountryTypes.GreatBritain;
                this.print_validation_label.Sensitive = print_validation_is_usable;
                this.print_validation_checkbutton.Sensitive = print_validation_is_usable;
                this.show_print_validation_linkbutton.Sensitive = print_validation_is_usable;


                bool certification_control_is_usable = this.Control.ProfileManager.CurrentProfile.ReportCountry == ReportCountryTypes.Germany &&
                                                            this.Control.ProfileManager.CurrentProfile.ExchangeData.ProtocolType == ProtocolType.ApoIdent;
                                                     
                this.certification_control_label.Sensitive = certification_control_is_usable;
                this.certification_control_checkbutton.Sensitive = certification_control_is_usable;
                this.show_certification_control_linkbutton.Sensitive = certification_control_is_usable;

                this.profile_table.Sensitive = true;
            }
            else
            {
                this.profile_table.Sensitive = false;
            }

            bool visible = this.Control.Locale == CatalogLocale.LocaleType.de_DE;

            this.report_management_combo.Visible = visible;
            this.report_management_label.Visible = visible;

            this.certification_control_label.Visible = visible;
            this.certification_control_checkbutton.Visible = visible;
            this.show_certification_control_linkbutton.Visible = visible;

            visible = visible && this.Control.GlobalStates.IsOnlyQuantifierModuleAvailable == false;

            this.bak_label.Visible = visible;
            this.bak_checkbutton.Visible = visible;
            this.show_bak_linkbutton.Visible = visible;

            this.print_validation_label.Visible = visible;
            this.print_validation_checkbutton.Visible = visible;
            this.show_print_validation_linkbutton.Visible = visible;

            this.mandatory_label.Visible = visible;
            this.mandatory_checkbutton.Visible = visible;
            this.show_deactive_mandatory_linkbutton.Visible = visible;

            visible = this.Control.GlobalStates.IsOnlyQuantifierModuleAvailable == false;

            this.show_difference_label.Visible = visible;
            this.show_difference_checkbutton.Visible = visible;
            this.show_difference_linkbutton.Visible = visible;
        }

        private void UpdateReportManagementSettingsButton()
        {
            if (this.Control.ProfileManager.CurrentProfile == null ||
                this.Control.ProfileManager.CurrentProfile.ExchangeData.ProtocolType == ProtocolType.ApoIdent ||
                CatalogLocale.Language != "de")
            {
                this.report_management_button.Visible = false;
            }
            else
            {
                this.report_management_button.Visible = true;
            }
        }

        #endregion profile settings

        private bool Check()
        {
            if (this.Control.IdentModuleSettings.ModuleLocation == RemoteModuleLocationTypes.Custom &&
                String.IsNullOrEmpty(this.Control.IdentModuleSettings.Url) == true)
            {
                Plugin.host.ShowInfoMessage(this.preferences_dialog,
                    Catalog.GetString("Please enter an url in the field 'IP Address' in IdentModule settings."));
                this.close_button.Sensitive = true;
                return false;
            }

            if (this.Control.IdentModuleSettings.ModuleLocation == RemoteModuleLocationTypes.Custom &&
                this.Control.IdentModuleSettings.TcpPort < 0)
            {
                Plugin.host.ShowInfoMessage(this.preferences_dialog,
                    Catalog.GetString("Please enter a valid port number in the field 'Tcp port' in IdentModule settings."));
                this.close_button.Sensitive = true;
                return false;
            }

            if (this.Control.QuantifierModuleSettings.ModuleLocation == RemoteModuleLocationTypes.Custom &&
                String.IsNullOrEmpty(this.Control.QuantifierModuleSettings.Url) == true)
            {
                Plugin.host.ShowInfoMessage(this.preferences_dialog,
                    Catalog.GetString("Please enter an URL in the field 'IP Address' in QuantifierModule settings."));
                this.close_button.Sensitive = true;
                return false;
            }

            if (this.Control.QuantifierModuleSettings.ModuleLocation == RemoteModuleLocationTypes.Custom &&
                this.Control.QuantifierModuleSettings.TcpPort < 0)
            {
                Plugin.host.ShowInfoMessage(this.preferences_dialog,
                    Catalog.GetString("Please enter a valid port number in the field 'Tcp port' in QuantifierModule settings."));
                this.close_button.Sensitive = true;
                return false;
            }

            if (this.Control.DeviceSettings.SearchMode == DeviceSearchModes.Custom &&
                String.IsNullOrEmpty(this.Control.DeviceSettings.Url) == true)
            {
                Plugin.host.ShowInfoMessage(this.preferences_dialog,
                    Catalog.GetString("Please enter an url in the field 'IP Address'in device settings."));
                this.close_button.Sensitive = true;
                return false;
            }

            if (this.Control.DeviceSettings.SearchMode == DeviceSearchModes.Custom &&
                this.Control.DeviceSettings.TcpPort < 0)
            {
                Plugin.host.ShowInfoMessage(this.preferences_dialog,
                    Catalog.GetString("Please enter a valid port number in the field 'Tcp port' in device settings."));
                this.close_button.Sensitive = true;
                return false;
            }

            return true;
        }

        private void Close()
        {
            this.close_button.Sensitive = false;

            System.Threading.Tasks.Task.Run(() =>
            {
                Application.Invoke((sender, e2) =>
                {
                    Preferences.CheckForDemoVersion(this.preferences_dialog, this.Control.ProfileManager);
                    this.CheckDirectoryEntriesForDoubleEntries();

                    this.preferences_dialog.Destroy();
                    this.Control.UnstashSettings();
                    this.Control.MeasuringManager.Finder.UpdateReferencingDir(this.Control.ProfileManager.CurrentProfile);
                    this.Control.SaveConfig();
                });
            });
        }

        private Dictionary<string, int> CountryEntries { get; set; } = new Dictionary<string, int>();
        private Gtk.Window ParentWindow { get; set; }
        private AppControl Control { get; set; }
        private int MainThread { get; set; } = System.Threading.Thread.CurrentThread.ManagedThreadId;
    }
}
