// Created with MonoDevelop
//
//    QuickStep: Acquire, view and identify spectra 
//    Copyright (C) 2021 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 System.Linq;
using Hiperscan.Spectroscopy.IdentModule;

namespace Hiperscan.Extensions.ApoIdent
{
    public class SubstanceResolver
    {
        public void AddModelClassToResolver(ModelClassInfo model_class_info)
        {
            this.ModelClassNameDetailResolver.Add(model_class_info.ModelClassName, model_class_info);

            foreach (ClassificationInfo classification_info in model_class_info.Classifications)
            {
                foreach (SubstanceInfo substance_info in classification_info.Substances)
                {
                    if (substance_info.IsVisible == false)
                        continue;

                    this.AddSubstanceNamesToResolver(model_class_info.ModelClassName, 
                                                     classification_info, 
                                                     substance_info);

                    this.AddSubstanceIdToResolver(model_class_info.ModelClassName,
                                                  substance_info);
                }
            }
        }

        private void AddSubstanceIdToResolver(string model_class_name, SubstanceInfo substance_info)
        {
            if (substance_info.Id == "20662")
                Console.WriteLine();

            if (this.SubstanceIdModelClassNameResolver.ContainsKey(substance_info.Id) == false)
                this.SubstanceIdModelClassNameResolver.Add(substance_info.Id, new HashSet<string>());

            this.SubstanceIdModelClassNameResolver[substance_info.Id].Add(model_class_name);

            if (this.SubstanceIdSubstanceInfoResolver.ContainsKey(substance_info.Id) == false)
                this.SubstanceIdSubstanceInfoResolver.Add(substance_info.Id, substance_info);
        }


        private void AddSubstanceNamesToResolver(string model_class_name,  ClassificationInfo classification_info,  SubstanceInfo substance_info)
        {
            HashSet<string> corrected_names = new HashSet<string>();
            foreach (string substance_name in substance_info.AllNames)
            {
                if (classification_info.ClassificationType == ClassificationType.NonMultiple)
                {
                    foreach (string batch_number in substance_info.BatchNumbers)
                        corrected_names.Add(BatchExtension.AddExtension(substance_name, batch_number));
                }
                else
                {
                    corrected_names.Add(substance_name);
                }
            }

            foreach (string corrected_name in corrected_names)
            {
                if (this.SubstanceNameModelClassNameResolver.ContainsKey(corrected_name) == false)
                    this.SubstanceNameModelClassNameResolver.Add(corrected_name, new HashSet<string>());

                this.SubstanceNameModelClassNameResolver[corrected_name].Add(model_class_name);
            }
        }

        public void RemoveUserdefinedModelClassFromResolver()
        {
            string model_class_name = LocalizedSubstanceExtensions.UserDefinedModelClassName;

            if (this.ModelClassNameDetailResolver.ContainsKey(model_class_name))
                this.ModelClassNameDetailResolver.Remove(model_class_name);

            this.RemoveUserDefinedSubstanceIdsFromResolver();
            this.RemoveUserDefinedSubstanceNamesFromResolver();
        }

        private void RemoveUserDefinedSubstanceIdsFromResolver()
        {
            string model_class_name = LocalizedSubstanceExtensions.UserDefinedModelClassName;
            HashSet<string> substance_ids = new HashSet<string>(this.SubstanceIdModelClassNameResolver.Keys);

            foreach (string substance_id in substance_ids)
            {
                this.SubstanceIdModelClassNameResolver[substance_id].Remove(model_class_name);
                if (this.SubstanceIdModelClassNameResolver[substance_id].Count == 0)
                {
                    this.SubstanceIdModelClassNameResolver.Remove(substance_id);
                    this.SubstanceIdSubstanceInfoResolver.Remove(substance_id);
                }
            }
        }

        private void RemoveUserDefinedSubstanceNamesFromResolver()
        {
            string model_class_name = LocalizedSubstanceExtensions.UserDefinedModelClassName;
            HashSet<string> substance_names = new HashSet<string>(this.SubstanceNameModelClassNameResolver.Keys);

            foreach (string substance_name in substance_names)
            {
                this.SubstanceNameModelClassNameResolver[substance_name].Remove(model_class_name);
                if (this.SubstanceNameModelClassNameResolver[substance_name].Count == 0)
                    this.SubstanceNameModelClassNameResolver.Remove(substance_name);
            }
        }

