using NLog;
using ProgramLib.GUI.View;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Threading;

namespace ProgramLib
{
   internal class ProgramGuiManager : IDisposable
   {
      #region Private Members
      private Thread _guiManagerThread;
      private static NLog.ILogger _logger;
      private Dictionary<WINDOWS, Window> _windowDict = new Dictionary<WINDOWS, Window>();
      private ManualResetEvent _allGuiInitializedEvent = new ManualResetEvent(false);
      private bool _isDisposed = false;
      #endregion

      #region Public Members
      public enum WINDOWS
      {
         LIVE_DATA,
         IMPEDANCE_CHECK
      }
      #endregion

      /// <summary>
      /// constructor
      /// </summary>
      public ProgramGuiManager()
      {
         _logger = LogManager.GetCurrentClassLogger();
      }

      /// <summary>
		/// The Finalizer
      /// Do not call Dispose() in here
		/// </summary>
		~ProgramGuiManager()
      {
         _logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() ...");
      }

      public Window this[WINDOWS window]
      {
         get { return _windowDict[window]; }
      }

      /// <summary>
      /// Initialize all the GUIs
      /// </summary>
      public void Initialize()
      {
         _guiManagerThread = new Thread(new ThreadStart(GuiManagerThread));
         _guiManagerThread.SetApartmentState(ApartmentState.STA);
         _guiManagerThread.Start();

         _allGuiInitializedEvent.WaitOne();
      }

      private void GuiManagerThread()
      {
         _logger?.Debug($"{this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() is running...");

         // instantiate all the windows here
         _windowDict[WINDOWS.LIVE_DATA] = new LiveDataWindow();
         _windowDict[WINDOWS.IMPEDANCE_CHECK] = new ImpedanceCheckWindow();

         _allGuiInitializedEvent.Set();

         // Enter the event queue
         Dispatcher.Run();

         _logger?.Debug($"{this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() is exiting...");
      }

      /// <summary>
		/// Dispose of this object.
		/// </summary>
		public void Dispose()
      {
         _logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() ...");

         try
         {
            if (!_isDisposed)
            {
               _logger?.Debug($"{this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() disposing");

               _windowDict?.First().Value.Dispatcher.Invoke((Action)delegate
               {
                  // shut down all windows
                  foreach (var entry in _windowDict)
                  {
                     entry.Value.Close();
                  }
                  // kill the GuiManagerthread
                  Dispatcher.CurrentDispatcher.InvokeShutdown();
               });

               _isDisposed = true;
            }
         }
         catch (Exception)
         {
         }
      }
   }
}
