// Created with MonoDevelop
//
//    Copyright (C) 2017 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 System.Runtime.Serialization;
using Hiperscan.AnalysisModule.Authentification;
using Hiperscan.Spectroscopy.Method;
using static Hiperscan.Common.I18n.CatalogLocale;

namespace Hiperscan.AnalysisModule.Identification
{
    [DataContract]
    [Serializable]
    public class IdentModelClass : IModelClass
    {
        public virtual void InitResolver()
        {
            this.SubstanceId_Substance_Resolver = new Dictionary<string, IdentSubstance>();
            this.SubstanceName_Substance_Resolver = new Dictionary<string, IdentSubstance>();
            this.Collisions = new Dictionary<string, List<IdentSubstance>>();

            foreach (IdentClassification classification in this.Classifications)
            {
                foreach (IdentSubstance substance in classification.Substances)
                {
                    if (substance.IsVisible == false)
                        continue;

                    substance.Classification = classification;
                    substance.ModelClass = this;
 
                    this.SubstanceId_Substance_Resolver.Add(substance.Id, substance);
      
                    foreach (string substance_name in substance.AllSubstanceNames)
                    {
                        if (this.SubstanceName_Substance_Resolver.ContainsKey(substance_name) == false)
                        {
                            this.SubstanceName_Substance_Resolver.Add(substance_name, substance);
                        }
                        else
                        {
                            if (this.Collisions.ContainsKey(substance_name) == false)
                            {
                                this.Collisions.Add(substance_name, new List<IdentSubstance>());
                                IdentSubstance tmp = this.SubstanceName_Substance_Resolver[substance_name];
                                this.Collisions[substance_name].Add(tmp);
                            }
                            this.Collisions[substance_name].Add(substance);
                        }
                    }
                }
            }
        }

        public void CalcFuzzy(string reference_substance_name)
        {
            foreach (IdentSubstance substance in this.GetAllSubstances())
                substance.FindFuzzyParameters(reference_substance_name);
        }

        public List<IdentSubstance> GetAllSubstances()
        {
            return this.SubstanceId_Substance_Resolver.Values.ToList();
        }

        public IdentSubstance GetSubstanceBySubstanceName(string substance_name)
        {
            if (this.SubstanceName_Substance_Resolver.ContainsKey(substance_name))
                return this.SubstanceName_Substance_Resolver[substance_name];

            return null;
        }

        public IdentSubstance GetSubstanceBySubstanceId(string substance_id)
        {

            if (this.SubstanceId_Substance_Resolver.ContainsKey(substance_id))
                return this.SubstanceId_Substance_Resolver[substance_id];

            return null;
        }

        public IdentModelClass Clone()
        {
            IdentModelClass tmp = new IdentModelClass();

            tmp.Id = this.Id;
            tmp.Name = this.Name;
            tmp.AccessDefinitionName = this.AccessDefinitionName;

            tmp.SubstanceType = this.SubstanceType;
            tmp.HasValidationDocument = this.HasValidationDocument;
            tmp.HasAdditionalTestDocument = this.HasAdditionalTestDocument;
            tmp.DefaultSupplierName = this.DefaultSupplierName;
            tmp.DatabaseInfo = this.DatabaseInfo?.Clone();

            tmp.Classifications = this.Classifications.Select(c => c.Clone()).ToList(); 
            tmp.InitResolver();

            return tmp;
        }

        public static AccessDatabaseInfo GetUserDefinedDatabaseInfo()
        {
            return new AccessDatabaseInfo("userdefined",                                                         
                                          AccessDatabaseType.UserDefined,                                                           
                                          AnalysisType.ByCustomer);
        }

        public static string GetUserDefinedModelClassName(LocaleType locale)
        {
            switch (locale)
            {
                case LocaleType.de_DE:
                    return "Benutzerdefinierte Substanzen"; ;

                default:
                    return "Userdefined Substances";
            }
        }

        public string GetCollissionMessages()
        {
            if (this.HasCollisions == false)
            {
                return String.Format("There are no collisions within the model class {0}", this.Name);
            }

            String message = String.Format("====== Model Class '{0}' has {1} collision(s).\n",
                                           this.Name, this.Collisions.Count);
            foreach(string substance_name in this.Collisions.Keys)
            {
                message += String.Format("Substance name '{0}' is not unique:\n", substance_name);
                foreach (IdentSubstance substance in this.Collisions[substance_name])
                {
                    message += String.Format("  => SubstanceId {0} with names: {1}\n",
                                             substance.Id,
                                             String.Join("; ", substance.AllSubstanceNames));
                }
            }

            message += String.Format("====== End of Model Class '{0}'.\n",
                                           this.Name);

            return message;
        }

        public bool HasCollisions
        {
            get
            {
                if (this.Collisions == null)
                    return false;

                return this.Collisions.Count > 0;
            }
        }

        [IgnoreDataMember]
        private Dictionary<string, IdentSubstance> SubstanceId_Substance_Resolver { get; set; } 
            = new Dictionary<string, IdentSubstance>();

        [IgnoreDataMember]
        private Dictionary<string, IdentSubstance> SubstanceName_Substance_Resolver { get; set; } 
            = new Dictionary<string, IdentSubstance>();

        [DataMember] public string DefaultSupplierName { get; set; }
        [DataMember] public string AccessDefinitionName { get; set; }
        [DataMember] public string Name { get; set; }
        [DataMember] public string Id { get; set; }
        [DataMember] public SubstanceType SubstanceType { get; set; }
        [DataMember] public bool HasValidationDocument { get; set; }
        [DataMember] public bool HasAdditionalTestDocument { get; set; }

        [IgnoreDataMember]
        public AccessDatabaseInfo DatabaseInfo { get; set; }

        [DataMember] public List<IdentClassification> Classifications { get; set; }
            = new List<IdentClassification>();

        [IgnoreDataMember]
        public Dictionary<string, List<IdentSubstance>> Collisions { get; set; }

    }
}