// 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 System.IO;
using Gtk;
using System.Collections.Generic;
using System.Reflection;

using Hiperscan.Unix;
using Hiperscan.I18n;
using Hiperscan.Common;


namespace Hiperscan.Extensions.ApoIdent
{
    
	public partial class Preferences
	{
		
		public Preferences(FinderWindow window)
		{
			this.FinderWindow = window;
			this.Config = window.Config;

            this.Config.Stash();

            foreach (Profile profile in this.Config.Profiles.Values)
                profile.OldArchive = profile.Archive.TrimEnd('\\', '/');

            WaitWindow wait = new WaitWindow(this.FinderWindow.GtkWindow,
                                            Catalog.GetString("Loading settings. Please wait..."), 600);

			this.AcquisitionMessageShown = false;

			Glade.XML gui = new Glade.XML(null, "ApoIdent.Resources.Glade.FinderWindow.glade", "preferences_dialog", "Hiperscan");
			gui.Autoconnect(this);

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

			this.preferences_dialog.TransientFor = window.GtkWindow;
           
			this.InitializeDialog();

			this.preferences_dialog.Shown += this.OnDialogShown;
			this.is_running = true;
            wait.Destroy();

            this.preferences_dialog.IconList = ApoIdentStock.FinderIcons;
            this.preferences_dialog.IconName = Stock.Preferences;
			do
			{
				ResponseType answer = (ResponseType) this.preferences_dialog.Run();
				if (answer == ResponseType.DeleteEvent)
				{
					this.OnCloseButtonClicked(null, null);
				}
			}
			while(this.is_running == true);         
		}

