// 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 Hiperscan.Spectroscopy;

namespace Hiperscan.Extensions.ApoIdent
{


    public class AppControl
    {
        public static readonly DateTime NO_DATE = DateTime.MinValue;

        public AppControl(IHost host, int main_thread_id)
        {
            this.Host = host;
            this.Host.DontShowInfoMessage = true;
            this.MainThreadId = main_thread_id;
            this.ProfileChangedMode = this.Host.ProfileChangedMode;

            this.ScanState = new ScanState();
            this.ProtocolState = new ProtocolState();
            this.FinderButtonState = new FinderButtonState();
            this.MeasuringProgressState = new MeasuringProgressState();

            this.QuitRequested = false;
            this.ConnectionSuccess = false;
            this.Busy = false;
            this.IsTopLevelWindow = false;

            this.SetBeforeMeasurement();

            if (this.MeasuringProgressState.IsProcessing)
                this.ScanState.DeleteFlag(ScanStates.IsNotMeasuring);
            else
                this.ScanState.SetFlag(ScanStates.IsNotMeasuring);
        }

        public void SetBeforeMeasurement()
        {
            this.CurrentProcessedSpectrum = null;
            this.NoMisIdentificationYet = true;
            this.CurrentReport = null;
            this.CreateNotMeasurableReport = false;
            this.NotMeasurableCreationDate = AppControl.NO_DATE;

            this.MeasurementProcessInterrupted = false;
            this.MeasuringProgressState.ResetFlags();

            this.ProtocolState.DeleteFlag(ProtocolStates.IdentificationResultExists);
            this.ProtocolState.SetFlag(ProtocolStates.ProtocolNotSaved);
            this.ProtocolState.DeleteFlag(ProtocolStates.ResultAdditionalTestCorrect);
        }

        public void SetNotMeasurable()
        {
            this.CreateNotMeasurableReport = true;
            this.NotMeasurableCreationDate = DateTime.Now;
            this.ProtocolState.SetFlag(ProtocolStates.IdentificationResultExists);
            this.ProtocolState.DeleteFlag(ProtocolStates.ResultAdditionalTestCorrect);
        }

        public void PrepareMeasurement()
        {
            this.CurrentProcessedSpectrum = null;
            this.CurrentReport = null;
            this.ProtocolState.DeleteFlag(ProtocolStates.IdentificationResultExists);
            this.ProtocolState.SetFlag(ProtocolStates.ProtocolNotSaved);
            this.ProtocolState.DeleteFlag(ProtocolStates.ResultAdditionalTestCorrect);
        }


        private bool is_top_level_window = false;
        public bool IsTopLevelWindow
        {
            get
            {
                return this.is_top_level_window;
            }
            set
            {
                this.is_top_level_window = value;
                if (this.is_top_level_window)
                {
                    this.ScanState.SetFlag(ScanStates.MainWindowIsTopLevel);
                    this.FinderButtonState.SetFlag(FinderButtonStates.MainWindowIsTopLevel);
                }
                else
                {
                    this.ScanState.DeleteFlag(ScanStates.MainWindowIsTopLevel);
                    this.FinderButtonState.DeleteFlag(FinderButtonStates.MainWindowIsTopLevel);
                }

            }
        }

        private bool quit_requested = false;
        public bool QuitRequested
        {
            get
            {
                return this.quit_requested;
            }
            set
            {
                this.quit_requested = value;
                if (this.quit_requested)
                {
                    this.ScanState.DeleteFlag(ScanStates.NoQuitRequested);
                    this.FinderButtonState.DeleteFlag(FinderButtonStates.NoQuitRequested);
                }
                else
                {
                    this.ScanState.SetFlag(ScanStates.NoQuitRequested);
                    this.FinderButtonState.SetFlag(FinderButtonStates.NoQuitRequested);
                }

            }
        }

        private bool connection_success = false;
        public bool ConnectionSuccess
        {
            get
            {
                return this.connection_success;
            }
            set
            {
                this.connection_success = value;
                if (this.connection_success == false)
                {
                    this.ScanState.DeleteFlag(ScanStates.ConnectionSuccess);
                    this.FinderButtonState.DeleteFlag(FinderButtonStates.ConnectionSuccess);
                }
                else
                {
                    this.ScanState.SetFlag(ScanStates.ConnectionSuccess);
                    this.FinderButtonState.SetFlag(FinderButtonStates.ConnectionSuccess);
                }
            }
        }

