package timedistortion;

import java.util.Objects;

public class ColorF32 {
  public float r;
  public float g;
  public float b;
  
  public static final ColorF32 black = new ColorF32(0.0f, 0.0f, 0.0f);
  public static final ColorF32 white = new ColorF32(1.0f, 1.0f, 1.0f);

  public ColorF32() {
    this.r = 0.0f;
    this.g = 0.0f;
    this.b = 0.0f;
  }

  public ColorF32(float r, float g, float b) {
    this.r = r;
    this.g = g;
    this.b = b;
  }
  
  @Override
  public int hashCode() {
    return Objects.hash(r, g, b);
  }

  @Override
  public boolean equals(Object other) {
    if(other instanceof ColorF32) {
      ColorF32 c = (ColorF32) other;
      return c.r == this.r && c.g == this.g && c.b == this.b;
    }
    return false;
  }

  public static void copy(ColorF32 src, ColorF32 dst) {
    assert src != null;
    assert dst != null;
    dst.r = src.r;
    dst.g = src.g;
    dst.b = src.b;
  }
  
  private static float clamp(float v) {
    if(v < 0.0f) {
      return 0.0f;
    }
    if(v > 1.0f) {
      return 1.0f;
    }
    return v;
  }
 
  private static int clamp_u8(float v) {
    if(v < 0.0f) {
      return 0;
    }
    if(v > 1.0f) {
      return 255;
    }
    return (int)(v * 255);
  }
 
  private static float max_float(float v1, float v2) {
    return v1 < v2 ? v2 : v1;
  }

  private static float min_float(float v1, float v2) {
    return v1 < v2 ? v1 : v2;
  }

  public static void rgb2hsb(ColorF32 src, ColorF32 dst) {
    assert src != null;
    assert dst != null;
    
    float r = clamp(src.r);
    float g = clamp(src.g);
    float b = clamp(src.b);
    
    float max = max_float(r, max_float(g, b));
    float min = min_float(r, min_float(g, b));
    float delta = max - min;
    
    dst.b = max;
    if (delta == 0) {
      dst.r = 0;
      dst.g = 0;
      return;
    }
    dst.g = delta / max;
    
    if (r == max)
      dst.r = (g - b) / delta / 6;
    else if (g == max)
      dst.r = (2 + (b - r) / delta) / 6;
    else
      dst.r = (4 + (r - g) / delta) / 6;
    if (dst.r < 0)
      dst.r += 1;
  }
  
  public static void hsb2rgb(ColorF32 src, ColorF32 dst) {
    assert src != null;
    assert dst != null;
    if (src.g <= 0.0f) {
        dst.r = src.b;
        dst.g = src.b;
        dst.b = src.b;
    }
    else {
        float h = (src.r - (float)Math.floor(src.r)) * 6.0f;
        float f = h - (float)java.lang.Math.floor(h);
        float p = src.b * (1.0f - src.g);
        float q = src.b * (1.0f - src.g * f);
        float t = src.b * (1.0f - (src.g * (1.0f - f)));
        switch ((int) h) {
        case 0:
            dst.r = src.b;
            dst.g = t;
            dst.b = p;
            break;
        case 1:
            dst.r = q;
            dst.g = src.b;
            dst.b = p;
            break;
        case 2:
            dst.r = p;
            dst.g = src.b;
            dst.b = t;
            break;
        case 3:
            dst.r = p;
            dst.g = q;
            dst.b = src.b;
            break;
        case 4:
            dst.r = t;
            dst.g = p;
            dst.b = src.b;
            break;
        default: // case 5:
            dst.r = src.b;
            dst.g = p;
            dst.b = q;
            break;
        }
    }
  }

  public static int toRGB8(ColorF32 src) {
    int r = clamp_u8(src.r);
    int g = clamp_u8(src.g);
    int b = clamp_u8(src.b);
    return 0xff000000 | (r << 16) | (g << 8) | b;
  }

//  public static java.awt.Color to_awt_color(ColorF32 src) {
//    return new java.awt.Color(src.r, src.g, src.b);
//  }

  @Override
  public String toString() {
    return "ColorF32 [r=" + r + ", g=" + g + ", b=" + b + "]";
  }
  

}
