// Created with MonoDevelop
//
//    QuickStep: Acquire, view and identify spectra 
//    Copyright (C) 2022, 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 Hiperscan.SGS;
using Hiperscan.Unix;
using Hiperscan.ApoIdentCore.ActionControl;
using Hiperscan.ApoIdentCore.GuiControl;
using Hiperscan.ApoIdentCore.Enums;
using Hiperscan.ApoIdentCommon.ApoConfig;
using Hiperscan.GuiExtensions;
using Hiperscan.GuiExtensions.Dialog;
using Hiperscan.AnalysisModule;
using Hiperscan.AnalysisModule.Remoting;
using Hiperscan.AnalysisModule.Identification;

namespace Hiperscan.ApoIdentCore
{
    public partial class AppControl
    {
        private void Connect()
        {
            try
            {
                if (this.InitConnection() == false)
                    return;

                this.InitConnectionSetProfiles();

                if (this.InitConnectionDevice() == false)
                    return;

                if (this.InitConnectionCheckInstallations() == false)
                    return;

                if (this.InitConnectionAnalysisModules() == false)
                    return;

                if (this.InitConnectionFinder() == false)
                    return;

                if (this.InitConnectionWarmup() == false)
                    return;

                this.InitConnectionExit();
                this.InitConnectionUpdateDocu();
                this.InitNotMeasurableSubstances();
                this.InitConnectionSuccess();
                this.InitConnectionRemindForUpdate(AnalysisType.Identification);
                this.InitConnectionRemindForUpdate(AnalysisType.Quantification);
                this.InitConnectionArchive();
            }
            catch (Exception ex)
            {
                this.InitConnectionError(ex);
            }
            finally
            {
                UpdateArgs arg = new UpdateArgs();
                arg.StateBarValues = new StateBarValues();
                arg.StateBarValues.ProgressVisible = false;
                this.UpdateGuiNeeded?.Invoke(arg);
                this.SetReadyForSubstanceInput();
                this.MeasuringManager.AddDeviceListEvents();
            }
        }

        private bool InitConnection()
        {
            if (this.GlobalStates.QuitRequested)
                return false;

            if (this.GlobalStates.ConnectionSuccess && this.MeasuringManager.Finder.Device.Info.IsRemote == false)
                return false;

            this.GlobalStates.ConnectionSuccess = false;
            this.GlobalStates.HasNotMeasurableData = false;
            this.SubstanceManager.ResetAvailableModules();
            this.SubstanceManager.Reset();
            this.MeasuringManager.RemoveDeviceListEvents();

            ApoActionArg action_arg = new ApoActionArg();
            action_arg.Action = ApoActionType.CloseWindows;
            this.ActionNeeded?.Invoke(action_arg);

            Console.WriteLine("Init connection device - analysis module ...");

            this.GlobalStates.Busy = true;
            UpdateArgs arg = UpdateArgs.GetReloadAllArg();
            arg.StateBarValues = new StateBarValues();
            arg.StateBarValues.State = String.Empty;
            arg.StateBarValues.DeviceInfos = String.Empty;
            arg.AnimationType = ProgramState.Working;
            arg.SplashScreenState = SplashScreenState.Start;
            arg.CursorState = CursorState.Busy;
            this.UpdateGuiNeeded?.Invoke(arg);

            System.Threading.Thread.Sleep(1000);

            return true;
        }

