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

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

        private IEnumerator<bool> _job = null;
        private MyCommandLine _cli = new MyCommandLine();

        private List<IMyShipConnector> dockingPorts = new List<IMyShipConnector>();
        private List<IMyThrust> thrusters = new List<IMyThrust>();
        private List<IMyGasTank> gasTanks = new List<IMyGasTank>();

        private ActionGroup actionGroup;

        public Program()
        {
            Console = new MainConsole(this, "Docking Controller");
            actionGroup = new ActionGroup(Console, "docking");

            // We store a list of the dockingPorts because we will only dock if one is ready to lock.
            GridTerminalSystem.GetBlocksOfType(dockingPorts, blockFilter);

            foreach (IMyShipConnector dockingPort in dockingPorts)
            {
                actionGroup.AddActionBlock("dock", 0, new BlockActionConnector(dockingPort, ConnectorAction.Connect));
                actionGroup.AddActionBlock("undock", 1, new BlockActionConnector(dockingPort, ConnectorAction.Disconnect));
            }

            List<IMyThrust> thrusters = new List<IMyThrust>();
            GridTerminalSystem.GetBlocksOfType(thrusters, blockFilter);
            foreach (IMyThrust thruster in thrusters)
            {
                actionGroup.AddActionBlock("dock", 1, new BlockActionThruster(thruster, ThrusterAction.Disable));
                actionGroup.AddActionBlock("undock", 0, new BlockActionThruster(thruster, ThrusterAction.Enable));
            }

            List<IMyGasTank> gasTanks = new List<IMyGasTank>();
            GridTerminalSystem.GetBlocksOfType(gasTanks, blockFilter);
            foreach (IMyGasTank gasTank in gasTanks)
            {
                actionGroup.AddActionBlock("dock", 1, new BlockActionGasTank(gasTank, GasTankAction.Stockpile));
                actionGroup.AddActionBlock("undock", 0, new BlockActionGasTank(gasTank, GasTankAction.Dispense));
            }
        }

        public void Main(string argument, UpdateType updateSource)
        {
            if (argument != "")
            {
                _cli.TryParse(argument);
                if (_cli.ArgumentCount == 0)
                {
                    Console.Print("Error: Must pass an argument, 'dock' or 'undock'.");
                }
                else if (_job != null)
                {
                    Console.Print("Already performing a docking action.");
                }
                else
                {
                    _job = actionGroup.RunAction(_cli.Argument(0).ToLower());
                    Runtime.UpdateFrequency = UpdateFrequency.Update10;
                }
            }

            if (_job != null && !_job.MoveNext())
            {
                _job.Dispose();
                _job = null;
                Console.Print("Docking action complete.");
                Runtime.UpdateFrequency = UpdateFrequency.None;
            }
        }

        private bool blockFilter(IMyTerminalBlock block)
        {
            if (MyIni.HasSection(block.CustomData, "docking"))
            {
                Ini.TryParse(block.CustomData);
                return Ini.Get("docking", "ignore").ToBoolean(false);
            }
            return true;
        }
    }
}