using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Hiperscan.AnalysisModule;
using Hiperscan.AnalysisModule.Identification;
using Hiperscan.AnalysisModule.Remoting;
using Hiperscan.ApoIdentCore.ComplexFinder;
using Hiperscan.ApoIdentCore.Misc;
using Hiperscan.ApoIdentCore.Remoting;
using Hiperscan.ApoIdentCore.SectionManager.Result;
using Hiperscan.Common;
using Hiperscan.ApoIdentCommon.ApoConfig;
using Hiperscan.SGS;
using Hiperscan.Spectroscopy;

namespace Hiperscan.ApoIdentCore.SectionManager.Substance
{
    public partial class SubstanceManager
    {
        public void ResetAvailableModules()
        {
            this.GlobalStates.ResetAvailableModules();

            if (this.HasValidIMVersion && this.IsModuleInstalled(AnalysisType.Identification))
                this.GlobalStates.AddInstallation(true);

            if (this.HasValidQMVersion && this.IsModuleInstalled(AnalysisType.Quantification))
                this.GlobalStates.AddInstallation(false);

        }

        private bool HasValidIMVersion
        {
            get
            {
                RemoteSettings settings = this.GetRemoteSettings(AnalysisType.Identification);

                if (settings.TestVersion ?? true)
                    return false;

                Version im_version = this.GetVersion(settings.ModuleVersion);
                return this.ApoIdentVersion == im_version;
            }
        }

        private bool HasValidQMVersion
        {
            get
            {
                RemoteSettings settings = this.GetRemoteSettings(AnalysisType.Quantification);

                if (settings.IsApoIdent_2_1 == false)
                    return false;

                if (settings.TestVersion ?? true)
                    return false;

                Version qm_version = this.GetVersion(settings.ModuleVersion);
                return this.ApoIdentVersion == qm_version;
            }
        }

        public bool HasValidationData
        {
            get
            {
                RemoteSettings settings = null;

                if (this.GlobalStates.IsIdentModuleAvailable)
                {
                    settings = this.GetRemoteSettings(AnalysisType.Identification);
                    if (settings.ValidatedModels.Count > 0)
                        return true;
                }

                if (this.GlobalStates.IsQuantifierModuleAvailable)
                {
                    settings = this.GetRemoteSettings(AnalysisType.Identification);
                    if (settings.ValidatedModels.Count > 0)
                        return true;
                }

                return false;
            }
        }

        public bool HasAdditionalData
        {
            get
            {
                RemoteSettings settings = null;

                if (this.GlobalStates.IsIdentModuleAvailable)
                {
                    return true;
                }

                if (this.GlobalStates.IsQuantifierModuleAvailable)
                {
                    settings = this.GetRemoteSettings(AnalysisType.Identification);
                    if (settings.AdditionalTestedModels.Count > 0)
                        return true;
                }

                return false;
            }
        }

        public bool IsModuleInstalled(AnalysisType analysis_type)
        {
            return this.RemoteManager.ServerIsInstalled(analysis_type);
        }

       public string GetModuleCreatorName(AnalysisType analysis_type)
        {
            if (analysis_type == AnalysisType.None || analysis_type == AnalysisType.ByCustomer)
                return CombinedFinder.NO_CREATOR;

            string creator = ApoIdentInfo.NAME + " " + ApoIdentInfo.FullVersion;
            AnalysisServerInfo info = this.RemoteManager.GetServerInfo(analysis_type);
            if (analysis_type == AnalysisType.Identification)
                creator += ", IdentModule " + info.Version.ModuleVersion;
            else
                creator += ", QuantifierModule " + info.Version.ModuleVersion;

            return creator;
        }

        public RemoteState StartServer(AnalysisType analysis_type)
        {
            Console.WriteLine("Starting {0}", analysis_type.GetProductName());
            RemoteState state = this.RemoteManager.StartServer(analysis_type);

            if (analysis_type == AnalysisType.Identification)
                this.IdentServerIsStarted = state.NoError;
            else
                this.QuantifierServerIsStarted = state.NoError;

            return state.Clone();
        }

        public void StopServers()
        {
            if (this.IdentServerIsStarted)
            {
                this.RemoteManager.StopServer(AnalysisType.Identification);
                this.IdentServerIsStarted = false;
            }

            if (this.QuantifierServerIsStarted)
            {
                this.RemoteManager.StopServer(AnalysisType.Quantification);
                this.QuantifierServerIsStarted = false;
            }
        }

        public AnalysisServerInfo GetServerInfo(AnalysisType analysis_type)
        {
            return this.RemoteManager.GetServerInfo(analysis_type);
        }

        public RemoteState RegisterDevice(AnalysisType analysis_type, IDevice devie)
        {
            return this.RemoteManager.RegisterDevice(analysis_type, devie).Clone();
        }

        public RemoteState LoadData(AnalysisType analysis_type)
        {
            return this.RemoteManager.LoadModelData(analysis_type).Clone();
        }

        public RemoteSettings GetRemoteSettings(AnalysisType analysis_type)
        {
            return this.RemoteManager.GetSettings(analysis_type);
        }

        public byte[] GetValidationDocument(IdentModelClass model_class)
        {
            return this.RemoteManager.GetValidationDocument(model_class);
        }

        public byte[] GetAdditionalTestDocument(IdentModelClass model_class = null)
        {
            return this.RemoteManager.GetAdditionalTestDocument(model_class);
        }

        public byte[] GetLicense(AnalysisType analysis_type)
        {
            return this.RemoteManager.GetLicense(analysis_type);
        }

        public byte[] GetUpdateChanges()
        {
            return this.RemoteManager.GetIdentUpdateChanges();
        }

        private Version GetVersion(string value)
        {
            try
            {
                return new Version(this.VersionRegex.Match(value).Value);

            }
            catch (Exception)
            {
                return new Version("0.0");
            }
        }

        public object Analyse(AnalysisType analysis_type, Spectrum spectrum)
        {
            if (analysis_type == AnalysisType.Identification)
                return this.RemoteManager.Classify(spectrum);
             
            CannabisResult result = new CannabisResult(this.RemoteManager.Quantify(spectrum),                            
                                                       this.SubstancesCatalog.Substance.Samples);
            return result;                                     
        }

        public void DiscardResults()
        {
            this.RemoteManager.DiscardResults();
        }

        public Dictionary<string, byte[]> GetLogFiles(AnalysisType analysis_type)
        {
            return this.RemoteManager.GetLogFiles(analysis_type);
        }

        public AnalysisServerInfo CurrentServerInfo
        {
            get
            {
                if (this.SubstancesCatalog.AnalysisType == AnalysisType.None)
                    return null;

                if (this.SubstancesCatalog.AnalysisType == AnalysisType.Quantification)
                    return this.GetServerInfo(AnalysisType.Quantification);

                return this.GetServerInfo(AnalysisType.Identification);
            }
        }

        public Version ApoIdentVersion { get; private set; }

        private Regex VersionRegex { get; set; } = new Regex(@"\d+\.\d+");

        private bool IdentServerIsStarted { get; set; }
        private bool QuantifierServerIsStarted { get; set; }

        private RemoteManager RemoteManager { get; set; }
        private GlobalStates GlobalStates { get; set; }
    }
}
