
using Godot;
using System.Collections.Generic;

namespace Rokojori
{ 
  public class FontFXGroup
  {
    public FontDefinition fontDefinition;
    public float scale = 1;
    public string characters;

    float _width = 0;
    public float width 
    { 
      get 
      {
        
        if ( _width == 0 )
        {
          _width = fontDefinition.GetWidth( characters ) * scale;
        }

        return _width;
      }
    }

    public List<float> relativeOffsets => fontDefinition.GetOffsets( characters ).Map( o => o * scale ); 

    public List<float> absoluteOffsets;


  }

  public class FontFXLine
  {
    public List<FontFXGroup> groups = new List<FontFXGroup>();

    public void ComptuteOffsets()
    {
      var offset = 0f;

      for ( int i = 0; i < groups.Count; i++ )
      {
        var width = groups[ i ].width;
        groups[ i ].absoluteOffsets = groups[ i ].relativeOffsets.Map( o => o + offset );
        offset += width;        
      }
    }

    public List<FontFXLine> LayoutLineWrapped( float width )
    {
      var lines = new List<FontFXLine>();
      var line = new FontFXLine();

      var lineWidth = 0f;

      groups.ForEach(
        ( g )=>
        {
          var groupWidth = g.width;
          var nextEnd = lineWidth + groupWidth;

          if ( nextEnd > width )
          {
            lines.Add( line );
            line = new FontFXLine();
            lineWidth = 0;
          } 

          line.groups.Add( g );
          lineWidth += groupWidth;
        }
      );

      lines.Add( line );

      return lines;
    }

  }

  public class FontFXLayouter
  {       

    public List<FontFXLine> Layout( string text, FontDefinition font, float maxWidth = 10000000 )
    {
      var lines = new List<FontFXLine>();

      var lexed = WordLexer.Lex( text );

      if ( lexed == null )
      {
        return null;
      }

      var line = new FontFXLine();

      lexed.ForEach(
        ( l )=>
        {
          if ( l.isDone )
          {
            return;
          }

          if ( l.Is( WordLexer.LineBreak ) )
          {
            lines.Add( line );

            line = new FontFXLine();
            return;
          }

          var group = new FontFXGroup();
          group.fontDefinition = font;
          group.characters = l.match;

          line.groups.Add( group );
        }
      );

      lines.Add( line );


      lines = lines.MultiMap( ( line, index ) => line.LayoutLineWrapped( maxWidth ) );
      

      return lines;
    }
  }
}