        private bool InitConnectionCheckInstallations()
        {
            Console.WriteLine("Check installations analysis servers ....");
            this.ShowCurrentState(Catalog.GetString("Checking server installations"));


            string header = String.Empty;
            string message = String.Empty;

            bool is_im_available = this.SubstanceManager.IsModuleInstalled(AnalysisType.Identification);
            if (is_im_available == false)
                is_im_available = this.SubstanceManager.GetServerInfo(AnalysisType.Identification) != null;

            bool is_qm_available = false;                   
            if (this.MeasuringManager.Finder.IsES20)
            {
                is_qm_available = this.SubstanceManager.IsModuleInstalled(AnalysisType.Quantification);
                if (is_qm_available == false)
                    is_qm_available = this.SubstanceManager.GetServerInfo(AnalysisType.Quantification) != null;

                header = Catalog.GetString("No analysis module found.");
                message = Catalog.GetString("Currently there is no database module installed. This component is required to perform substance analyses on your local computer. Please also check if a compatible version is installed.");
            }
            else
            {
                header = Catalog.GetString("No IdentModule found.");
                message = Catalog.GetString("Currently there is no IdentModule installed. To proceed, please install the IdentModule.");
            }


            if (is_im_available == false && is_qm_available == false)
            {
                this.InitConnectionReset();

                UpdateArgs arg = UpdateArgs.GetReloadAllArg();
                arg.CursorState = CursorState.Normal;
                arg.AnimationType = ProgramState.ServerConnectionFailed;
                arg.SplashScreenState = SplashScreenState.Abort;
                arg.DialogArgs.StandardDialogType = StandardDialogType.ErrorWithServiceMessage;
                arg.DialogArgs.Title = header;
                arg.DialogArgs.Message = message;
                this.UpdateGuiNeeded?.Invoke(arg);
            }
            else
            {
                this.GlobalStates.ResetAvailableModules();

                if (is_im_available)
                    this.GlobalStates.AddInstallation(true);

                if (is_qm_available)
                    this.GlobalStates.AddInstallation(false);
            }

            return is_im_available || is_qm_available;
        }



        private bool InitConnectionAnalysisModules()
        {
            foreach(AnalysisType analysis_type in Enum.GetValues(typeof(AnalysisType)))
            {
                if (analysis_type != AnalysisType.Identification && 
                    analysis_type != AnalysisType.Quantification)
                    continue;

                if (analysis_type == AnalysisType.Identification)
                {
                    if (this.GlobalStates.IsIdentModuleAvailable == false)
                        continue;
                }
                else
                {
                    if (this.GlobalStates.IsQuantifierModuleAvailable == false)
                        continue;
                }

                if (analysis_type == AnalysisType.Quantification &&
                    this.MeasuringManager.Finder.IsES20 == false)
                    continue;

                if (this.InitConnectionStartServer(analysis_type) == false)
                    return false;

                if (this.InitConnectionCheckVersion(analysis_type) == false)
                    return false;

                if (this.InitConnectionCheckReleaseState(analysis_type) == false)
                    return false;

                if (this.InitConnectionRegistration(analysis_type) == false)
                    return false;

                if (this.InitConnectionLoadData(analysis_type) == false)
                    return false;
            }

            return this.InitConnectionCheckLoadedData();
        }

        private bool InitConnectionStartServer(AnalysisType analysis_type)
        {
            Console.WriteLine("Starting server for {0} ....", analysis_type.GetProductName());
            this.ShowCurrentState(String.Format(Catalog.GetString("Starting {0}"), analysis_type.GetProductName()));

            RemoteState state = this.SubstanceManager.StartServer(analysis_type);

            if (state.NoError == false)
            {
                string header = String.Format(Catalog.GetString("No server started."));

                string message = String.Format(Catalog.GetString("The server for {0} could not be started: {1}"),
                                               analysis_type.GetProductName(),
                                               state.Exception.Message);

                this.InitConnectionReset();

                UpdateArgs arg = UpdateArgs.GetReloadAllArg();
                arg.CursorState = CursorState.Normal;
                arg.AnimationType = ProgramState.ServerConnectionFailed;
                arg.SplashScreenState = SplashScreenState.Abort;
                arg.DialogArgs.StandardDialogType = StandardDialogType.ErrorWithServiceMessage;
                arg.DialogArgs.Title = header;
                arg.DialogArgs.Message = message;
                arg.DialogArgs.Exception = state.Exception;
                this.UpdateGuiNeeded?.Invoke(arg);
            }

            return state.NoError;        
        }

        private bool InitConnectionCheckVersion(AnalysisType analysis_type)
        {
            Console.WriteLine("Check assembly version for {0} ....", analysis_type.GetProductName());
            this.ShowCurrentState(String.Format(Catalog.GetString("Checking {0} version"), analysis_type.GetProductName()));

            string tmp = this.SubstanceManager.GetServerInfo(analysis_type).Version.ShortAssemblyVersion;
            Version module_version = new Version(tmp);

            if (module_version != this.SubstanceManager.ApoIdentVersion)
            {
                string header = String.Format(Catalog.GetString("Incompatible {0} version."), analysis_type.GetProductName());

                string message = String.Format(Catalog.GetString("The installed version of the {1} is not compatible. Please install the version {0}.x or deinstall the current version."),
                                               this.SubstanceManager.ApoIdentVersion,
                                               analysis_type.GetProductName());

                this.InitConnectionReset(analysis_type);

                UpdateArgs arg = UpdateArgs.GetReloadAllArg();
                arg.CursorState = CursorState.Normal;
                arg.AnimationType = ProgramState.ServerConnectionFailed;
                arg.SplashScreenState = SplashScreenState.Abort;
                arg.DialogArgs.StandardDialogType = StandardDialogType.ErrorWithServiceMessage;
                arg.DialogArgs.Title = header;
                arg.DialogArgs.Message = message;
                this.UpdateGuiNeeded?.Invoke(arg);
                return false;
            }

            return true;
        }

