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

namespace Rokojori
{  
  public class SVGPathParser
  {
    public static readonly string SVGPathCommands = "mlhvcsqtaz";

    List<SVGPathCommand> commands = new List<SVGPathCommand>();
    List<Message> messages = new List<Message>();

    public static List<SVGPathCommand> Parse( string d )
    {
      var svgPath = new SVGPathParser();
      var commands = svgPath.ParseCommands( d );
        
      if ( Messages.HasError( svgPath.messages ) )
      {
        return null;
      }

      return commands;
    }   

    public static List<Message> GetMessages( string d )
    {
      var svgPath = new SVGPathParser();
      var commands = svgPath.ParseCommands( d );
        
      return svgPath.messages;
    }

    public List<SVGPathCommand> ParseCommands( string d )
    {
      for ( int i = 0; i < d.Length; i++ )
      {
        if ( d[ i ] == ' ' )
        {
          continue;
        }

        var lowerCase = ( d[ i ] + "" ).ToLower();

        

        var commandIndex = SVGPathCommands.IndexOf( lowerCase );
        
        if ( commandIndex == -1 )
        {
          Messages.Error( messages, "Unknown command at '" + i + "'. Found " + d[ i ] );
          return null;
        }

        var commandEnd = ProcessCommand( d, i );

        // RJLog.Log( "Processing", d[ i ], ">>", lowerCase, " ends ", commandEnd );

        if ( commandEnd == -1 || Messages.HasError( messages ) )
        {
          Messages.Error( messages, "Command couldn't be processed at '" + i + "'. Processed " + d[ i ] );
          return null;
        }

        i = commandEnd;
      }

      return commands;
    }

    int ProcessCommand( string d, int offset )
    {
      var end = FindEnd( d, offset + 1 );

      var pc = new SVGPathCommand();
      pc.type = d[ offset ] + "";
      pc.pathIndex = commands.Count;

      ReadParameters( pc, d, offset + 1, end ); 

      commands.Add( pc );

      return end;
    }

    int FindEnd( string d, int offset )
    {
      for ( int i = offset; i < d.Length; i++ )
      {
        var chr = ( d[ i ] + "" ).ToLower();

        if ( SVGPathParser.SVGPathCommands.IndexOf( chr ) != - 1 )
        {
          return i - 1;
        }
      }

      return d.Length - 1;
    }  

    void ReadParameters( SVGPathCommand command, string d, int start, int end )
    {
      
      var parameters = d.Substring( start, ( end + 1 ) - start );
      parameters = parameters.Trim();

     // RJLog.Log( "Parsing parameters:", parameters );

      var regex = new Regex( " |," );
      var splitted = RegexUtility.Split( parameters, " |," );

      splitted.ForEach(
        ( s )=>
        {
          var number = RegexUtility.ParseFloat( s.Trim() );
          command.paramaters.Add( number );
          // RJLog.Log( s, ">>", number );
        }
      );
    }

    void ReadParametersOld( SVGPathCommand command, string d, int start, int end )
    {
      var matcher = LexerMatcherLibrary.NumberMatcher;
      var offset = start;
      var isNegative = false;

      while ( offset < end )
      {
        if ( d[ offset ] == ' ' || d[ offset ] == ','  )
        {
          offset ++;
          isNegative = false;
          continue;
        }

        if ( d[ offset ] == '-' )
        {
          offset ++;
          isNegative = true;
          continue;
        }


        var matchLength = matcher.MatchLength( d, offset );

        if ( matchLength == -1 )
        {
          Messages.Error( messages, 
            "Found no number." +
            " Offset:" + offset + 
            " Start: " + start + 
            " End: " + end + 
            " Part: " + "'" + d.Substring( start, end - start ) + "'"
          ); 
          return;
        }

        var endIndex = offset + matchLength;

        if ( endIndex > end )
        {
          Messages.Error( messages, 
            "Number parsing exceeded expected end." +
            " Offset:" + offset + 
            " Start: " + start + 
            " End: " + end + 
            " Match End: " + endIndex + 
            " Part: " + "'" + d.Substring( start, end - start ) + "'"
          );
          return;
        }

        var number = RegexUtility.ParseFloat( d.Substring( offset, matchLength ) );

        if ( isNegative )
        {
          number = -number;
        }

        offset += matchLength;

        command.paramaters.Add( number );

        isNegative = false;
      }
    }
  }
}