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

namespace IngameScript
{
    public partial class Program : MyGridProgram
    {
        private Dictionary<string, Airlock> _airlocks;
        private List<IEnumerator<bool>> _jobs;

        private int _tickCount = 0;
        private MyCommandLine _cli;
        private Console _console;
        private MyIni _ini;

        public Program()
        {
            _ini = new MyIni();
            _console = new Console(this, _ini);
            _cli = new MyCommandLine();
            _jobs = new List<IEnumerator<bool>>();
            _airlocks = new Dictionary<string, Airlock>();

            List<IMyTerminalBlock> airlockBlocks = new List<IMyTerminalBlock>();
            GridTerminalSystem.GetBlocksOfType(airlockBlocks, block => MyIni.HasSection(block.CustomData, "airlock"));
            IMyAirVent referenceVent = null;
            foreach (IMyTerminalBlock block in airlockBlocks)
            {
                _ini.TryParse(block.CustomData, "airlock");

                // TODO: redundant reference vents would be awesome. Everyone loves redundancy
                if (block is IMyAirVent && _ini.Get("airlock", "reference").ToBoolean())
                {
                    if (referenceVent != null) {
                        _console.Print("Found multiple reference vents. Only the first one will be used.");
                        continue;
                    }

                    referenceVent = block as IMyAirVent;
                    _console.Print($"Found reference vent {block.CustomName}.");
                    continue;
                }

                string airlockName = _ini.Get("airlock", "id").ToString();
                if (!_airlocks.ContainsKey(airlockName))
                {
                    _airlocks[airlockName] = new Airlock(_ini, _console, airlockName);
                }

                _airlocks[airlockName].AddBlock(block);
            }

            if (referenceVent != null) foreach (Airlock airlock in _airlocks.Values) { airlock.ReferenceVent = referenceVent; }

            _console.Print($"Found {_airlocks.Count} airlocks.");
            _console.PrintLower($"Airlock Controller\nTotal Ticks: 0");
        }

        public void Main(string argument, UpdateType updateSource)
        {
            _console.PrintLower($"Airlock Controller\nTotal Ticks: {++_tickCount}");

            if (updateSource == UpdateType.Trigger || updateSource == UpdateType.Terminal)
            {
                _cli.TryParse(argument);
                if (_cli.ArgumentCount == 0) { _console.Print("You must provide an airlock ID."); }
                else
                {
                    string airlockName = _cli.Argument(0);
                    if (!_airlocks.ContainsKey(airlockName)) _console.Print($"Airlock ID '{airlockName}' not found.");
                    else if (!_airlocks[airlockName].Functional) _console.Print($"Airlock '{airlockName}' is not functional.");
                    else
                    {
                        _jobs.Add(_airlocks[airlockName].CycleAirlock());
                        Runtime.UpdateFrequency |= UpdateFrequency.Update1;
                    }
                }
            }

            for (int i = 0; i < _jobs.Count; i++)
            {
                IEnumerator<bool> job = _jobs[i];
                if (job.MoveNext()) continue;
                job.Dispose();
                _jobs.Remove(job);
                i--;
                _console.Print("Job Removed From Queue.");
            }

            if (_jobs.Count == 0) Runtime.UpdateFrequency = UpdateFrequency.None;
        }
    }
}