        private bool InitConnectionCheckReleaseState(AnalysisType analysis_type)
        {
            Console.WriteLine("Check release state for {0} ....", analysis_type.GetProductName());
            this.ShowCurrentState(String.Format(Catalog.GetString("Checking {0} state"), analysis_type.GetProductName()));

            bool is_released = this.SubstanceManager.GetServerInfo(analysis_type).IsRelease;

            if (is_released == false)
            {
                string header = String.Format(Catalog.GetString("Unreleased {0} version."),
                                              analysis_type.GetProductName());

                string message = String.Format(Catalog.GetString("The installed version of the {0} is a test version. "),
                                               analysis_type.GetProductName());

                this.InitConnectionReset(analysis_type);

                UpdateArgs arg = UpdateArgs.GetReloadAllArg();
                arg.CursorState = CursorState.Normal;
                arg.AnimationType = ProgramState.ServerConnectionFailed;
                arg.SplashScreenState = SplashScreenState.Abort;
                arg.DialogArgs.StandardDialogType = StandardDialogType.ErrorWithServiceMessage;
                arg.DialogArgs.Title = header;
                arg.DialogArgs.Message = message;
                this.UpdateGuiNeeded?.Invoke(arg);
            }
            else
            {
                if (analysis_type == AnalysisType.Identification)
                    this.GlobalStates.AddInstallation(true);
                else
                    this.GlobalStates.AddInstallation(false);
            }

            return is_released;
        }

        private bool InitConnectionRegistration(AnalysisType analysis_type)
        {
            Console.WriteLine("Register device at {0} ....", analysis_type.GetProductName());
            this.ShowCurrentState(String.Format(Catalog.GetString("Registering device at {0}"), analysis_type.GetProductName()));


            RemoteState state = this.SubstanceManager.RegisterDevice(analysis_type,this.MeasuringManager.Finder.Device);

            if (state.NoError == false)
            {
                string header = String.Format(Catalog.GetString("No models loaded from {0}."),
                                              analysis_type.GetProductName());

                string message = String.Format(Catalog.GetString("Registration for device {0} at {1} failed: {2}"),
                                               this.MeasuringManager.Finder.Serial,
                                               analysis_type.GetProductName(),
                                               state.Exception.Message);

                this.InitConnectionReset();

                UpdateArgs arg = UpdateArgs.GetReloadAllArg();
                arg.CursorState = CursorState.Normal;
                arg.AnimationType = ProgramState.DeviceRegistratopnFailed;
                arg.SplashScreenState = SplashScreenState.Abort;
                arg.DialogArgs.StandardDialogType = StandardDialogType.ErrorWithServiceMessage;
                arg.DialogArgs.Title = header;
                arg.DialogArgs.Message = message;
                arg.DialogArgs.Exception = state.Exception;
                this.UpdateGuiNeeded?.Invoke(arg);
            }

            return state.NoError;
        }

        private bool InitConnectionLoadData(AnalysisType analysis_type)
        {
            Console.WriteLine("Loading data from {0} ....", analysis_type.GetProductName());
            this.ShowCurrentState(String.Format(Catalog.GetString("Loading data from {0}"), analysis_type.GetProductName()));


            RemoteState state = this.SubstanceManager.LoadData(analysis_type);

            if (state.NoError == false)
            {
                string header = String.Format(Catalog.GetString("No models loaded from {0}."),
                                              analysis_type.GetProductName());

                string message = String.Format(Catalog.GetString("Loading {0} failed: {1}"),
                                               analysis_type.GetProductName(),
                                               state.Exception.Message);

                this.InitConnectionReset();

                UpdateArgs arg = UpdateArgs.GetReloadAllArg();
                arg.CursorState = CursorState.Normal;
                arg.AnimationType = ProgramState.ServerConnectionFailed;
                arg.SplashScreenState = SplashScreenState.Abort;
                arg.DialogArgs.StandardDialogType = StandardDialogType.ErrorWithServiceMessage;
                arg.DialogArgs.Title = header;
                arg.DialogArgs.Message = message;
                arg.DialogArgs.Exception = state.Exception;
                this.UpdateGuiNeeded?.Invoke(arg);
            }

            return state.NoError;
        }

