//
// An unorganized collection of color functions.
//

/**
 * clampColor(color) -> Array
 * - color (Array): a color in the form [r,g,b]
 * Returns the same color (as reference) clamped to 0..255
 **/
function clampColor(color) {
  for(var i = 0; i < 3; i++) {
    color[i] = Math.min(255, Math.max(0, color[i]));
  }
  return color;
}

/**
 * shiftHue(color, percent) -> Array
 * - color (Array): a color in the form [r,g,b].
 * - percent (Integer): a number between 0-100 for how much to shift the hue.
 * Returns a color as [r,g,b] with the hue shifted the given percent. 
 **/
function shiftHue(color, percent) {
  var hsv = rgbToHsv(color);
  var ratio = percent / 100.0;
  var newhue = Math.round(360.0 * ratio + hsv[0]) % 360;
  return hsvToRgb( [newhue, hsv[1], hsv[2]] );
}

/**
 * shiftValue(color, percent) -> Array
 * - color (Array): a color in the form [r,g,b], Red 0-255, Green 0-255, Blue 0-255.
 * - percent (Integer): a number between 0-100 for how much to shift the value.
 * Returns a color as [r,g,b] with the value shifted in a way that increases contrast.
 **/
function shiftValue(color, percent) {
  clampColor(color);
  var hsv = rgbToHsv(color);
  var x = hsv[2];
  var curve = percent/100.0;
  var notCurve = 1 - curve;
  var newvalue = (Math.sin(x/Math.PI/5)*50+50)*(curve) + x*(notCurve);
  return hsvToRgb([hsv[0] % 360, hsv[1], newvalue]);
}

/**
 * hsvToRgb(color) -> Array
 * - color (Array): a color in the form [h,s,v], Hue 0-360, Saturation 0-100, Value 0-100.
 * Returns the color converted to rgb as an array [r,g,b], Red 0-255, Green 0-255, Blue 0-255.
 * implements formula found here: http://en.wikipedia.org/wiki/HSL_and_HSV
 * adapted from: http://matthaynes.net/blog/2008/08/07/javascript-colour-functions/
 **/
function hsvToRgb(color) {
  var [h, s, v] = color
  s /= 100.0;
  v /= 100.0;

  var hi = Math.floor((h/60) % 6);
  var f = (h / 60) - hi;
  var p = v * (1 - s);
  var q = v * (1 - f * s);
  var t = v * (1 - (1 - f) * s);

  var rgb = [];

  switch (hi) {
    case 0: rgb = [v,t,p];break;
    case 1: rgb = [q,v,p];break;
    case 2: rgb = [p,v,t];break;
    case 3: rgb = [p,q,v];break;
    case 4: rgb = [t,p,v];break;
    case 5: rgb = [v,p,q];break;
  }

  var r = Math.min(255, Math.round(rgb[0]*256)),
      g = Math.min(255, Math.round(rgb[1]*256)),
      b = Math.min(255, Math.round(rgb[2]*256));

  return [r,g,b];
}	

/**
 * hsvToRgb(color) -> Array
 * - color (Array): a color in the form [r,g,b], Red 0-255, Green 0-255, Blue 0-255.
 * Returns the color converted to hsv as an array [hue,saturation,value], 
 * Hue 0-360, Saturation 0-100, Value 0-100.
 * implements formula found here: http://en.wikipedia.org/wiki/HSL_and_HSV
 * adapted from: http://matthaynes.net/blog/2008/08/07/javascript-colour-functions/
 **/
function rgbToHsv(color) {
  var [r, g, b] = color
  r /= 255.0; g /= 255.0; b /= 255.0;

  var min = Math.min(Math.min(r, g), b),
      max = Math.max(Math.max(r, g), b),
      delta = max - min;

  var value = max, saturation, hue;

  // Hue
  if (max == min)    hue = 0;
  else if (max == r) hue = (60 * ((g-b) / (max-min))) % 360;
  else if (max == g) hue = 60 * ((b-r) / (max-min)) + 120;
  else if (max == b) hue = 60 * ((r-g) / (max-min)) + 240;

  if (hue < 0) hue += 360;

  // Saturation
  if (max == 0) saturation = 0;
  else          saturation = 1 - (min/max);

  return [Math.round(hue), Math.round(saturation * 100), Math.round(value * 100)];
}

