using System.Collections;
using System.Collections.Generic;
using System.Text;
using System;
using System.Linq;


namespace Rokojori
{   
  public class EventSlot<T>
  {
    protected List<Action<T>> _actions = new List<Action<T>>();
    List<Action<T>> _once = new List<Action<T>>();

    protected bool _canModify = true;
    List<Action<T>> _additions = new List<Action<T>>();
    List<Action<T>> _onceAdditions = new List<Action<T>>();
    List<Action<T>> _removals = new List<Action<T>>();


    public bool hasListeners => _once.Count > 0 || _actions.Count > 0;

    public void AddAction( Action<T> action )
    {
      if ( _actions.IndexOf( action ) != - 1 || _additions.IndexOf( action ) != -1 )
      {
        return;
      }

      if ( _canModify )
      {
        _actions.Add( action );
      }
      else
      {
       
        _additions.Add( action );
      }      
    }

    public void RemoveAction( Action<T> action )
    {
      if ( _canModify )
      {
        _actions.Remove( action );
      }
      else
      {
        _removals.Add( action );
      }        
    }

    public void Once( Action<T> action )
    {
      if ( _canModify )
      {
        _actions.Add( action );
        _once.Add( action );
      }
      else
      {
        _onceAdditions.Add( action );
      }   

     
    }

    protected void _UpdateLists()
    {
      _once.ForEach( a => { _actions.Remove( a ); } );
      _once.Clear();

      if ( _removals.Count > 0 )
      {
        Lists.RemoveRange( _actions, _removals );
        _removals.Clear();
      }         
      
      if ( _additions.Count > 0 )
      {
        _actions.AddRange( _additions ); 
        _additions.Clear();
      }

      if ( _onceAdditions.Count > 0 )
      {
        _once.AddRange( _onceAdditions );
        _actions.AddRange( _onceAdditions );
      }      
      

    } 

    public void DispatchEvent( T t )
    {
      _canModify = false;

      _actions.ForEach( a => { if ( a != null ){ a( t ); } } );

      _UpdateLists();
      
      _canModify = true;

    }
  }
  
}