        private bool InitConnectionCheckLoadedData()
        {
            Console.WriteLine("Check loaded data ....");
            this.ShowCurrentState(Catalog.GetString("Checking loaded models"));

            bool has_data = this.SubstanceManager.SubstancesCatalog.AllModelClasses.Count > 0;
                  
            if (has_data == false)
            {
                string header = Catalog.GetString("No models loaded.");

                string message = String.Format(Catalog.GetString("No models could be found for device {0}"),
                                               this.MeasuringManager.Finder.Serial);

                this.InitConnectionReset();

                UpdateArgs arg = UpdateArgs.GetReloadAllArg();
                arg.CursorState = CursorState.Normal;
                arg.AnimationType = ProgramState.ServerConnectionFailed;
                arg.SplashScreenState = SplashScreenState.Abort;
                arg.DialogArgs.StandardDialogType = StandardDialogType.ErrorWithServiceMessage;
                arg.DialogArgs.Title = header;
                arg.DialogArgs.Message = message;
                this.UpdateGuiNeeded?.Invoke(arg);
            }

            return has_data;
        }

        private bool InitConnectionDevice()
        {
            Console.WriteLine("\tInitializing instrument ...");
            this.ShowCurrentState(Catalog.GetString("Initialising device"));

            bool success = this.MeasuringManager.Finder.InitDevice();

            if (success == false)
            {
                this.InitConnectionReset();

                UpdateArgs arg = UpdateArgs.GetReloadAllArg();
                arg.CursorState = CursorState.Normal;
                arg.AnimationType = ProgramState.DeviceConnectionFailed;
                arg.SplashScreenState = SplashScreenState.Abort;
                arg.DialogArgs.StandardDialogType = StandardDialogType.ErrorWithServiceMessage;
                arg.DialogArgs.Title = this.MeasuringManager.Finder.ErrorTitle;
                arg.DialogArgs.Message = this.MeasuringManager.Finder.ErrorMessage;
                arg.DialogArgs.Exception = this.MeasuringManager.Finder.Exception;
                this.UpdateGuiNeeded?.Invoke(arg);
            }

            this.SaveConfig();

            return success;
        }

        private bool InitConnectionFinder()
        {
            Console.WriteLine("\tInitializing Finder ...");
            this.ShowCurrentState(Catalog.GetString("Initialising Finder"));


            bool success = this.MeasuringManager.Finder.InitFinder();
            if (success == false)
            {
                this.InitConnectionReset();

                UpdateArgs arg = UpdateArgs.GetReloadAllArg();
                arg.CursorState = CursorState.Normal;
                arg.AnimationType = ProgramState.DeviceConnectionFailed;
                arg.SplashScreenState = SplashScreenState.Abort;
                arg.DialogArgs.StandardDialogType = StandardDialogType.ErrorWithServiceMessage;
                arg.DialogArgs.Title = this.MeasuringManager.Finder.ErrorTitle;
                arg.DialogArgs.Message = this.MeasuringManager.Finder.ErrorMessage;
                arg.DialogArgs.Exception = this.MeasuringManager.Finder.Exception;
                this.UpdateGuiNeeded?.Invoke(arg);
            }

            return success;
        }

        private bool InitConnectionWarmup()
        {
            Console.WriteLine("\tWarm-up ...");
            this.ShowCurrentState(Catalog.GetString("Checking temperature"));


            bool success = this.MeasuringManager.Finder.DeviceWarmup();
            if (success == false)
            {
                this.MeasuringManager.Finder.Reset();
                this.GlobalStates.Busy = false;
                this.SubstanceManager.StopServers();

                UpdateArgs arg = UpdateArgs.GetReloadAllArg();
                arg.CursorState = CursorState.Normal;
                arg.AnimationType = ProgramState.DeviceConnectionFailed;
                arg.SplashScreenState = SplashScreenState.Abort;
                arg.DialogArgs.StandardDialogType = StandardDialogType.ErrorWithServiceMessage;
                arg.DialogArgs.Title = this.MeasuringManager.Finder.ErrorTitle;
                arg.DialogArgs.Message = this.MeasuringManager.Finder.ErrorMessage;
                arg.DialogArgs.Exception = this.MeasuringManager.Finder.Exception;
                this.UpdateGuiNeeded?.Invoke(arg);
            }

            return success;
        }

