// 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 System.Collections.Generic;
using Hiperscan.Unix;
using Gtk;
using Gdk;
using Glade;
using Hiperscan.Extensions.ApoIdent.SubstanceManagementExtension;
using HollyLibrary;
using Hiperscan.Spectroscopy.IdentModule;
using GLib;

namespace Hiperscan.Extensions.ApoIdent
{
    public class SubstanceExtensionDialog
    {
        private enum Columns
        {
            Selectable,
            Info,
            SubstanceCategoryPic,
            SubstanceName,
            LatinName,
            SubstanceInfo,
            SubstanceCategory, 
            Search,
        }

        [Widget] Gtk.Dialog substance_extension_dialog  = null;
        [Widget] Gtk.Entry search_entry                 = null;

        [Widget] Gtk.TreeView substance_treeview        = null;
        [Widget] Gtk.Label explanation_label            = null;
		[Widget] Gtk.ComboBox config_combobox           = null;

        Gtk.TreeModelFilter FilterModel = null;
        Gtk.ListStore ListStoreModel    = null;      

		public SubstanceExtensionDialog(FinderWindow finder_window)
		{
			this.FinderWindow = finder_window;
			this.Config = finder_window.Config;
			this.Config.Profiles.Stash();
			this.SubstanceDB = finder_window.SubstanceManagement;

            Glade.XML gui = new Glade.XML(null, "substance_extension_dialog.glade", "substance_extension_dialog", "Hiperscan");
            gui.Autoconnect(this);

            this.substance_extension_dialog.SetWmclass(Plugin.name.ToLower(), Plugin.name.ToLower());
            this.substance_extension_dialog.TransientFor = finder_window.GtkWindow;

            this.RedPoint       = new Pixbuf(null, "red_point.png", 18, 18);
            this.GreyPoint     = new Pixbuf(null, "black_point.png", 18, 18);

			this.InitConfigCombo();
            this.InitSubstanceList();
            this.UpdateSubstanceList();

            this.substance_treeview.ButtonPressEvent += this.OnButtonPressEvent;
            this.substance_treeview.MotionNotifyEvent += this.OnMotion;

            this.explanation_label.Text = this.ExplanationText();

            int width = substance_treeview.SizeRequest().Width + 20;
            if (width > WindowSize.RESOLUTION_WIDTH)
                width = WindowSize.RESOLUTION_WIDTH - 100;
           
            this.explanation_label.WidthRequest = width;
            this.substance_extension_dialog.HeightRequest = 500;
            this.search_entry.GrabFocus();
            this.search_entry.Activated += (sender, e) => this.ShowAddDialog();

            this.substance_extension_dialog.IconList = ApoIdentStock.FinderIcons;
            while (this.substance_extension_dialog.Run() == (int)ResponseType.Accept) 
            {
                this.ShowAddDialog();
            }

            WaitWindow wait = new WaitWindow(this.substance_extension_dialog,
                                             Catalog.GetString("Please wait while saving changes ..."),
                                             0);
			this.SubstanceDB.Extension.Save();
			this.Config.Profiles.Unstash(false);  
            wait.Destroy();
            this.substance_extension_dialog.Destroy();
        }

        private string ExplanationText()
        {
            return Catalog.GetString("Here you can manage substances. You can create new substance entries and " +
                                           "you can control which substance should be shown at the application surface.");
        }

        public void ShowAddDialog()
        {
            AddSubstanceDialog dialog = new AddSubstanceDialog(this);
            if (dialog.ClassificationInfo != null)
                this.AddSubstance(dialog.ClassificationInfo);  
        }

