using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace Rokojori
{
  public class LexerList 
  {
    protected List<LexerEvent> _events;

    public List<LexerEvent> events => _events;

    public LexerList Filter( System.Predicate<LexerEvent> le )
    {
      return Create( events.Filter( e => le( e ) ) );
    }

    public LexerList GetAll( LexerMatcher lexerMatcher )
    {
      return Create( events.Filter( e => e.Is( lexerMatcher ) ) );
    }

    public List<RangeI> Seperate( int start, int end, LexerMatcher[] ignore = null )
    {
      return Seperate( ",", start, end, ignore ); 
    }

    public List<RangeI> Seperate( string seperator, int start, int end, LexerMatcher[] ignore = null )
    {
      var list = new List<RangeI>();
      
      var currentStart = -1;

      for ( int i = start; i <= end; i++ )
      {
        if ( _events[ i ].MatchIs( seperator ) )
        {
          if ( currentStart != -1 )
          {
            list.Add( new RangeI( currentStart, i - 1 ) );
          }

          currentStart = -1;
        } 
        else if ( ignore != null && _events[ i ].IsAnyOf( ignore ) )
        {
          continue;
        }
        else if ( currentStart == -1 )
        {
          currentStart = i;
        }

      }

      if ( currentStart != -1 )
      {
        list.Add( new RangeI( currentStart, end ) );
      }

      return list;
    }

    public void ForEach( LexerMatcher lexerMatcher, System.Action<LexerEvent> action )
    {
      events.ForEach(
        ( e )=>
        {
          if ( ! e.Is( lexerMatcher ) )
          {
            return;
          }

          action( e );
        }
      );
    }

    public LexerEvent.FindResult FindOpeningBracket( int offset, string blockBracket = "{" )
    {
      return LexerEvent.FindOpeningBracket( _events, offset, blockBracket );
    }

    public LexerEvent.FindResult ReverseFindOpeningBracket( int offset )
    {
      return LexerEvent.ReverseFindOpeningBracket( _events, offset );
    }

    public LexerEvent.FindResult ReverseFind( int offset, System.Func<LexerEvent,LexerEvent.FindResultType> evaluator )
    {
      return LexerEvent.Find( _events, offset, evaluator, false );
    }

    public LexerEvent.FindResult Find( int offset, System.Func<LexerEvent,LexerEvent.FindResultType> evaluator )
    {
      return LexerEvent.Find( _events, offset, evaluator, true );
    }
    
    public LexerEvent.FindResult Find( int offset, List<LexerEventSelector> found,     
    List<LexerEventSelector> keepSearching = null, List<LexerEventSelector> errors = null )
    {
      return Find(
        offset,
        ( le )=>
        {
          var errorItem = errors == null ? null : errors.Find( s => s.Selects( le ) );

          if ( errorItem != null )
          {
            return LexerEvent.FindResultType.Error;
          } 

          var foundItem = found.Find( s => s.Selects( le ) );

          if ( foundItem != null )
          {
            return LexerEvent.FindResultType.Found;
          } 


          if ( keepSearching == null )
          {
            return LexerEvent.FindResultType.KeepSearching;
          }

          var keepSearchingItem = keepSearching.Find( s => s.Selects( le ) );

          return keepSearchingItem == null ? LexerEvent.FindResultType.Error : LexerEvent.FindResultType.KeepSearching; 

        }
      );
    }

    public List<List<LexerEvent>> FindSequences( System.Func<int,bool,Trillean> matcher )
    {
      return LexerEvent.FindSequences( _events, matcher );
    }

    public List<RangeI> GetBlocks()
    {
      return LexerEvent.GetBlocks( _events );
    }

    public LexerList Range( RangeI range )
    {
      return Range( range.min, range.max );
    }

    public LexerList Range( int start, int end = -1 )
    {
      if ( end == -1 )
      {
        end = _events.Count;
      }

      return Create( _events.Sub( start, end - start + 1 ) );
    }

    public static LexerList Create( List<LexerEvent> lexerEvents )
    {
      var list = new LexerList();
      list._events = lexerEvents;

      return list;
    }
  } 
}