
using Godot;
using System.Collections.Generic;
using System.Text;

namespace Rokojori
{  
  public partial class RDContext
  {
    protected List<RDObject> _cleanUps = new List<RDObject>();
    protected List<string> _cleanUpInfo = new List<string>();

    protected bool cleanAll = false;

    public void Free( RDObject ro, string info = null )
    {
      if ( ro == null )
      {
        Warning( "ro == null, couldn't clean up: ", info );
        return;
      }

      if ( ! ro.rid.IsValid )
      { 
        Verbose( "Not valid rid:", ro.rid );
        return;
      }

      if ( ! cleanAll && ro is RDPipeline )
      {
        Verbose( "Not cleaning pipelines" );
        return; 
      }

      if ( ! cleanAll && ro is RDUniformSet )
      {
        Verbose( "Not cleaning uniform sets" );
        return; 
      }
      
      Verbose( "Cleaning up: ", info, ro.rid  );
      ro.Free( this );
    }

    public string GetMemoryInfo()
    {
      var types = new List<RenderingDevice.MemoryType>(){
        RenderingDevice.MemoryType.Buffers, 
        RenderingDevice.MemoryType.Textures, 
        RenderingDevice.MemoryType.Total
      };

      var sb = new StringBuilder();

      types.ForEach(
        ( t ) =>
        {
          var size = renderingDevice.GetMemoryUsage( t );
          var sizeInfo = Bytes.ConvertToString( size );
          sb.Append( t + ": " + sizeInfo + "(" + size + " bytes) " );
        }
      );

      // Verbose( "Cleaning up:", renderingDevice.GetMemoryUsage() );

      return sb.ToString();
    }
    
    public void CleanUp()
    {
      var index = 0;

      Verbose( "Memory before cleanup");

      Verbose( GetMemoryInfo() );

      _cleanUps.ForEach( 
        c => 
        {
          Free( c, _cleanUpInfo[ index ] );
          index ++;
        }
      );

      Verbose( "Memory after cleanup" );
      Verbose( GetMemoryInfo() );

      _cleanUps.Clear();
      _cleanUpInfo.Clear();
    }

    public void Free()
    {
      renderingDevice.Free();
      _renderingDevice = null;
    }

    public void CleanUpAndFree()
    {
      CleanUp();
      Free();      
    }

    public void AddToCleanUp( RDObject ro, string info = null )
    {
      if ( _cleanUps.Contains( ro ) )
      {
        return;
      }

      _cleanUps.Add( ro );
      _cleanUpInfo.Add( info );
    }

    public void AddToCleanUp( List<RDObject> ro, string info = null )
    {
      var index = 0;
      info = info == null ? "" : info;

      ro.ForEach( 
        r =>       
        { 
          AddToCleanUp( r, info + "["+ index + "]" ); 
          index ++; 
        } 
      );
    }
  }
}