		private void InitConfigCombo()
        {
            if (this.Config.Profiles.Count > 0)
            {
                ListStore config_store = new ListStore(typeof(string));
                CellRendererText config_text = new CellRendererText();
                config_text.Scale = Pango.Scale.Large;
				this.config_combobox.PackStart(config_text, false);
				this.config_combobox.SetAttributes(config_text, "text", 0);
				this.config_combobox.Model = config_store;
                foreach (Profile item in this.Config.Profiles.Values)
					this.config_combobox.AppendText(item.Name);

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

			this.config_combobox.Sensitive = this.Config.Profiles.Count > 1;
			this.config_combobox.Changed += this.OnConfigComboChanged;
        }

        private void InitSubstanceList()
        {
            CellRendererToggle toggle = new CellRendererToggle();
            toggle.Activatable = true;
            toggle.Toggled += this.OnSelectableToggled;

            CellRendererInfo info = new CellRendererInfo();
            info.Activatable = true;
            info.Toggled +=  this.OnSubstanceInfoToggled;


            this.substance_treeview.AppendColumn(Catalog.GetString("Selectable"), toggle, "active" ,                    Columns.Selectable);
            this.substance_treeview.AppendColumn("   ", info, "active" ,                                                Columns.Info);
            this.substance_treeview.AppendColumn(Catalog.GetString("Category"), new CellRendererPixbuf(), "pixbuf",     Columns.SubstanceCategoryPic);
            this.substance_treeview.AppendColumn(Catalog.GetString("Substance Name"), new CellRendererText(), "text",   Columns.SubstanceName);
            this.substance_treeview.AppendColumn(Catalog.GetString("Latin Name"), new CellRendererText(), "text",       Columns.LatinName);

            foreach (TreeViewColumn col in substance_treeview.Columns)
            {
                col.Clickable = true;
                col.SortOrder = SortType.Ascending;
                col.Clicked += this.OnTVColumnClicked;
            }

            this.ListStoreModel = new ListStore (typeof(bool),
                                                 typeof(bool),
                                                 typeof(Gdk.Pixbuf),
                                                 typeof(string),
                                                 typeof(string),
                                                 typeof(SubstanceInfo),
                                                 typeof (SubstanceCategory),
                                                 typeof(HashSet<string>));

   
            this.ListStoreModel.SetSortFunc((int)Columns.Selectable,              this.CompareSelectables);
            this.ListStoreModel.SetSortFunc((int)Columns.Info,                    this.CompareInfos);
            this.ListStoreModel.SetSortFunc((int)Columns.SubstanceCategoryPic,    this.CompareCategories);
            this.ListStoreModel.SetSortFunc((int)Columns.SubstanceName,           this.CompareSubstanceNames);
            this.ListStoreModel.SetSortFunc((int)Columns.LatinName,               this.CompareLatinNames);

            this.LastActiveColumnId = (int)Columns.Selectable;
            this.substance_treeview.Columns[(int)Columns.SubstanceName].SortOrder = SortType.Ascending;
            this.ListStoreModel.SetSortColumnId((int)Columns.Selectable, SortType.Ascending);
            this.substance_treeview.Columns[(int)Columns.Selectable].SortIndicator = true;

            this.FilterModel = new TreeModelFilter(this.ListStoreModel, null);
            this.FilterModel.VisibleFunc = new TreeModelFilterVisibleFunc(this.SubstanceFilter);
            this.substance_treeview.Model = this.FilterModel;                      
        }

        private void UpdateSubstanceList()
        {
            this.IgnoreFilter = true;

            this.ListStoreModel.Clear();

            bool show_info_column = false;


			foreach (ClassificationInfo classification_info in this.SubstanceDB.Extension.ModelClassExtension.Classifications)
            {
                foreach (SubstanceInfo substance_info in classification_info.Substances)
                {
                    string substance_name = substance_info.PrimaryDefaultName;
                    string latin_name = substance_info.PrimaryLatinName;
                    if (String.IsNullOrEmpty(latin_name) == true)
                        latin_name = SubstanceManagement.LocalizedNotAvailable;

                    SubstanceCategory category = SubstanceListAutoCompletionEntry.ConvertToSubstanceCategory(classification_info);
                
                    bool is_selectable = substance_info.IsVisible;
                    bool has_info = substance_info.HasAlternativeNames;
                    Pixbuf buf = category == SubstanceCategory.NotMeasurable ? this.RedPoint : this.GreyPoint;
                    HashSet<string> search = new HashSet<string>();
                    foreach (string item in substance_info.AllNames)
                        search.Add(item.CleanForSubstanceSearch());

                    if (has_info == true)
                        show_info_column = true;

                    this.ListStoreModel.AppendValues(is_selectable, has_info, 
                                                     buf, 
                                                     substance_name, 
                                                     latin_name, 
                                                     substance_info, 
                                                     category, 
                                                     search); 
                    
                }
            }

            this.substance_treeview.Columns[(int)Columns.Info].Visible = show_info_column;

            this.IgnoreFilter = false;
            this.FilterModel.Refilter();
        }

        [ConnectBefore]
        private void OnMotion(object o,MotionNotifyEventArgs e)
        {
            try
            {
                TreePath path;
                TreeIter iter;
                bool is_in_range = false;

                if (this.substance_treeview.GetPathAtPos((int)e.Event.X, (int)e.Event.Y, out path))
                {
                    Rectangle rect = this.substance_treeview.GetCellArea(path, this.substance_treeview.Columns[
                        (int)Columns.SubstanceCategoryPic]);
                    this.FilterModel.GetIter(out iter, path);

                    if (rect.X <= e.Event.X && e.Event.X <= rect.X + rect.Width)
                        is_in_range = true;

                    bool? entered_range = null;
                    bool changed_row = path.ToString() != this.LastTreePath.ToString();

                    if (is_in_range == true && this.IsPictureColumn == false)
                        entered_range = true;
                    else if (is_in_range == false && this.IsPictureColumn == true)
                        entered_range = false;

                    this.IsPictureColumn = is_in_range;
                    this.LastTreePath = path.ToString();

                    SubstanceCategory category = (SubstanceCategory)this.FilterModel.GetValue(iter, (int)Columns.SubstanceCategory);

                    int x = 0;
                    int y = 0;

                    this.substance_treeview.TranslateCoordinates(this.substance_extension_dialog, 0, 0, out x, out y);
                    double mouse_x = x + rect.X + rect.Width / 2;
                    double mouse_y = y + rect.Y + rect.Height / 2;

                    this.substance_extension_dialog.GdkWindow.GetPosition(out x, out y);
                    mouse_x += x;
                    mouse_y += y;

                    switch(entered_range)
                    {
                        case true:
                            this.ToolTip = new SubstanceCategoryToolTip(mouse_x, mouse_y, category);
                            break;

                        case false:
                            try
                            {
                                this.ToolTip.Destroy();
                                Plugin.host.ProcessEvents();
                            }
                            catch(Exception){}
                            break;

                        default:
                            if (this.IsPictureColumn == true && changed_row == true)
                            {
                                try
                                {
                                    this.ToolTip.Destroy();
                                    Plugin.host.ProcessEvents();
                                }
                                catch (Exception) { }
                                this.ToolTip = new SubstanceCategoryToolTip(mouse_x, mouse_y, category);
                            }

                            break;
                    }
                }
            }
            catch (Exception)
            {
                this.LastTreePath = "-1";
                this.IsPictureColumn = false;
                try  {this.ToolTip.Destroy();} catch{};
            }
        }





        private int CompareCategories(TreeModel model, TreeIter a, TreeIter b)
        {
            try
            {
                SubstanceCategory c1 = (SubstanceCategory)model.GetValue(a, (int)Columns.SubstanceCategory);
                SubstanceCategory c2 = (SubstanceCategory)model.GetValue(b, (int)Columns.SubstanceCategory);

                if (c1 == SubstanceCategory.NotMeasurable && c2 == SubstanceCategory.UserDefined)
                    return -1;

                if (c1 == SubstanceCategory.UserDefined && c2 == SubstanceCategory.NotMeasurable)
                    return 1;

                return this.CompareSubstanceNames(model, a, b);
            }
            catch(Exception)
            {
                return 0;
            }
        }

        private int CompareInfos(TreeModel model, TreeIter a, TreeIter b)
        {
            try
            {
                bool b1 = (bool)model.GetValue(a, (int)Columns.Info);
                bool b2 = (bool)model.GetValue(b, (int)Columns.Info);

                if (b1 == true && b2 == false)
                    return -1;

                if (b1 == false && b2 == true)
                    return 1;
                
                return this.CompareSubstanceNames(model, a, b);
            }
            catch(Exception)
            {
                return 0;
            }
        }

        private int CompareSelectables(TreeModel model, TreeIter a, TreeIter b)
        {
            if (this.SortActive == false)
                return 0;

            try
            {
                bool b1 = (bool)model.GetValue(a, (int)Columns.Selectable);
                bool b2 = (bool)model.GetValue(b, (int)Columns.Selectable);

                if (b1 == true && b2 == false)
                    return -1;

                if (b1 == false && b2 == true)
                    return 1;

                return this.CompareSubstanceNames(model, a, b);
            }
            catch(Exception)
            {
                return 0;
            }
        }

        private int CompareSubstanceNames(TreeModel model, TreeIter a, TreeIter b)
        {
            try
            {
                string s1 = (string)model.GetValue(a, (int)Columns.SubstanceName);
                string s2 = (string)model.GetValue(b, (int)Columns.SubstanceName);

                return String.Compare(s1, s2);
            }
            catch(Exception)
            {
                return 0;
            }
        }

        private int CompareLatinNames(TreeModel model, TreeIter a, TreeIter b)
        {
            try
            {
                string s1 = (string)model.GetValue(a, (int)Columns.LatinName);
                string s2 = (string)model.GetValue(b, (int)Columns.LatinName);

                if (s1 != SubstanceManagement.LocalizedNotAvailable && s2 == SubstanceManagement.LocalizedNotAvailable)
                    return -1;

                if (s1 == SubstanceManagement.LocalizedNotAvailable && s2 != SubstanceManagement.LocalizedNotAvailable)
                    return 1;

                int compare = String.Compare(s1, s2);
                if (compare != 0)
                    return compare;

                return this.CompareSubstanceNames(model, a, b);
            }
            catch(Exception)
            {
                return 0;
            }
        }

		private void OnConfigComboChanged(object sender, EventArgs e)
		{
			this.substance_extension_dialog.GdkWindow.Cursor = new Gdk.Cursor(Gdk.CursorType.Watch);
			this.substance_extension_dialog.Sensitive = false;
			this.FinderWindow.host.ProcessEvents();
			this.Config.Profiles.Current.SubstanceExtension?.Save();
            this.Config.Profiles.Current = this.Config.Profiles[this.config_combobox.ActiveText];
            this.FinderWindow.CreateArchive(this.Window);
                this.SubstanceDB.InitModelExtension();
            this.UpdateSubstanceList();
			this.substance_extension_dialog.Sensitive = true; 
			this.substance_extension_dialog.GdkWindow.Cursor = new Gdk.Cursor(Gdk.CursorType.Arrow);
			this.FinderWindow.host.ProcessEvents();
		}

        private void OnTVColumnClicked (object sender, EventArgs e)
        {
            Gtk.TreeViewColumn col = sender as Gtk.TreeViewColumn;
            if (col == null)
                return;

            this.SortActive = true;

            int id = 0;
            foreach(Gtk.TreeViewColumn item in this.substance_treeview.Columns)
            {
                if (item == col)
                    break;
                id++;
            }

            if(this.LastActiveColumnId == id)
            {
                if (col.SortOrder == SortType.Ascending)
                    col.SortOrder = SortType.Descending;
                else
                    col.SortOrder = SortType.Ascending;
            }
            else
            {
                col.SortOrder = SortType.Ascending;
                this.substance_treeview.Columns[this.LastActiveColumnId].SortIndicator = false;
                this.LastActiveColumnId = id;
            }

            this.ListStoreModel.SetSortColumnId(id, col.SortOrder);
            col.SortIndicator = true;

            TreeIter iter;
            if (this.substance_treeview.Selection.GetSelected(out iter) == true)
            {
                TreePath path = this.ListStoreModel.GetPath(iter);
                this.substance_treeview.ScrollToCell(path, this.substance_treeview.Columns[0], false, 0.5f, 0.5f);
            }
        }

        private bool SubstanceFilter(Gtk.TreeModel model, Gtk.TreeIter iter)
        {
            if (this.IgnoreFilter == true)
                return true;
            
            string substance_pattern = this.search_entry.Text.CleanForSubstanceSearch();

            if (String.IsNullOrEmpty(substance_pattern) == true)
                return true;

            HashSet<string> names = (HashSet<string>) model.GetValue(iter, (int)Columns.Search);
            if (names == null)
                return true;

            foreach (string item in names)
            {
                if (String.IsNullOrEmpty(substance_pattern) == false && item.StartsWith(substance_pattern) == true)
                    return true;
            }

            return false;
        }

        private void OnSelectableToggled(object sender, ToggledArgs args)
        {
            this.SortActive = false;
            TreeIter iter;
            Gtk.TreeModelFilter model = this.substance_treeview.Model as Gtk.TreeModelFilter;

            if (model.GetIter (out iter, new TreePath(args.Path))) 
            {
                iter = model.ConvertIterToChildIter(iter);

                SubstanceInfo substance_info = (SubstanceInfo) this.ListStoreModel.GetValue(iter, (int)Columns.SubstanceInfo);
                if (substance_info.IsVisible == false)
                    substance_info.IsVisible = this.CheckForUniqueSubstanceNames(substance_info, false);
                else
                    substance_info.IsVisible = !substance_info.IsVisible;
                
                this.ListStoreModel.SetValue(iter, (int)Columns.Selectable, substance_info.IsVisible);
                this.SubstanceDB.RefreshExtension();
            }   
        }

        private void OnSubstanceInfoToggled(object sender, ToggledArgs args)
        {
            TreeIter iter;
            Gtk.TreeModelFilter model = this.substance_treeview.Model as Gtk.TreeModelFilter;

            if (model.GetIter(out iter, new TreePath(args.Path))) 
            {
                iter = model.ConvertIterToChildIter(iter);

                bool has_info = (bool) this.ListStoreModel.GetValue(iter, (int)Columns.Info);
                if (has_info == false)
                    return;
                
                SubstanceInfo substance_info = (SubstanceInfo) this.ListStoreModel.GetValue(iter, (int)Columns.SubstanceInfo);

                string alternative_substance_names = SubstanceManagement.LocalizedNotAvailable;
                if (substance_info.OtherDefaultNames.Count > 0)
                    alternative_substance_names = String.Join("\n\t- ", substance_info.OtherDefaultNames.ToArray());

                string alternavtive_latin_names = SubstanceManagement.LocalizedNotAvailable;
                if (substance_info.OtherLatinNames.Count > 0)
                    alternavtive_latin_names = String.Join("\n\t- ", substance_info.OtherLatinNames.ToArray());


                string message = String.Format(Catalog.GetString("Alternative substance names:\n\t- {0}\n\n" +
                                                                 "Alternative latin names:\n\t- {1}"),
                                               alternative_substance_names,
                                               alternavtive_latin_names);


                HToolTip.ShowToolTipAsDialog(this.substance_treeview,
                                             substance_info.PrimaryDefaultName,
                                             message,                      
                                             Stock.DialogInfo);
            }
        }

        private void SelectTreeIterItem(string primary_name)
        {
            TreeIter iter;
            this.search_entry.Text = String.Empty;

            this.substance_treeview.GrabFocus();

            Gtk.TreeModelFilter model = this.substance_treeview.Model as Gtk.TreeModelFilter;

            for (int i = 0; i < model.IterNChildren(); i++)
            {
                if (model.IterNthChild(out iter, i) == true)
                {
                    string name =(string) model.GetValue(iter, (int)Columns.SubstanceName);
                    if (name == primary_name)
                    {
                        this.substance_treeview.Selection.SelectIter(iter);
                        TreePath path = model.GetPath(iter);
                        this.substance_treeview.ScrollToCell(path, this.substance_treeview.Columns[0], true, 0.5f, 0.0f);
                        break;
                    }
                }
            }        
        }

        private void OnSearchEntryChanged(object sender, EventArgs e)
        {
            this.FilterModel.Refilter();
        }

        private void AddSubstance(ClassificationInfo classification_info)
        {
            string message = String.Empty;
            SubstanceInfo substance_info = classification_info.Substances[0];

            if (this.IsInputValid(substance_info.PrimaryDefaultName) == false)
            {
                message = String.Format(Catalog.GetString("The substance name '{0}' is not valid."),
                                        substance_info.PrimaryDefaultName);
                
                this.ShowMessage(message, MessageType.Error);
                return;
            }

            if (this.IsInputValid(substance_info.PrimaryLatinName) == false)
            {
                message = String.Format(Catalog.GetString("The latin name '{0}' is not valid."),
                                        substance_info.PrimaryLatinName);

                this.ShowMessage(message, MessageType.Error);
                return;
            }

            string substance_name = substance_info.PrimaryDefaultName.CleanForSubstanceSearch();
            string latin_name = substance_info.PrimaryLatinName.CleanForSubstanceSearch();

            if (substance_name == latin_name)
            {
                message = Catalog.GetString("The substance name and the latin name must not be equal.");
                this.ShowMessage(message, MessageType.Error);
                return;
            }

            if (this.CheckForUniqueSubstanceNames(substance_info, true) == false)
                return;

			this.SubstanceDB.Extension.ModelClassExtension.Classifications.Add(classification_info);
			this.SubstanceDB.Extension.ModelClassExtension.InitResolver();
            this.SubstanceDB.RefreshExtension();
            this.UpdateSubstanceList();
            this.search_entry.Text = String.Empty;
            this.FilterModel.Refilter();
            this.SelectTreeIterItem(substance_info.PrimaryDefaultName);
        }

        private bool IsInputValid(string substance_name)
        {
            substance_name = substance_name.ToLower().Trim(new char[]{' ', ',','\t', ';'});
            if (substance_name == SubstanceManagement.LocalizedNotAvailable.ToLower())
                return false;                      
                                          
            string batch = SubstanceManagement.LocalizedBatchExtension.Trim(new char[]{' ', ','}).ToLower();
            if (substance_name.EndsWith(batch) == true)
                return false;

            if (substance_name.StartsWith(batch) == true)
                return false;

            return true;
        }

        private bool CheckForUniqueSubstanceNames(SubstanceInfo substance_info, bool refresh_treeview)
        {
                string message = String.Empty;

            string substance_name = substance_info.PrimaryDefaultName.CleanForSubstanceSearch();
            string latin_name = substance_info.PrimaryLatinName.CleanForSubstanceSearch();

            Dictionary<string, string> substance_name_classifiers = this.SubstanceDB.CheckUniqueSubstanceName(substance_name);
            Dictionary<string, string> latin_name_classifiers = this.SubstanceDB.CheckUniqueSubstanceName(latin_name);

            if (substance_name_classifiers.ContainsKey(SubstanceManagement.LocalizedUserdefinedClassifierName) == true)
            {
                string primary_name = substance_name_classifiers[SubstanceManagement.LocalizedUserdefinedClassifierName];
                message = String.Format(Catalog.GetString("The substance '{0}' already exists in this classifier '{2}'. " +
                                                          "Please look at the entry with the primary name '{1}'. " + 
                                                         "Before adding/activating this substance, you have to deactivate the selectable property " +
                                                         "of the existing substance."),
                                        substance_info.PrimaryDefaultName, 
                                        primary_name,
                                        SubstanceManagement.LocalizedUserdefinedClassifierName);

                this.ShowMessage(message, MessageType.Error);
                if (refresh_treeview == true)
                {
                    this.search_entry.Text = String.Empty;
                    this.FilterModel.Refilter();
                    this.SelectTreeIterItem(primary_name);
                }
                return false;
            }

            if (latin_name_classifiers.ContainsKey(SubstanceManagement.LocalizedUserdefinedClassifierName) == true)
            {  
                string primary_name = latin_name_classifiers[SubstanceManagement.LocalizedUserdefinedClassifierName];

                message = String.Format(Catalog.GetString("The substance '{0}' already exists in this classifier '{2}'. " +
                                                          "Please look at the entry with the primary name '{1}'. " + 
                                                         "Before adding/activating this substance, you have to deactivate the selectable property " +
                                                         "of the existing substance."),
                                        substance_info.PrimaryLatinName, 
                                        primary_name,
                                        SubstanceManagement.LocalizedUserdefinedClassifierName);

                this.ShowMessage(message, MessageType.Error);
                if (refresh_treeview == true)
                {
                    this.search_entry.Text = String.Empty;
                    this.FilterModel.Refilter();
                    this.SelectTreeIterItem(primary_name);
                }
                return false;
            }

            if (substance_name_classifiers.Count > 0 || latin_name_classifiers.Count > 0)
            {
                string name = substance_name_classifiers.Count > 0 ? substance_info.PrimaryDefaultName : substance_info.PrimaryLatinName;

                message = String.Format(Catalog.GetString("The substance '{0}' already exists as a NIR measurable substance. " +
                                                          "Do you want to add/activate this substance anyway?." + 
                                                          "Press the YES buttun for continuing."), name);

                if (this.ShowMessage(message, MessageType.Warning) == false)
                    return false;
            }

            return true;
        }

        [ConnectBefore]
        private void OnButtonPressEvent(object sender, ButtonPressEventArgs e)
        {
            if (e.Event.Button == 3)
            {
                Menu menu = new Menu();
                MenuItem item = new MenuItem(Catalog.GetString("Deselect all substances"));
                item.Activated += this.OnDeselectAllSubstances;
                menu.Append(item);
                menu.ShowAll();
                menu.Popup();
            }
        }

        private void OnDeselectAllSubstances(object sender, EventArgs e)
        {
            TreeIter iter;
            this.SortActive = false;

            Gtk.TreeModelFilter model = this.substance_treeview.Model as Gtk.TreeModelFilter;

            for (int i = 0; i < model.IterNChildren(); i++)
            {
                if (model.IterNthChild(out iter, i) == true)
                {
                    iter = model.ConvertIterToChildIter(iter);
                    this.ListStoreModel.SetValue(iter, (int)Columns.Selectable, false);
                    SubstanceInfo substance_info = (SubstanceInfo)this.ListStoreModel.GetValue(iter, (int)Columns.SubstanceInfo);
                    substance_info.IsVisible = false;
                }
            }  
        }

        public string SearchText
        {
            get
            {
                return this.search_entry.Text.Trim();
            }
        }

        private bool ShowMessage(string message, Gtk.MessageType message_type)
        {
            MessageDialog mdlg = new MessageDialog(this.substance_extension_dialog,
                                                   Gtk.DialogFlags.Modal,message_type,
                                                   message_type == MessageType.Warning ? ButtonsType.YesNo : ButtonsType.Ok,
                                                   message);

            mdlg.IconList = ApoIdentStock.FinderIcons;
            ResponseType answer = (ResponseType) mdlg.Run();
            mdlg.Destroy();
            if (answer == ResponseType.Yes)
                return true;

            return false;
        }

        public Gtk.Window Window
        {
            get
            {
                return this.substance_extension_dialog;
            }
        }

        private Gdk.Pixbuf RedPoint     {get; set;}
        private Gdk.Pixbuf GreyPoint    {get; set;}
        private int LastActiveColumnId  {get; set;}
        
        private SubstanceManagement SubstanceDB         {get; set;}
        private bool SortActive                         {get; set;} = true;
        private bool IgnoreFilter                       {get; set;} = true;
		private Configurations Config                   { get; set; }
		private FinderWindow FinderWindow               { get; set; }

        public bool IsPictureColumn { get; set; } = false;
        public string LastTreePath { get; set; } = "-1";
        public SubstanceCategoryToolTip ToolTip { get; set; }
    }
}
