/**
 * color.js
 * color transformation utilities
 * From Michael Jackson
 * http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
 * Foxtrick conversion and additions by CatzHoek
 */

'use strict';

/* eslint-disable */
if (!this.Foxtrick)
	var Foxtrick = {};
/* eslint-enable */

if (!Foxtrick.util)
	Foxtrick.util = {};

Foxtrick.util.color = {};

/**
 * Converts an RGB color value to HSL.
 * Colors may be passed as a single array.
 * Conversion formula adapted from http://en.wikipedia.org/wiki/HSL_color_space.
 * Assumes r, g, and b are contained in the set [0, 255] and
 * returns h, s, and l in the set [0, 1].
 *
 * @param   {number}  r       The red color value
 * @param   {number}  g       The green color value
 * @param   {number}  b       The blue color value
 * @return  {Array}           The HSL representation
 */
Foxtrick.util.color.rgbToHsl = function(r, g, b) {
	if (Array.isArray(r))
		return this.rgbToHsl.apply(this, r);

	r /= 255; g /= 255; b /= 255;
	var max = Math.max(r, g, b), min = Math.min(r, g, b);
	var h, s, l = (max + min) / 2;

	if (max == min) {
		h = s = 0; // achromatic
	}
	else {
		var d = max - min;
		s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
		switch (max) {
			case r: h = (g - b) / d + (g < b ? 6 : 0); break;
			case g: h = (b - r) / d + 2; break;
			case b: h = (r - g) / d + 4; break;
		}
		h /= 6;
	}

	return [h, s, l];
};

/**
 * Converts an HSL color value to RGB.
 * Colors may be passed as a single array.
 * Conversion formula adapted from http://en.wikipedia.org/wiki/HSL_color_space.
 * Assumes h, s, and l are contained in the set [0, 1] and
 * returns r, g, and b in the set [0, 255].
 *
 * @param   {number}  h       The hue
 * @param   {number}  s       The saturation
 * @param   {number}  l       The lightness
 * @return  {Array}           The RGB representation
 */
Foxtrick.util.color.hslToRgb = function(h, s, l) {
	if (Array.isArray(h))
		return this.hslToRgb.apply(this, h);

	var r, g, b;

	if (s === 0) {
		r = g = b = l; // achromatic
	}
	else {
		var hue2rgb = function(p, q, t) {
			if (t < 0)
				t += 1;
			if (t > 1)
				t -= 1;
			if (t < 1 / 6)
				return p + (q - p) * 6 * t;
			if (t < 1 / 2)
				return q;
			if (t < 2 / 3)
				return p + (q - p) * (2 / 3 - t) * 6;
			return p;
		};

		var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
		var p = 2 * l - q;
		r = hue2rgb(p, q, h + 1 / 3);
		g = hue2rgb(p, q, h);
		b = hue2rgb(p, q, h - 1 / 3);
	}

	return [r * 255, g * 255, b * 255];
};

/**
 * Converts an RGB color value to HSV.
 * Colors may be passed as a single array.
 * Conversion formula adapted from http://en.wikipedia.org/wiki/HSV_color_space.
 * Assumes r, g, and b are contained in the set [0, 255] and
 * returns h, s, and v in the set [0, 1].
 *
 * @param   {number}  r       The red color value
 * @param   {number}  g       The green color value
 * @param   {number}  b       The blue color value
 * @return  {Array}           The HSV representation
 */
Foxtrick.util.color.rgbToHsv = function(r, g, b) {
	if (Array.isArray(r))
		return this.rgbToHsv.apply(this, r);

	r = r / 255; g = g / 255; b = b / 255;
	var max = Math.max(r, g, b), min = Math.min(r, g, b);
	var h, s, v = max;

	var d = max - min;
	s = max === 0 ? 0 : d / max;

	if (max == min) {
		h = 0; // achromatic
	}
	else {
		switch (max) {
			case r: h = (g - b) / d + (g < b ? 6 : 0); break;
			case g: h = (b - r) / d + 2; break;
			case b: h = (r - g) / d + 4; break;
		}
		h /= 6;
	}

	return [h, s, v];
};

/**
 * Converts an HSV color value to RGB.
 * Colors may be passed as a single array.
 * Conversion formula adapted from http://en.wikipedia.org/wiki/HSV_color_space.
 * Assumes h, s, and v are contained in the set [0, 1] and
 * returns r, g, and b in the set [0, 255].
 *
 * @param   {number}  h       The hue
 * @param   {number}  s       The saturation
 * @param   {number}  v       The value
 * @return  {Array}           The RGB representation
 */
Foxtrick.util.color.hsvToRgb = function(h, s, v) {
	if (Array.isArray(h))
		return this.hsvToRgb.apply(this, h);

	var r, g, b;

	var i = Math.floor(h * 6);
	var f = h * 6 - i;
	var p = v * (1 - s);
	var q = v * (1 - f * s);
	var t = v * (1 - (1 - f) * s);

	switch (i % 6) {
		case 0: r = v; g = t; b = p; break;
		case 1: r = q; g = v; b = p; break;
		case 2: r = p; g = v; b = t; break;
		case 3: r = p; g = q; b = v; break;
		case 4: r = t; g = p; b = v; break;
		case 5: r = v; g = p; b = q; break;
	}

	return [parseInt(r * 255, 10), parseInt(g * 255, 10), parseInt(b * 255, 10)];
};

/**
 * Converts an color in 6 digit hex representation to RGB.
 * returns r, g, and b in the set [0, 255].
 *
 * @param   {string}  hex     The 6 digit hex representation, # is not required
 * @return  {Array}           The RGB representation
 */
Foxtrick.util.color.hexToRgb = function(hex) {
	var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
	return result ? [
		parseInt(result[1], 16),
		parseInt(result[2], 16),
		parseInt(result[3], 16)
	] : null;
};

/**
 * Converts an rgb color into a 6 digit hex representation.
 * Colors may be passed as a single array.
 * returns hex with leading #.
 *
 * @param   {number}  r       The red color value
 * @param   {number}  g       The green color value
 * @param   {number}  b       The blue color value
 * @return  {string}          The hex representation
 */
Foxtrick.util.color.rgbToHex = function(r, g, b) {
	if (Array.isArray(r))
		return this.rgbToHex.apply(this, r);

	/* jshint -W016 */
	var rgb = b | (g << 8) | (r << 16);
	/* jshint +W016 */
	return '#' + rgb.toString(16);
};