        public ModelClassInfo GetModelClassificationInfo(string model_class_name)
        {
            return this.ModelClassNameDetailResolver[model_class_name];
        }

        public HashSet<string> GetModelClassesBySubstanceName(string substance_name)
        {
            if (this.SubstanceNameExists(substance_name) == false)
                return new HashSet<string>();

            return this.SubstanceNameModelClassNameResolver[substance_name];
        }

        public HashSet<string> GetModelClassesBySubstanceId(string substance_id)
        {
            if (this.SubstanceIdExists(substance_id) == false)
                return new HashSet<string>();

            return this.SubstanceIdModelClassNameResolver[substance_id];
        }

        public SubstanceInfo GetSusbtanceInfo(string substance_id)
        {
            if (this.SubstanceIdExists(substance_id) == false)
                return null;

            return this.SubstanceIdSubstanceInfoResolver[substance_id];
        }

        public bool SubstanceIdExists(string substance_id)
        {
            return this.SubstanceIdModelClassNameResolver.ContainsKey(substance_id);
        }

        public bool SubstanceNameExists(string substance_name)
        {
            return this.SubstanceNameModelClassNameResolver.ContainsKey(substance_name);
        }

        public List<ModelClassInfo> MasterModelClassInfos
        {
            get
            {
                return new List<ModelClassInfo>(this.ModelClassNameDetailResolver.Values.Where(x => x.DatabaseInfo == AccessDatabaseInfo.Master));
            }
        }

        public HashSet<string> AllModelClassNames
        {
            get
            {
                return new HashSet<string>(this.ModelClassNameDetailResolver.Keys);
            }
        }

        public bool HasUserDefinedModelClass
        {
            get
            {
                return this.ModelClassNameDetailResolver.Values.Any(x => x.DatabaseInfo == AccessDatabaseInfo.UserDefined);
            }
        }

        public HashSet<string> AllSubstanceNames
        {
            get
            {
                return new HashSet<string>(this.SubstanceNameModelClassNameResolver.Keys);
            }
        }

        public List<SubstanceListAutoCompletionEntry> AutpCompletionEntries
        {
            get
            {
                List<SubstanceListAutoCompletionEntry> values = new List<SubstanceListAutoCompletionEntry>();

                foreach (string substance_name in this.SubstanceNameModelClassNameResolver.Keys)
                {
                    List<ClassificationInfo> classification_infos = new List<ClassificationInfo>();
                    foreach (string class_name in this.SubstanceNameModelClassNameResolver[substance_name])
                    {
                        ModelClassInfo class_info = this.ModelClassNameDetailResolver[class_name];

                        string substance_name_without_batch = BatchExtension.RemoveExtension(substance_name);

                        classification_infos.Add(class_info.GetClassificationInfo(substance_name_without_batch));
                        
                    }

                    SubstanceListAutoCompletionEntry entry = new SubstanceListAutoCompletionEntry(substance_name, classification_infos);
                    values.Add(entry);
                }

                values.Sort();
                return values;
            }
        }

        public List<SubstanceInfo> GetAdditionalTestPdfCheckSubstances()
        {
            List<SubstanceInfo> substances = this.SubstanceIdSubstanceInfoResolver.Values.
                                                 Where(x => String.IsNullOrEmpty(x.PdfLinkAdditionalTest) == false)
                                                 .ToList();

            substances.Sort();
            return substances;
        }

        private Dictionary<string, HashSet<string>> SubstanceIdModelClassNameResolver { get; set; }
            = new Dictionary<string, HashSet<string>>();

        private Dictionary<string, HashSet<string>> SubstanceNameModelClassNameResolver { get; set; }
            = new Dictionary<string, HashSet<string>>();

        private Dictionary<string, ModelClassInfo> ModelClassNameDetailResolver { get; set; } 
            = new Dictionary<string, ModelClassInfo>();

        private Dictionary<string, SubstanceInfo> SubstanceIdSubstanceInfoResolver { get; set; }
            = new Dictionary<string, SubstanceInfo>();
    }
}
