
using Godot;
using System.Collections.Generic;

namespace Rokojori
{ 
  [Tool]
  [GlobalClass]
  public partial class FontCreator:Node3D
  {   
    [Export]
    public Font font;

    [Export]
    public string characterSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcedfghijklmnopqrstuvwxyz0123456789!?.-#+[]:,;_/";

    [Export(PropertyHint.Dir)]
    public string exportPath;

    [Export]
    public FontDefinition fontDefinition;

    [Export]
    public Label3D label3D;

    [Export]
    public int elements = 3;

    [Export]
    public float offset = 0.1f;

    [Export]
    public Gradient fillGradient;

    [Export]
    public Gradient strokeGradient;

    [Export]
    public float height;

    [ExportToolButton( "Create Glyphs" )]
    public Callable createButton => Callable.From( ()=> CreateGlyphs() ) ;


    [Export]
    public Node3D[] glyphs;

    
    void CreateGlyphs()
    {
      this.DestroyChildren();
      glyphs = [];

      var gList = new List<Node3D>();

      for ( int i = 0; i < characterSet.Length; i++ )
      {
        var g = CreateGlyph( characterSet[ i ] + "" );
        gList.Add( g );
      }

      glyphs = gList.ToArray();

      ComputeWidths();
    }

    async void ComputeWidths()
    {
      await this.RequestNextFrame();
      await this.RequestNextFrame();

      var glyphList = new List<FontGlyph>();

      for ( int i = 0; i < glyphs.Length; i++ )
      {
        var label = glyphs[ i ].Get<Label3D>();

        var bounds = (label.GetAabb());

        var scenePath = exportPath + "/scene " + glyphs[ i ].Name + ".tscn";
        glyphs[ i ].SaveAs( scenePath, false );

        var glyph = new FontGlyph();
        glyph.glyphMesh = new SceneReference();
        glyph.glyphMesh.scenePath = scenePath;
        glyph.width = bounds.Size.X;
        glyph.kerningGroup = 0;
        glyph.characters = characterSet[ i ] + "";

        var glyphPath = exportPath + "/glyph " + glyphs[ i ].Name + ".tres";
        glyph.SaveAs( glyphPath, false );

        glyphList.Add( glyph );

      }

      fontDefinition.glyphs = glyphList.ToArray();

      await this.RequestNextFrame();
      await this.RequestNextFrame();

      #if TOOLS
      EditorInterface.Singleton.GetResourceFilesystem().ScanSources();
      #endif
    }

    Node3D CreateGlyph( string character )
    {
     
      
      var characterLabel = "";

      for ( int i = 0; i < character.Length; i++ )
      {
        if ( i != 0 ){ characterLabel += " "; }
        characterLabel += character[ i ].MapCharacterToName();        
      }

      var container = this.CreateChild<Node3D>( characterLabel );

      for ( int i = 0; i < elements; i++ )
      {
        var label = (Label3D)label3D.Duplicate();

        label.Text = character;
        
        label.SetParent( container );
        label.Name =  characterLabel;
        label.SetLocalZ( i * offset );

        label.Modulate = fillGradient.Sample( i / ( elements - 1f ) );
        label.OutlineModulate = strokeGradient.Sample( i / ( elements - 1f ) );
      }   

      return container;
    }
  }
}