        private void InitConnectionSetProfiles()
        {
            foreach (ProfileSettings profile in this.ProfileManager.AllProfiles.Values)
                profile.LoadCacheData(false);
        }

        private void InitConnectionUpdateDocu()
        {
            bool is_es20 = this.MeasuringManager.Finder.IsES20;
            this.SubstanceManager.LoadRemotePdfs(AnalysisType.Identification, is_es20);
            this.SubstanceManager.LoadRemotePdfs(AnalysisType.Quantification, is_es20);
        }


        private void InitConnectionSuccess()
        {
            if (this.ProfileManager.CurrentProfile != null)
                this.MeasuringManager.Finder.UpdateReferencingDir(this.ProfileManager.CurrentProfile);

            this.MeasuringManager.Finder.DeviceReadyState = Catalog.GetString("Ready");
            this.SaveConfig();
            this.GlobalStates.ConnectionSuccess = true;
            this.GlobalStates.Busy = false;

            UpdateArgs arg = UpdateArgs.GetReloadAllArg();
            arg.CursorState = CursorState.Normal;
            arg.SplashScreenState = SplashScreenState.Finished;
            arg.StateBarValues = new StateBarValues();
            arg.StateBarValues.State = Catalog.GetString("Ready");
            this.UpdateGuiNeeded?.Invoke(arg);
        }

        private void InitConnectionExit()
        {
            if (this.MeasuringManager.Finder.QuitRequested)
            {
                UpdateArgs arg = new UpdateArgs();
                arg.SplashScreenState = SplashScreenState.Finished;
                this.UpdateGuiNeeded(arg);
                this.Exit(false);
            }
        }

        private void InitNotMeasurableSubstances()
        {
            this.GlobalStates.HasNotMeasurableData = false;

            if (this.MeasuringManager.Finder.QuitRequested)
                return;

            if (this.GlobalStates.IsOnlyQuantifierModuleAvailable == true)
                return;
            
            foreach (ProfileSettings profile in this.ProfileManager.AllProfiles.Values)
            {
                IdentModelClass tmp = this.SubstanceManager.SubstancesCatalog.NotMeasurableModelClassFromServer;
                profile.ModelExtension.Add(tmp, profile.ModelClassExtensionFile);
                if (profile.HasSubstances)
                    this.GlobalStates.HasNotMeasurableData = true;
            }

            IdentModelClass model_class = this.ProfileManager.CurrentProfile?.ModelExtension.ModelClass;
            this.SubstanceManager.SubstancesCatalog.RefreshUserDefinedSubstances(model_class);
        }

        private void InitConnectionRemindForUpdate(AnalysisType analysis_type)
        {
            if (analysis_type == AnalysisType.Identification && this.GlobalStates.IsIdentModuleAvailable == false)
                return;

            if (analysis_type == AnalysisType.Quantification && this.GlobalStates.IsQuantifierModuleAvailable == false)
                return;

            RemoteSettings settings = this.SubstanceManager.GetRemoteSettings(analysis_type);

            if (settings.ReleaseExpirationTime < DateTime.Now)
            {
                UpdateArgs arg = new UpdateArgs();
                arg.DialogArgs.ApoDialogType = ApoDialogType.RemindForUpdate;
                arg.DialogArgs.AnalysisType = analysis_type;
                this.UpdateGuiNeeded?.Invoke(arg);

                if (arg.DialogArgs.DontShowAgain == true)
                    settings.ReleaseExpirationTime = DateTime.Now.AddMonths(1);
            }
        }

        private void InitConnectionArchive()
        {
            this.PharmacyManager.CheckArchive();
        }