        private bool busy = false;
        public bool Busy
        {
            get
            {
                return this.busy;
            }
            set
            {
                this.busy = value;
                if (this.busy)
                {
                    this.ScanState.DeleteFlag(ScanStates.MainWindowIsNotBusy);
                    this.FinderButtonState.DeleteFlag(FinderButtonStates.MainWindowIsNotBusy);
                }
                else
                {
                    this.ScanState.SetFlag(ScanStates.MainWindowIsNotBusy);
                    this.FinderButtonState.SetFlag(FinderButtonStates.MainWindowIsNotBusy);
                }
            }
        }

        public MeasuringProgressState MeasuringProgressState { get; private set; }

        private bool substance_selected = false;
        public bool SubstanceSelected
        {
            get
            {
                return this.substance_selected;
            }
            set
            {
                this.substance_selected = value;
                if (this.substance_selected)
                    this.FinderButtonState.SetFlag(FinderButtonStates.SubstanceSelected);
                else
                    this.FinderButtonState.DeleteFlag(FinderButtonStates.SubstanceSelected);
            }
        }

        private bool create_not_measurable_report = false;
        public bool CreateNotMeasurableReport
        {
            get
            {
                return this.create_not_measurable_report;
            }
            set
            {
                this.create_not_measurable_report = value;
                if (this.create_not_measurable_report)
                    this.FinderButtonState.DeleteFlag(FinderButtonStates.SubstanceIsMeasurable);
                else
                    this.FinderButtonState.SetFlag(FinderButtonStates.SubstanceIsMeasurable);
            }
        }

        public bool ProgramExitCalled { get; set; } = false;


        public bool MeasurementProcessInterrupted { get; set; } = false;

        public bool ConnectionIsInitializing { get; set; } = false;
        public bool IsDisconnecting { get; set; } = false;

        public Spectrum CurrentProcessedSpectrum { get; set; } = null;
        public DateTime NotMeasurableCreationDate { get; set; } 

        public bool NoMisIdentificationYet {get; set; } = true;
        public Report.Generic CurrentReport { get; set; } = null;
        public ReportInfo CurrentReportInfo { get; set; } = null;

        public ProtocolState ProtocolState { get; set; }
        public ScanState ScanState { get; set; }
        public FinderButtonState FinderButtonState { get; set; }

        public IHost Host { get; private set; } = null;
        public int MainThreadId { get; private set; }
        public bool ProfileChangedMode { get; private set; } = false;


        public string ReportTestUser { get; set; }
        public string ReportPpn { get; set; }
        public string ReportBatch { get; set; }
        public string ReportSupplier { get; set; }
        public DateTime ReportExpiryDate { get; set; }
        public string ReportWeighingCorr { get; set; }
        public string ReportAdditionalText { get; set; }
        public string ReportCommon { get; set; }

        public void EnterGui(string guid)
        {
            if (guid == Guid.Empty.ToString())
                return;

            lock(ThreadSync)
            {
                lock (this.ThreadSync)
                {
                    this.ThreadSyncs.Add(guid, false);
                }
            }
        }

        public void LeaveGui(string guid)
        {
            if (guid == Guid.Empty.ToString())
                return;

            lock (ThreadSync)
            {
                this.ThreadSyncs[guid] = true;
            }
        }

        public void WaitForGuiUpdateFinished (string guid)
        {
            if (guid == Guid.Empty.ToString())
                return;

            for (; ; )
            {
                lock (ThreadSync)
                {
                    if (this.ThreadSyncs[guid] == true)
                    {
                        this.ThreadSyncs.Remove(guid);
                        break;
                    }
                }

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

        public bool IsGuiUpdating
        {
            get
            {
                bool value = false;
                lock (ThreadSync)
                {
                    value = this.ThreadSyncs.Count != 0;
                }

                return value;
            }
        }

        public object Transaction { get; set; } = new object();
        public object DeviceEventsSync { get; set; } = new object();

        public Dictionary<string, bool> ThreadSyncs { get; set; } = new Dictionary<string, bool>();
        private object ThreadSync { get; set; } = new object();
    }
}
