using Godot;
using System.Collections.Generic;

namespace Rokojori
{
  public class SceneFileLexer:Lexer
  {
    public SceneFileLexer()
    {
      AddAllMatchers( 
        LexerMatcherLibrary.DoubleQuotedStringMatcher,
        LexerMatcherLibrary.NumberMatcher,
        LexerMatcherLibrary.NullMatcher,
        LexerMatcherLibrary.BoolMatcher,
        LexerMatcherLibrary.BreakMatcher,
        LexerMatcherLibrary.WhiteSpaceMatcher,
        LexerMatcherLibrary.BracketMatcher,
        LexerMatcherLibrary.OperatorMatcher,
        LexerMatcherLibrary.CFunctionMatcher,
        LexerMatcherLibrary.CwordMatcher,
        LexerMatcherLibrary.AnySymbolMatcher
      );
    }

    public class SceneFileAssignmentResult
    {
      public bool hasError = true;
      public string errorMessage = "";
      
      public string name;
      public string value;

      public SceneFileNamedValue GetNamedValue()
      {
        return SceneFileNamedValue.Create( name, value );
      }

      public int startOffset;
      public int endOffset;

      public static SceneFileAssignmentResult Create( int startOffset )
      {
        var r = new SceneFileAssignmentResult();

        r.startOffset = startOffset;

        return r;
      }

      public SceneFileAssignmentResult AsError( int offset, LexerEvent le, string message )
      {
        hasError = true;
        endOffset = offset;
        errorMessage = message + " Token: " + le.type + "'" + le.match + "'" ;

        return this;
      } 

      public SceneFileAssignmentResult AsValue( int offset, LexerEvent le )
      {
        hasError = false;
        endOffset = offset;
        value = le.match;

        return this;
      } 

      public SceneFileAssignmentResult AsValue( int offset, string value )
      {
        hasError = false;
        endOffset = offset;
        this.value = value;

        return this;
      } 

    }

    public static SceneFileAssignmentResult ReadAssignment( List<LexerEvent> tokens, int offset )
    {
      var result = SceneFileAssignmentResult.Create( offset );
      var token = tokens[ offset ];

      if ( ! token.Is( LexerMatcherLibrary.CwordMatcher ) )
      {
        return result.AsError( offset, token, "Expected a word as name." ) ;
      } 

      result.name = token.match;

      offset ++; token = tokens[ offset ];

      if ( ! token.Is( LexerMatcherLibrary.OperatorMatcher, "=" ) )
      {
        return result.AsError( offset, token, "Expected assignment operator." ) ;
      } 

      offset ++; token = tokens[ offset ];

      if ( token.Is( LexerMatcherLibrary.NumberMatcher ) ||
           token.Is( LexerMatcherLibrary.DoubleQuotedStringMatcher )
      )
      {
        return result.AsValue( offset, token );
      }
      else if ( token.Is( LexerMatcherLibrary.CFunctionMatcher ) )
      {
        var start = offset + 1;
        var closer = LexerEvent.FindClosingBracket( tokens, offset + 1 );

        if ( closer.type != LexerEvent.FindResultType.Found )
        {
          return result.AsError( offset, token, "Unmatched brackets.");
        }

        var length = ( closer.index - start ) + 1;
      
        var value = LexerEvent.GetMatchFromRange( tokens, start, length );
        
        return result.AsValue( closer.index, value );      
        
      }
      else
      {
        return result.AsError( offset, token, "Unexpected token.");
      }
    }
  }
}