
using Godot;
using System.Collections.Generic;

namespace Rokojori
{  
  [Tool][GlobalClass, Icon("res://addons/rokojori_action_library/Icons/Parallel.svg") ]
  public partial class Parallel : SequenceAction
  {
    public enum Mode
    {
      First_Finishes_Sequence,
      Wait_For_All_To_Finish
    }

    [Export]
    public Mode mode = Mode.Wait_For_All_To_Finish;

    [Export]
    public Action[] actions = new Action[ 0 ];

    [Export]    
    public bool triggerDirectChildren = true;

    [Export]
    public bool ignoreNonSequenceActions = true;

    [Export]
    public bool errorsCountAsFinished = false;


    protected override void _OnTrigger()
    {
      var actions = new List<Action>( this.actions );
      
      if ( triggerDirectChildren )
      {
        Nodes.ForEachDirectChild<Action>( this, a => actions.Add( a ) );
      }

      var sequenceActions = Lists.FilterAndMap( actions, ( a, i ) => a is SequenceAction, a => (SequenceAction) a );

      var sequenceID = DispatchStart(); 

      if ( ! ignoreNonSequenceActions && sequenceActions.Count != actions.Count && Mode.First_Finishes_Sequence == mode )
      {
        actions.ForEach( a => Action.Trigger( a )  );
        DispatchEnd( sequenceID );
        return;
      }

      
      var numFinished = 0;
      var running = true;

      sequenceActions.ForEach( 
        sa =>
        {
          sa.onSequenceDone.Once(
            ( fe )=>
            {
              if ( ! running )
              {
                return;
              }

              if ( fe.success || errorsCountAsFinished )
              {
                numFinished ++;

                if ( Mode.First_Finishes_Sequence == mode )
                {
                  running = false;
                  DispatchEnd( sequenceID );
                  
                }
                else if ( Mode.Wait_For_All_To_Finish == mode )
                {
                  if ( numFinished == sequenceActions.Count )
                  {
                    running = false;
                    DispatchEnd( sequenceID );
                  }
                }
              }
              else
              {
                running = false;
                DispatchCancelled( sequenceID );
              }
            }
          );
        }
      );

      actions.ForEach( a => Action.Trigger( a ) );
    }
  }
}