        private void InitConnectionError(Exception ex)
        {
            this.InitConnectionReset();
            this.GlobalStates.Busy = false;
            this.SubstanceManager.StopServers();

            UpdateArgs arg = UpdateArgs.GetReloadAllArg();
            arg.SplashScreenState = SplashScreenState.Abort;
            arg.CursorState = CursorState.Normal;
            arg.DialogArgs.StandardDialogType = StandardDialogType.ErrorWithServiceMessage;
            arg.DialogArgs.Title = Catalog.GetString("Error");
            arg.DialogArgs.Message = String.Format(Catalog.GetString("Error initialising Apo-Ident: {0}"), ex.Message);
            arg.DialogArgs.Exception = ex;
            this.UpdateGuiNeeded?.Invoke(arg);
        }

        private void InitConnectionReset(AnalysisType analysis_type = AnalysisType.None)
        {
            this.SubstanceManager.Clear();
            this.InitNotMeasurableSubstances();
            this.SubstanceManager.StopServers();
            this.MeasuringManager.Finder.Reset();
            this.GlobalStates.Busy = false;
            this.GlobalStates.RemoveInstallation(analysis_type);
        }

        private void OnDeviceAdded(object sender, EventArgs e)
        {
            System.Threading.Tasks.Task.Run(() =>
            {
                if (this.ProgramSync.IsCriticalZoneEntered == false)
                {
                    this.ProgramSync.EnterCriticialZone();
                    this.Connect();
                    this.ProgramSync.LeaveCriticalZone();
                }
            });
        }

        private void ShowCurrentState(string state, int delay = 500)
        {
            UpdateArgs args = new UpdateArgs();
            args.StateBarValues = new StateBarValues();
            args.StateBarValues.State = state;
            this.UpdateGuiNeeded?.Invoke(args);

            System.Threading.Thread.Sleep(delay);
        }

        private void OnDeviceRemoved(object sender, EventArgs e)
        {
            System.Threading.Tasks.Task.Run(() =>
            {
                this.ProgramSync.EnterCriticialZone();
                this.RemoveDevice();
                this.ProgramSync.LeaveCriticalZone();
            });
        }

        private void RemoveDevice()
        {
            if (this.GlobalStates.QuitRequested == true)
                return;

            if (this.GlobalStates.ConnectionSuccess == false)
                return;

            ApoActionArg action_arg = new ApoActionArg();
            action_arg.Action = ApoActionType.CloseWindows;
            this.ActionNeeded?.Invoke(action_arg);


            this.Disconnect();
            this.GlobalStates.Busy = false;

            UpdateArgs arg = new UpdateArgs();
            arg.DialogArgs.StandardDialogType = StandardDialogType.ErrorWithServiceMessage;
            arg.DialogArgs.Title = Catalog.GetString("Device removed");
            arg.DialogArgs.Message = Catalog.GetString("Device is not connected. Please check in the QuickStep software if the device can be found. You can find these settings on the left side at the field called \"Spectrometer\".");


            arg.CursorState = CursorState.Normal;
            arg.AnimationType = ProgramState.ConnectionLost;

            this.UpdateGuiNeeded?.Invoke(arg);

            this.SetReadyForSubstanceInput();
        }

        private void OnConnectionSettingsChanged(object sender, EventArgs e)
        {
            System.Threading.Tasks.Task.Run(() =>
            {
                this.ProgramSync.EnterCriticialZone();

                bool continue_action = true;

                if (this.GlobalStates.ConnectionSuccess && this.MeasuringManager.Finder.Device.Info.IsRemote == false)
                    continue_action = false;

                if (this.GlobalStates.QuitRequested == true)
                    continue_action = false;

                if (this.IdentModuleSettings.HasChanges == true)
                    continue_action = true;


                if (continue_action)
                {
                    this.Disconnect();
                    this.Connect();
                }

                this.ProgramSync.LeaveCriticalZone();
            });
        }

        private void Disconnect()
        {
            this.ProtocolManager.Clear();
            this.ResultManager.Clear();
            this.MeasuringManager.Clear();
            this.SpecimenManager.Clear();
            this.SubstanceManager.Clear();
            this.PharmacyManager.Clear();
            this.GlobalStates.ConnectionSuccess = false;

            this.SubstanceManager.StopServers();
            this.InitNotMeasurableSubstances();

            UpdateArgs arg = UpdateArgs.GetReloadAllArg();
            arg.StateBarValues = new StateBarValues();
            arg.StateBarValues.DeviceInfos = String.Empty;

            this.UpdateGuiNeeded?.Invoke(arg);
        }
    }
}
