using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;

using Harmony;

using GamecraftModdingAPI.Utility;
using GamecraftModdingAPI.Events;
using GamecraftModdingAPI.Tasks;

namespace GamecraftModdingAPI
{
    /// <summary>
    /// The main class of the GamecraftModdingAPI.
    /// Use this to initialize the API before calling it.
    /// </summary>
    public static class Main
    {
        private static HarmonyInstance harmony;

        public static bool IsInitialized { 
            get { return harmony != null; }
        }

        private static int referenceCount = 0;

        /// <summary>
        /// Initializes the GamecraftModdingAPI. 
        /// Call this as soon as possible after Gamecraft starts up.
        /// Ideally, this should be called from your main Plugin class's OnApplicationStart() method.
        /// </summary>
        public static void Init()
        {
            referenceCount++;
            if (referenceCount > 1) { return; }
            if (IsInitialized)
            {
                Logging.LogWarning("GamecraftModdingAPI.Main.Init() called but API is already initialized!");
                return;
            }
            Logging.MetaDebugLog($"Patching Gamecraft");
            var currentAssembly = Assembly.GetExecutingAssembly();
            harmony = HarmonyInstance.Create(currentAssembly.GetName().Name);
            harmony.PatchAll(currentAssembly);
            // init utility
            Logging.MetaDebugLog($"Initializing Utility");
            Utility.GameState.Init();
            // create default event emitters
            Logging.MetaDebugLog($"Initializing Events");
            EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.ApplicationInitialized, "GamecraftModdingAPIApplicationInitializedEventEmitter", false));
            EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.Menu, "GamecraftModdingAPIMenuActivatedEventEmitter", false));
            EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.MenuSwitchedTo, "GamecraftModdingAPIMenuSwitchedToEventEmitter", false));
            EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.Game, "GamecraftModdingAPIGameActivatedEventEmitter", false));
            EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.GameReloaded, "GamecraftModdingAPIGameReloadedEventEmitter", false));
            EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.GameSwitchedTo, "GamecraftModdingAPIGameSwitchedToEventEmitter", false));
            // init block implementors
            Logging.MetaDebugLog($"Initializing Blocks");
            Blocks.Movement.Init();
            Blocks.Rotation.Init();
            Blocks.Signals.Init();
            Blocks.Placement.Init();
            Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} initialized");
        }

        /// <summary>
        /// Shuts down & cleans up the GamecraftModdingAPI.
        /// Call this as late as possible before Gamecraft quits.
        /// Ideally, this should be called from your main Plugin class's OnApplicationQuit() method.
        /// </summary>
        public static void Shutdown()
        {
            if (referenceCount > 0) { referenceCount--; }
            if (referenceCount == 0)
            {
                if (!IsInitialized)
                {
                    Logging.LogWarning("GamecraftModdingAPI.Main.Shutdown() called but API is not initialized!");
                    return;
                }
                Scheduler.Dispose();
                var currentAssembly = Assembly.GetExecutingAssembly();
                harmony.UnpatchAll(currentAssembly.GetName().Name);
                harmony = null;
                Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} shutdown");
            }
        }
    }
}