using System.Collections.Generic;
using Sandbox.ModAPI.Ingame;
using VRage.Game.ModAPI.Ingame.Utilities;
using System.Linq;

namespace IngameScript
{
    public partial class Program : MyGridProgram, IConsoleProgram
    {
        public MyIni Ini { get; private set; }
        public IConsole Console { get; private set; }

        private MyCommandLine _cli = new MyCommandLine();
        private Warehouse _warehouse;
        private Dictionary<string, Dock> _docks = new Dictionary<string, Dock>();

        public Program()
        {
            Ini = new MyIni();
            Console = new MainConsole(this, "Dock Loader");
            _warehouse = new Warehouse(Console);

            // Find all the blocks with a [dockLoader] config
            List<IMyTerminalBlock> blocks = new List<IMyTerminalBlock>();
            GridTerminalSystem.GetBlocksOfType(blocks, blockFilter);
            foreach (IMyTerminalBlock block in blocks)
            {
                Ini.TryParse(block.CustomData);
                if (Ini.Get("dockLoader", "warehouse").ToBoolean(false)) _warehouse.AddBlock(block, Ini);
                else
                {
                    string id = Ini.Get("dockLoader", "id").ToString();
                    if (id == "")
                    {
                        Console.Print($"Ignoring invalid block '{block.CustomName}'");
                        continue;
                    }

                    if (!_docks.ContainsKey(id)) _docks[id] = new Dock(id, Console);
                    _docks[id].AddBlock(block, Ini);
                }
            }

            // Remove any non-functional docks.
            foreach (Dock dock in _docks.Values.ToList())
            {
                if (!dock.Functional)
                {
                    Console.Print($"Dock '{dock.Id}' not fully configured, ignoring.");
                    _docks.Remove(dock.Id);
                }
            }

            Console.Print($"Found {_docks.Count} docks to manage.");

            Runtime.UpdateFrequency |= UpdateFrequency.Update100;
            Console.UpdateTickCount();
        }

        public void Main(string argument, UpdateType updateSource)
        {
            Console.UpdateTickCount();
            handleInput(argument);

            // Check on loading state
            int loadingCount = 0;
            bool timeout = _warehouse.Timeout;
            foreach (Dock dock in _docks.Values)
            {
                dock.Update();
                if (dock.Mode == DockMode.Loading)
                {
                    if (timeout) dock.Reset();
                    else loadingCount++;
                }
            }

            // This will decrement any loading timer, and switch to unloading mode when we do timeout.
            // It will also switch to unloading mode if we pass it a 0.
            if (updateSource.HasFlag(UpdateType.Update100)) _warehouse.Update(loadingCount);
        }

        private bool blockFilter(IMyTerminalBlock block)
        {
            return block.IsSameConstructAs(this.Me) && MyIni.HasSection(block.CustomData, "dockLoader");
        }

        private void handleInput(string argument)
        {
            if (argument == "") return;
            _cli.TryParse(argument);
            if (_cli.ArgumentCount != 2)
            {
                Console.Print("Must call script with exactly 2 arguments.");
                return;
            }

            string dockId = _cli.Argument(0).Trim().ToLower();
            string command = _cli.Argument(1).Trim().ToLower();

            if (!_docks.ContainsKey(dockId))
            {
                Console.Print($"Unknown dock '{dockId}'");
                return;
            }

            switch (command)
            {
                case "load":
                    _docks[dockId].StartLoading();
                    _warehouse.StartLoading();
                    break;
                case "unload":
                    _docks[dockId].StartUnloading();
                    break;
                case "reset":
                    _docks[dockId].Reset();
                    break;
                default:
                    Console.Print($"Unknown command '{command}'");
                    break;
            }

        }
    }
}