
using Godot;
using System.Collections.Generic;

namespace Rokojori
{  
  public class CEG_TextureCreator
  {
    public bool autoClean = true;

    public void AutoClean( RDTexture texture, RenderingDevice rd )
    {
      if ( texture == null || ! autoClean )
      {
        return;
      }

      rd.FreeRid( texture.rid );
      
    }

    public virtual RDTexture Create( RDTexture texture, RDGraph graph )
    {
      return texture;
    }
  }

  public class CEG_TextureCreator_ScreenSize:CEG_TextureCreator
  {
    public RDTextureFormat format = RDTexture.DefaultFormat( -1, -1 );
    public Vector2 scale = Vector2.One;

    public override RDTexture Create( RDTexture texture, RDGraph graph )
    {
      Vector2I scaledSize = (Vector2I) ( graph.context.internalSize * scale );

      if ( texture == null || scaledSize != texture.size )
      {
        AutoClean( texture, graph.context.renderingDevice );
        format = RDTextureFormats.FormatChangeSize( format, scaledSize );
        texture = RDTexture.Create( graph.context, format );
      }

      return texture;
    }
  }

  public class CEG_TextureCreator_FixedSize:CEG_TextureCreator
  {
    public RDTextureFormat format = RDTexture.DefaultFormat( -1, -1 );

    public override RDTexture Create( RDTexture texture, RDGraph graph )
    {
      var formatSize = new Vector2I( (int) format.Width, (int) format.Height );

      if ( texture == null || texture.size != formatSize )
      {
        AutoClean( texture, graph.context.renderingDevice );
        texture = RDTexture.Create( graph.context, format );
      }

      return texture;
    }
  }

  public class CEG_TextureCreator_Reference:CEG_TextureCreator
  {
    public RDTexture _texture;
    
    public CEG_TextureCreator_Reference( RDTexture texture )
    {
      this._texture = texture;
    }

    public override RDTexture Create( RDTexture texture, RDGraph graph )
    {
      return _texture;
    }
  }


  public class CEG_BufferTexture:RGGraphProcessor, RDGraphTextureSlotInput
  {
    RDTexture _texture;

    CEG_TextureCreator _creator;


    public RDTexture GetTexture()
    {
      return _texture;
    }

    public RGGraphProcessor GetProcessor()
    {
      return this;
    } 

    List<CompositorEffectGraphTextureSlot> _connectedSlots = new List<CompositorEffectGraphTextureSlot>();

    public void SetConnected( CompositorEffectGraphTextureSlot slot )
    {
      _connectedSlots.Add( slot );
    }

    public CEG_BufferTexture( RDGraph graph, CEG_TextureCreator creator ):base( graph )
    {
      _creator = creator;
    } 

    public static CEG_BufferTexture ScreenSize( RDGraph graph, Vector2? scale = null )
    {
      var screenSize = new CEG_TextureCreator_ScreenSize();
      screenSize.scale = scale == null ? Vector2.One : (Vector2) scale;
      return new CEG_BufferTexture( graph, screenSize );
    }

    public static CEG_BufferTexture FixedSize( RDGraph graph )
    {
      return new CEG_BufferTexture( graph, new CEG_TextureCreator_FixedSize() );
    }

    public static CEG_BufferTexture FixedSize( RDGraph graph, Vector2I size )
    {
      var creator = new CEG_TextureCreator_FixedSize();
      creator.format.Width = (uint) size.X;
      creator.format.Height = (uint) size.Y;
      return new CEG_BufferTexture( graph, creator );
    }

    public static CEG_BufferTexture From( RDGraph graph, RDTexture texture )
    {
      var creator = new CEG_TextureCreator_Reference( texture );
      var t = new CEG_BufferTexture( graph, creator );
      t._texture = texture;
      return t;
    }

    public override void Process()
    {
      _texture = _creator.Create( _texture, graph );
    }

    public void ConnectTo( CompositorEffectGraphTextureSlot slot )
    {
      slot.SetInput( this );
    }
    
  }
}