		private void InitializeDialog()
		{			
			this.preferences_dialog.Title = Plugin.name + " " + Catalog.GetString("Preferences");
			this.InitProtocolManagmentComboBox();
			this.InitializeHollyWidgets();
            this.InitLabelPrinter();
			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)))
			{
				//Deactivate following two lines for activating rezepturdoku
				if (protocol_type == ProtocolType.RezepturDoku)
					continue;

				this.report_management_combo.AppendText(StringEnum.GetStringValue(protocol_type));	
			}
		}

        private void InitLabelPrinter()
        {
            this.label_width_spin.FocusOutEvent += this.OnPrinterValueChanged;
            this.label_height_spin.FocusOutEvent += this.OnPrinterValueChanged;
            this.label_x_offset_spin.FocusOutEvent += this.OnPrinterValueChanged;
            this.label_y_offset_spin.FocusOutEvent += this.OnPrinterValueChanged;
            this.label_scale_factor_spin.FocusOutEvent += this.OnPrinterValueChanged;

            int index = this.PrinterNames.IndexOf(this.Config.PrinterSettings.PrinterName);
            if (index == -1)
                this.Config.PrinterSettings.HasPrinter = false;

            this.CurrentPaperSizes = LabelPrinter.GetPaperSizes(this.Config.PrinterSettings.PrinterName);
        }

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

			this.customer_number_hregexentry.Entry.Changed += this.OnCustomerNumberEntryChanged;
			this.name_info_hregexentry.Entry.Changed	   += this.OnCompanyEntryChanged;
			this.street_info_hregexentry.Entry.Changed	   += this.OnStreetEntryChanged;
			this.town_info_hregexentry.Entry.Changed	   += this.OnTownEntryChanged;
           
			this.default_filename_start_combo.Changed 	+= this.OnDefaultFileNameStartComboChanged;
			this.report_management_combo.Changed		+= this.OnReportManagementComboChanged;
			this.country_combobox.Changed				+= this.OnCountryComboBoxChanged;
			this.show_difference_checkbutton.Toggled	+= this.OnShowDifferenceCheckbittonToggled;

			this.identification_combo.Changed			+= this.OnIdentificationComboChanged;
			this.server_entry.Changed					+= this.OnServerEntryChanged;
			this.port_entry.Changed						+= this.OnPortEntryChanged;

			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_hregexentry.Entry.Changed -= this.OnCustomerNumberEntryChanged;
			this.name_info_hregexentry.Entry.Changed	   -= this.OnCompanyEntryChanged;
			this.street_info_hregexentry.Entry.Changed	   -= this.OnStreetEntryChanged;
			this.town_info_hregexentry.Entry.Changed	   -= this.OnTownEntryChanged;

			this.default_filename_start_combo.Changed 	-= this.OnDefaultFileNameStartComboChanged;
			this.report_management_combo.Changed		-= this.OnReportManagementComboChanged;
			this.country_combobox.Changed				-= this.OnCountryComboBoxChanged;
			this.show_difference_checkbutton.Toggled	-= this.OnShowDifferenceCheckbittonToggled;

			this.identification_combo.Changed			-= this.OnIdentificationComboChanged;
			this.server_entry.Changed					-= this.OnServerEntryChanged;
			this.port_entry.Changed						-= this.OnPortEntryChanged;

			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));
			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;
			foreach (string profile_name in this.Config.Profiles.Keys)
				this.config_combo.AppendText(profile_name);
		}


		private void OnConfigComboChanged(object o, EventArgs e)
		{
			this.Config.Profiles.Current = this.Config.Profiles[this.config_combo.ActiveText];
			this.Update(PreferencesUpdateStatus.UserConfigComboChanged);
		}
      
		private void UpdateConfigComboSection()
		{
			if (this.Config.Profiles.Current == 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.Config.Profiles.Count > 1;
				this.rename_config_button.Sensitive	= this.Config.Profiles.IsDemoVersion == false;

				this.config_combo.Active			= this.Config.Profiles.CurrentIndex(this.Config.Profiles.Current);
			}
		}

		#endregion config managment section


		#region profile settings

		private void OnCustomerNumberEntryChanged(object sender, EventArgs e)
		{
			this.Config.Profiles.Current.CustomerNumber = StringHelper.CleanUserInputString(this.customer_number_hregexentry.Text);          
		}

		private void OnCompanyEntryChanged(object sender, EventArgs e)
		{
			this.Config.Profiles.Current.Company = StringHelper.CleanUserInputString(this.name_info_hregexentry.Text);          
		}

		private void OnStreetEntryChanged(object sender, EventArgs e)
		{
			this.Config.Profiles.Current.Street = StringHelper.CleanUserInputString(this.street_info_hregexentry.Text);
		}

		private void OnTownEntryChanged(object sender, EventArgs e)
		{
			this.Config.Profiles.Current.Town = StringHelper.CleanUserInputString(this.town_info_hregexentry.Text);
		}

		private void OnDefaultFileNameStartComboChanged(object sender, EventArgs e)
		{			
			this.Config.Profiles.Current.FileNameStart = (FilenameStartTypes) this.default_filename_start_combo.Active;
		}

        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)
                {
                    string file = chooser.Filename;

                    if (this.Config.Profiles.Current.OldArchive != file.TrimEnd('\\', '/'))
                    {
                        string message = Catalog.GetString("Changing the archive directory causes information about previous " +
                                                           "measurements to become unavailable in the software. This applies " +
                                                           "in particular to measurement protocols, texts relating " +
                                                           "to additional substance tests and entries in the substance managment.");

                        MessageDialog mdlg = new MessageDialog(this.preferences_dialog,
                                                               DialogFlags.Modal,
                                                               Gtk.MessageType.Warning,
                                                               ButtonsType.OkCancel,
                                                               message);

                        mdlg.IconList = ApoIdentStock.FinderIcons;

                        ResponseType answer = (ResponseType)mdlg.Run();
                        mdlg.Destroy();
                        if (answer == ResponseType.Ok)
                        {
                            this.Config.Profiles.Current.Archive = file;
                            this.Config.Profiles.Current.ArchiveCreated = false;
                            this.Config.Profiles.Current.AdditionalCompletionEntries = null;
                            this.Config.Profiles.Current.SubstanceExtension = null;
                            this.archive_entry.Text = file;
                        }
                    }
                }

                chooser.Destroy();
            }
		}

      
		private void OnReportManagementComboChanged(object sender, EventArgs e)
		{
			this.Config.Profiles.Current.ExchangeData = DataExchange.Create((ProtocolType) this.report_management_combo.Active);          
			this.Update(PreferencesUpdateStatus.ReportMangementChanged);
		}

		private void OnCountryComboBoxChanged(object sender, EventArgs e)
		{
			this.Config.Profiles.Current.ReportCountry = (ReportCountryType) this.country_combobox.Active;
		}

		private void OnShowDifferenceCheckbittonToggled(object sender, EventArgs e)
		{
			this.Config.Profiles.Current.ShowDifference = this.show_difference_checkbutton.Active;
		}

		private void OnReportManagementButtonClicked(object sender, EventArgs e)
		{
			try
			{
                new DataExchangeSettingsDialog(this.Config.Profiles.Current.ExchangeData, this.preferences_dialog);
			}
			catch(Exception ex)
			{
				string message = String.Format(Catalog.GetString("Cannot open directory exchange settings dialog: {0}"), ex.Message );
				Plugin.host.ShowInfoMessage(this.preferences_dialog, message);
			}
		}

		private void UpdateProfileSection()
		{
			this.customer_number_hregexentry.Text       = String.Empty;
			this.name_info_hregexentry.Text 			= String.Empty;
			this.street_info_hregexentry.Text			= String.Empty;
			this.town_info_hregexentry.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.archive_entry.Text                     = String.Empty;

            switch (Locale.Language)
			{

			case "de":
                switch (Locale.Country)
				{

				case "at":
					this.country_combobox.Active = (int)ReportCountryType.Austria;
					break;

				case "ch":
					this.country_combobox.Active = (int)ReportCountryType.Switzerland;
					break;

				default:
					this.country_combobox.Active = (int)ReportCountryType.Germany;
					break;

				}
				break;

			default:
				this.country_combobox.Active = (int)ReportCountryType.GreatBritain;
				break;

			}

			if (this.Config.Profiles.Current != null)
			{
				this.customer_number_hregexentry.Text = this.Config.Profiles.Current.CustomerNumber;
				this.name_info_hregexentry.Text 	  = this.Config.Profiles.Current.Company;
				this.street_info_hregexentry.Text	  = this.Config.Profiles.Current.Street;
				this.town_info_hregexentry.Text		  = this.Config.Profiles.Current.Town;

				this.default_filename_start_combo.Active = (int) this.Config.Profiles.Current.FileNameStart;
				this.archive_entry.Text = this.Config.Profiles.Current.Archive;               
				this.report_management_combo.Active		= (int)this.Config.Profiles.Current.ExchangeData.ProtocolType;
				this.country_combobox.Active			= (int)this.Config.Profiles.Current.ReportCountry;
				this.show_difference_checkbutton.Active	= this.Config.Profiles.Current.ShowDifference;
				this.archive_entry.Text = this.Config.Profiles.Current.Archive;

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

            if (Locale.Language == "de")
			{
				this.report_management_combo.Visible = true;
				this.report_management_label.Visible = true;
			}
			else
			{
				this.report_management_combo.Visible = false;
				this.report_management_label.Visible = false;
			}
		}

		private void UpdateReportManagementSettingsButton()
		{
			if (this.Config.Profiles.Current == null || 
			    this.Config.Profiles.Current.ExchangeData.ProtocolType == ProtocolType.ApoIdent ||
                Locale.Language != "de")
			{
				this.report_management_button.Visible = false;
			}
			else
			{
				this.report_management_button.Visible = true;
			}
		}

		#endregion profile settings
			


		#region acquistion settings

		private void OnIdentificationComboChanged(object sender, EventArgs e)
		{
			this.Config.AcquisitionSettings.IdentificationMode = (IdentificationMode) this.identification_combo.Active;
			this.Update(PreferencesUpdateStatus.IdentficationModeChanged);
		}

		private void OnServerEntryChanged(object sender, EventArgs e)
		{
			this.Config.AcquisitionSettings.Url = StringHelper.CleanUserInputString(this.server_entry.Text);
		}

		private void OnPortEntryChanged(object sender, EventArgs e)
		{
			try
			{
				this.Config.AcquisitionSettings.TcpPort = Int32.Parse(StringHelper.CleanUserInputString(this.port_entry.Text));
			}
			catch(Exception)
			{
				this.Config.AcquisitionSettings.TcpPort = -1;
			}
		}

		private void UpdateAcquisitionSection()
		{
			this.identification_combo.Active    = (int) this.Config.AcquisitionSettings.IdentificationMode;
			this.server_entry.Text				= this.Config.AcquisitionSettings.Url;
			this.port_entry.Text				= String.Empty;
			if (this.Config.AcquisitionSettings.TcpPort > -1)
				this.port_entry.Text = this.Config.AcquisitionSettings.TcpPort.ToString();

			if (this.Config.AcquisitionSettings.IdentificationMode == IdentificationMode.Local)
			{
				this.server_entry.Sensitive = false;
				this.server_label.Sensitive	= false;
				this.port_entry.Sensitive 	= false;
				this.port_label.Sensitive	= false;
			}
			else
			{
				this.server_entry.Sensitive = true;
				this.server_label.Sensitive	= true;
				this.port_entry.Sensitive 	= true;
				this.port_label.Sensitive	= true;
			}

			this.acquisition_table.Sensitive = true;
		}

		private bool AcquisitionMessageShown {get; set;}
        #endregion acquistion settings


		private void OnCloseButtonClicked(object o, System.EventArgs e)
		{
            this.close_button.Sensitive = false;
            Plugin.host.ProcessEvents();

			if (this.Config.Profiles.Current == null) 
			{
				Plugin.host.ShowInfoMessage(this.preferences_dialog,
					Catalog.GetString("It does not exist any profile. Please create a profile now."));
                this.close_button.Sensitive = true;
				return;
			}
         
			if (this.Config.AcquisitionSettings.IdentificationMode == IdentificationMode.Custom &&
				String.IsNullOrEmpty(this.Config.AcquisitionSettings.Url) == true)
			{
				Plugin.host.ShowInfoMessage(this.preferences_dialog,
					Catalog.GetString("Please enter an url in the field 'Ident server'."));
                this.close_button.Sensitive = true;
				return;
			}

			if (this.Config.AcquisitionSettings.IdentificationMode == IdentificationMode.Custom &&
				this.Config.AcquisitionSettings.TcpPort < 0)
			{
				Plugin.host.ShowInfoMessage(this.preferences_dialog,
					Catalog.GetString("Please enter a valid port number in the field 'Tcp port'."));
                this.close_button.Sensitive = true;
				return;
			}
			
            Preferences.CheckForDemoVersion(this.preferences_dialog, this.Config);
			this.CheckDirectoryEntriesForDoubleEntries();
         
            this.is_running = false;
            this.preferences_dialog.Destroy();
            Plugin.host.ProcessEvents();

			this.Config.Unstash();

            try
            {
                this.Config.WriteToXmlFile();
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error while saving apo-ident configuration file: {0}", ex);
            }

			if (this.Config.Profiles.NeedCheck == true)
				new Preferences(this.FinderWindow);
           
		}

		private FinderWindow FinderWindow { get; set; }
		private Configurations Config { get; set; }
		private bool is_running { get; set; }
        private int MainThread { get; set; } = System.Threading.Thread.CurrentThread.ManagedThreadId;
	}	
}