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



namespace Rokojori
{
  public enum TextureCombinerBlendMode
  {
    Normal,
    Add,
    Multiply,
    Screen,
    Overlay,
    HardLight,
    SoftLight,
    Color,
    Hue
  }

  public class TextureCombinerBlendModeAlgorithm
  {
    public static void Blend( TextureCombinerBlendMode blendMode, int x, int y, int w, int h, float topOpacity,
      TextureCombinerBuffer bottom, TextureCombinerBuffer top, TextureCombinerBuffer output
    )
    {
      if ( TextureCombinerBlendMode.Normal == blendMode )
      {
        BlendMode( ColorX.Blend, x, y, w, h, topOpacity, bottom, top, output );
      }
      else if ( TextureCombinerBlendMode.Add == blendMode )
      {
        BlendMode( ColorX.BlendAdd, x, y, w, h, topOpacity, bottom, top, output );
      }
      else if ( TextureCombinerBlendMode.Multiply == blendMode )
      {
        BlendMode( ColorX.BlendMultiply, x, y, w, h, topOpacity, bottom, top, output );
      }
      else if ( TextureCombinerBlendMode.Screen == blendMode )
      {
        BlendMode( ColorX.BlendScreen, x, y, w, h, topOpacity, bottom, top, output );
      }
      else if ( TextureCombinerBlendMode.Overlay == blendMode )
      {
        BlendMode( ColorX.BlendOverlay, x, y, w, h, topOpacity, bottom, top, output );
      }
      else if ( TextureCombinerBlendMode.HardLight == blendMode )
      {
        BlendMode( ColorX.BlendHardLight, x, y, w, h, topOpacity, bottom, top, output );
      }
      else if ( TextureCombinerBlendMode.SoftLight == blendMode )
      {
        BlendMode( ColorX.BlendSoftLight, x, y, w, h, topOpacity, bottom, top, output );
      }
      else if ( TextureCombinerBlendMode.Color == blendMode )
      {
        BlendMode( ColorX.BlendColor, x, y, w, h, topOpacity, bottom, top, output );
      }
      else if ( TextureCombinerBlendMode.Hue == blendMode )
      {
        BlendMode( ColorX.BlendHue, x, y, w, h, topOpacity, bottom, top, output );
      }
    }

    

    static void BlendMode( System.Func<Color,Color,Color> blender, int x, int y, int w, int h, float topOpacity,
      TextureCombinerBuffer bottom, TextureCombinerBuffer top, TextureCombinerBuffer output )
    {
      for ( int i = 0; i < w; i++ )
      {
        var rx = x + i;

        for ( int j = 0; j < h; j++ )
        {
          var ry = y + j;

         var index        = output.ComputeIndexFromPosition( rx, ry );

          var topColor    = top.GetIndexed( index );
          var bottomColor = bottom.GetIndexed( index );


          var outputColor = blender( bottomColor, topColor );
          
          outputColor = bottomColor.Blend( outputColor.FadeAlpha( topOpacity ) );

          output.SetIndexed( index, outputColor );

        }
      }
    }

    public static void BlendMasked( TextureCombinerBlendMode blendMode, int x, int y, int w, int h, float topOpacity,
    TextureCombinerBuffer mask, 
      TextureCombinerBuffer bottom, TextureCombinerBuffer top, TextureCombinerBuffer output
    )
    {
      if ( TextureCombinerBlendMode.Normal == blendMode )
      {
        BlendModeMasked( ColorX.Blend, x, y, w, h, topOpacity, mask, bottom, top, output );
      }
      else if ( TextureCombinerBlendMode.Add == blendMode )
      {
        BlendModeMasked( ColorX.BlendAdd, x, y, w, h, topOpacity, mask, bottom, top, output );
      }
      else if ( TextureCombinerBlendMode.Multiply == blendMode )
      {
        BlendModeMasked( ColorX.BlendMultiply, x, y, w, h, topOpacity, mask, bottom, top, output );
      }
      else if ( TextureCombinerBlendMode.Screen == blendMode )
      {
        BlendModeMasked( ColorX.BlendScreen, x, y, w, h, topOpacity, mask, bottom, top, output );
      }
      else if ( TextureCombinerBlendMode.Overlay == blendMode )
      {
        BlendModeMasked( ColorX.BlendOverlay, x, y, w, h, topOpacity, mask, bottom, top, output );
      }
      else if ( TextureCombinerBlendMode.HardLight == blendMode )
      {
        BlendModeMasked( ColorX.BlendHardLight, x, y, w, h, topOpacity, mask, bottom, top, output );
      }
      else if ( TextureCombinerBlendMode.SoftLight == blendMode )
      {
        BlendModeMasked( ColorX.BlendSoftLight, x, y, w, h, topOpacity, mask, bottom, top, output );
      }
      else if ( TextureCombinerBlendMode.Color == blendMode )
      {
        BlendModeMasked( ColorX.BlendColor, x, y, w, h, topOpacity, mask, bottom, top, output );
      }
      else if ( TextureCombinerBlendMode.Hue == blendMode )
      {
        BlendModeMasked( ColorX.BlendHue, x, y, w, h, topOpacity, mask, bottom, top, output );
      }
    }

    static void BlendModeMasked( System.Func<Color,Color,Color> blender, int x, int y, int w, int h, float topOpacity, 
    TextureCombinerBuffer mask,
      TextureCombinerBuffer bottom, TextureCombinerBuffer top, TextureCombinerBuffer output )
    {
      for ( int i = 0; i < w; i++ )
      {
        var rx = x + i;

        for ( int j = 0; j < h; j++ )
        {
          var ry = y + j;

          var index        = output.ComputeIndexFromPosition( rx, ry );

          var topColor    = top.GetIndexed( index );
          var bottomColor = bottom.GetIndexed( index );


          var outputColor = blender( bottomColor, topColor );

          var maskOpacity = mask.GetIndexed( index );          
          
          outputColor = bottomColor.Blend( outputColor.FadeAlpha( topOpacity * maskOpacity.R ) );

          output.SetIndexed( index, outputColor );

        }
      }
    }
  }
}