// 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.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Gtk;
using Hiperscan.Extensions.ApoIdent.Widgets;
using Hiperscan.Extensions.ApoIdentCommon;
using Hiperscan.SGS;
using Hiperscan.SGS.Common;
using Hiperscan.Spectroscopy.IdentModule;
using Hiperscan.Unix;

namespace Hiperscan.Extensions.ApoIdent
{
    public partial class ApoIdentApplication
    {
        public static ApoIdentApplication Start(IHost host)
        {
            return new ApoIdentApplication(host);
        }

        private ApoIdentApplication(IHost host)
        {
            this.CheckForRunningInstances();

            if (ApoIdentApplication.CurrentInstance != null)
            {
                ApoIdentApplication.CurrentInstance.MainWindow.Present();
                return;
            }

            Console.WriteLine("Call ApoIdentApplication.ctor...");

            ApoIdentApplication.CurrentInstance = this;

            this.InitStateComponents(host);
            this.WriteSpecialEnvironmentVariables();
            this.InitConfig();

            if (ApoIdentExecutionModeRecognizer.GetMode() == ApoIdentExecutionMode.Windows)
                this.StartAutomaticSoftwareLauncherWindows();

            this.InitDataBackup();
            this.InitServerClientInstance();
            this.InitSubstanceManagement();

            this.InitGuiDesigner();
            this.DrawGui();
            this.InitScanner();
            this.SplashScreen = new SplashScreen(this.MainWindow, this.GuiDesignerData.SplashScreen);
            this.SplashScreen.InterruptingPressed += this.OnInterruptingWarmupPressed;

            try
            {
                Task.Run(() =>
                {
                    try
                    {
                        ReportInfo.ConvertToMetaData2_0(this.Config);
                        this.InitConnection();
                        this.CheckForImportantCustomerAdvice();
                        this.CheckSettings();
                    }
                    catch (Exception ex)
                    {
                        string message = String.Format(Catalog.GetString("Error while initializing Apo-Ident: {0}"), ex.Message);
                        this.Update(ApoIdentApplicationState.ShowErrorDialogWithServiceDialog, message, ex);
                    }

                });
            }
            catch(Exception ex)
            {
                string message = String.Format(Catalog.GetString("Error while initializing Apo-Ident: {0}"), ex.Message);
                this.Update(ApoIdentApplicationState.ShowErrorDialogWithServiceDialog, message, ex);
            }
        }


        private void InitGuiDesigner()
        {
            this.GuiDesignerData = new GuiDesigner();
            this.GuiDesignerData.BgYPositionChanged += this.OnBgYPositionChanged;
            this.GuiDesignerData.MeasuringButtonSizeChanged += this.OnMeasuringButtonSizeChanged;
            this.GuiDesignerData.MeasuringAlignmentChanged += this.OnMeasuringAlignemtChanged;

            this.GuiDesignerData.OuterLineWidthChanged += this.OnOuterLineWidthChanged;
            this.GuiDesignerData.MenuLineWidthChanged += this.OnMenuLineWidthChanged;
            this.GuiDesignerData.StatebarTopLineWidthChanged += this.OnStatebarTopWidthChanged;
            this.GuiDesignerData.StatebarLeftLineWidthChanged += this.OnStatebarLeftWidthChanged;
            this.GuiDesignerData.StatebarRightLineWidthChanged += this.OnStatebarRightWidthChanged;
        }


        private void WriteSpecialEnvironmentVariables()
        {
            string path_env = "PATH=" + Environment.GetEnvironmentVariable("PATH");
            string mono_env = "MONO_PATH=" + Environment.GetEnvironmentVariable("MONO_PATH");
            string mono_config = "MONO_CFG_DIR=" + Environment.GetEnvironmentVariable("MONO_CFG_DIR");
            string lang = "LANG=" + Environment.GetEnvironmentVariable("LANG");

            Console.WriteLine("Apo-Ident-Version: {0}", Plugin.version);
            Console.WriteLine(path_env);
            Console.WriteLine(mono_env);
            Console.WriteLine(mono_config);
            Console.WriteLine(lang);
        }

        private void InitStateComponents(IHost host)
        {
            this.Control = new AppControl(host, Thread.CurrentThread.ManagedThreadId);
            this.Control.ScanState.StateChanged += this.OnScanStateChanged;
            this.Control.FinderButtonState.StateChanged += this.OnFinderButtonStateChanged;
            this.Control.MeasuringProgressState.StateChanged += this.OnMeasurementProgressStateChanged;
        }

        private void CheckForImportantCustomerAdvice()
        {
            ImportantCustomerInfo.InfoShown += (sender, e) =>
            {
                if (this.Config.Profiles.Current == null)
                {
                    ImportantCustomerInfo.MarkAsRead();
                    return;
                }

                this.Update(ApoIdentApplicationState.ImportantCustomerInfo, sender as string);
            };

            ImportantCustomerInfo.ShowInfo();
        }

        private void CheckForRunningInstances()
        {
            try
            {
                if (Environment.OSVersion.Platform != PlatformID.Win32NT)
                    return;

                if (Plugin.replace_gui == false)
                    return;


                System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcessesByName("QuickStep");
                Console.WriteLine("Found {0} processes", processes.Length);



                System.Diagnostics.Process current_process = System.Diagnostics.Process.GetCurrentProcess();

                DateTime date = DateTime.MaxValue;
                System.Diagnostics.Process winner = null;

                foreach (System.Diagnostics.Process process in processes)
                {
                    if (process.StartTime < date)
                    {
                        date = process.StartTime;
                        winner = process;
                    }

                    if (current_process.Id == process.Id)
                        Console.WriteLine("This process started at: {0}", process.StartTime);
                    else
                        Console.WriteLine("The other process started at: {0}", process.StartTime);
                }

                if (current_process.Id != winner.Id)
                    this.BringWindowToFront(true);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error while checking instances: {0}",  ex);
            }
        }

        private void BringWindowToFront(bool close_app)
        {
            if (Environment.OSVersion.Platform != PlatformID.Win32NT)
                return;

            try
            {
                string file = Assembly.GetExecutingAssembly().Location;
                file = Path.GetDirectoryName(file);
                file = Path.Combine(file, "ShowApoIdent.exe");
                System.Diagnostics.Process bring_to_front = new System.Diagnostics.Process();
                bring_to_front.StartInfo.FileName = file;
                bring_to_front.StartInfo.CreateNoWindow = true;
                bring_to_front.StartInfo.UseShellExecute = false;
                bring_to_front.Start();
                bring_to_front.WaitForExit();

                if (close_app)
                    Plugin.host.Quit();
            }
            catch (Exception)
            {
                if (close_app)
                    Environment.Exit(-2);
            }
        }

        private static ApoIdentApplication CurrentInstance { get; set; }
    }
}