/*
colourpicker.js
lastUpdate = "13 September 2008 19:07 UTC+1";
*/

function getZeroPrefixPad(value, padSize) {
	var v = "" + value;
	if (v.length < padSize) {
		v = getZeroPrefixPad("0" + v, padSize);
	}
	return v;
}

function getHexFromRGB(r, g, b) {
	return "#" + getZeroPrefixPad((r * 65536 + g * 256 + b).toString(16), 6);
}

function doTempAdjust(temp) {
	return (temp < 0 ? ++temp : (temp > 1 ? --temp : temp));
}

function doTempProcessing(temp1, temp2, temp3) {
	if (6 * temp3 < 1) {
		return (temp1 + (temp2 - temp1) * 6 * temp3);
	}
	else if (2 * temp3 < 1) {
		return temp2;
	}
	else if (3 * temp3 < 2) {
		return (temp1 + (temp2 - temp1) * ((2 / 3) - temp3) * 6);
	}
	else {
		return temp1;
	}
}


function getHSLtoRGB(hDec, sDec, lDec) {
	// Scale HSL values to unit range
	var h = Math.round(hDec) / 255;
	var s = Math.round(sDec) / 255;
	var l = Math.round(lDec) / 255;

	if (s == 0) {
		return {r:lDec, g:lDec, b:lDec }
	}
	else {
		var temp2 = (l < 0.5 ? l * (1.0 + s) : l + s - l * s);
		var temp1 = 2.0 * l - temp2;

		var rTemp = doTempAdjust(h + 1.0 / 3.0);
		var gTemp =	doTempAdjust(h);
		var bTemp = doTempAdjust(h - 1.0 / 3.0);

		var r = doTempProcessing(temp1, temp2, rTemp);
		var g = doTempProcessing(temp1, temp2, gTemp);
		var b = doTempProcessing(temp1, temp2, bTemp);

		return {r:Math.floor(r * 255), g:Math.floor(g * 255), b:Math.floor(b * 255)}
	}
}


function getHuePicker(step, granularity) {
	var o = [];
	var c = 0;

	o[c++] = "<div id=\"huebar\">";
	for (var hue=0; hue<256; hue+=step) {
		var objRGB = getHSLtoRGB(hue, 255, 128);
		var strHex = getHexFromRGB(objRGB.r, objRGB.g, objRGB.b);
		o[c++] = "<div class=\"c_" + hue + "_255_128\" style=\"background-color:" + strHex + ";\" onmousedown=\"doStoreColour(event); getSLSquareForHue(" + hue + ", " + granularity + ");\" onmouseover=\"doSpoutColour(event);\"></div>";
	}
	o[c++] = "</div>";

	var hueBar = document.getElementById("hueBar");
	if (hueBar) {
		hueBar.innerHTML = o.join("") + "<br />";
	}
}


function doGenerateSLSquare(hue, step) {
	var o = [];
	var c = 0;
	o[c++] = "<div id=\"saturationvlightnesssquare\" style=\"width: " + Math.ceil(256/step)*3 + "px;\" onmouseover=\"doSpoutColour(event)\" onmousedown=\"doStoreColour(event)\">";
	for (var l=0; l<256; l+=step) {
		for (var s=0; s<256; s+=step) {
			var objRGB = getHSLtoRGB(hue, s, l);
			var strHex = getHexFromRGB(objRGB.r, objRGB.g, objRGB.b)
			o[c++] = "<div class=\"c_" + hue + "_" + s + "_" + l + "\" style=\"background-color:" + strHex + ";\"></div>";
		}
		o[c++] = "<div class=\"slrow\"></div>";
	}
	o[c++] = "</div>";

	return o.join("");
}


function getGraduations(scaleStep) {
	var colour1 = window["bank1"];
	var colour2 = window["bank2"];

	if (colour1 && colour1.h >= 0 && colour2 && colour2.h >= 0) {
		var h1	= colour1.h;
		var h2	= colour2.h;
		var s1	= colour1.s;
		var s2	= colour2.s;
		var l1	= colour1.l;
		var l2	= colour2.l;

		if (scaleStep > 300) {
			alert("The highest value allowed is '300'");
			scaleStep = 300;
		}
		else if (scaleStep < 3) {
			alert("The lowest value allowed is '3'");
			scaleStep = 3;
		}
		--scaleStep;

		sliceWidth = Math.ceil(300 / scaleStep);

		var o = [];
		var c = 0;

		o[c++] = "<div class=\"gradtitle\">Changing Hue Only</div>";
		o[c++] = "<div class=\"graduation\" onmouseover=\"doSpoutEffectColour(event);\" onmousedown=\"doStoreColour(event);\">";
		for (i=0, h=h1; i <= scaleStep; ++i) {
			var objRGB = getHSLtoRGB(h, s1, l1);
			var strHex = getHexFromRGB(objRGB.r, objRGB.g, objRGB.b)
			o[c++] = "<div class=\"c_" + Math.round(h) + "_" + s1 + "_" + l1 + "\" style=\"background-color:" + strHex + "; width: " + sliceWidth +"px;\"></div>";
			h += (h2 - h1) / scaleStep;
		}
		o[c++] = "</div>";


		o[c++] = "<div class=\"gradtitle\">Changing Saturation Only</div>";
		o[c++] = "<div class=\"graduation\" onmouseover=\"doSpoutEffectColour(event);\" onmousedown=\"doStoreColour(event);\">";
		for (i=0, s=s1; i <= scaleStep; ++i) {
			var objRGB = getHSLtoRGB(h1, s, l1);
			var strHex = getHexFromRGB(objRGB.r, objRGB.g, objRGB.b)
			o[c++] = "<div class=\"c_" + h1 + "_" + Math.round(s) + "_" + l1 + "\" style=\"background-color:" + strHex + "; width: " + sliceWidth +"px;\"></div>";
			s += (s2 - s1) / scaleStep;
		}
		o[c++] = "</div>";


		o[c++] = "<div class=\"gradtitle\">Changing Lightness Only</div>";
		o[c++] = "<div class=\"graduation\" onmouseover=\"doSpoutEffectColour(event);\" onmousedown=\"doStoreColour(event);\">";
		for (i=0, l=l1; i <= scaleStep; ++i) {
			var objRGB = getHSLtoRGB(h1, s1, l);
			var strHex = getHexFromRGB(objRGB.r, objRGB.g, objRGB.b)
			o[c++] = "<div class=\"c_" + h1 + "_" + s1 + "_" + Math.round(l) + "\" style=\"background-color:" + strHex + "; width: " + sliceWidth +"px;\"></div>";
			l += (l2 - l1) / scaleStep;
		}
		o[c++] = "</div>";


		o[c++] = "<div class=\"gradtitle\">Changing Saturation and Lightness</div>";
		o[c++] = "<div class=\"graduation\" onmouseover=\"doSpoutEffectColour(event);\" onmousedown=\"doStoreColour(event);\">";
		for (i=0, s=s1, l=l1; i <= scaleStep; ++i) {
			var objRGB = getHSLtoRGB(h1, s, l);
			var strHex = getHexFromRGB(objRGB.r, objRGB.g, objRGB.b)
			o[c++] = "<div class=\"c_" + h1 + "_" + Math.round(s) + "_" + Math.round(l) + "\" style=\"background-color:" + strHex + "; width: " + sliceWidth +"px;\"></div>";
			s += (s2 - s1) / scaleStep;
			l += (l2 - l1) / scaleStep;
		}
		o[c++] = "</div>";


		o[c++] = "<div class=\"gradtitle\">Changing Hue and Lightness</div>";
		o[c++] = "<div class=\"graduation\" onmouseover=\"doSpoutEffectColour(event);\" onmousedown=\"doStoreColour(event);\">";
		for (i=0, h=h1, l=l1; i <= scaleStep; ++i) {
			var objRGB = getHSLtoRGB(h, s1, l);
			var strHex = getHexFromRGB(objRGB.r, objRGB.g, objRGB.b)
			o[c++] = "<div class=\"c_" + Math.round(h) + "_" + s1 + "_" + Math.round(l) + "\" style=\"background-color:" + strHex + "; width: " + sliceWidth +"px;\"></div>";
			h += (h2 - h1) / scaleStep;
			l += (l2 - l1) / scaleStep;
		}
		o[c++] = "</div>";


		o[c++] = "<div class=\"gradtitle\">Changing Hue and Saturation</div>";
		o[c++] = "<div class=\"graduation\" onmouseover=\"doSpoutEffectColour(event);\" onmousedown=\"doStoreColour(event);\">";
		for (i=0, h=h1, s=s1; i <= scaleStep; ++i) {
			var objRGB = getHSLtoRGB(h, s, l1);
			var strHex = getHexFromRGB(objRGB.r, objRGB.g, objRGB.b)
			o[c++] = "<div class=\"c_" + Math.round(h) + "_" + Math.round(s) + "_" + l1 + "\" style=\"background-color:" + strHex + "; width: " + sliceWidth +"px;\"></div>";
			h += (h2 - h1) / scaleStep;
			s += (s2 - s1) / scaleStep;
		}
		o[c++] = "</div>";


		o[c++] = "<div class=\"gradtitle\">Changing Hue, Saturation and Lightness</div>";
		o[c++] = "<div class=\"graduation\" onmouseover=\"doSpoutEffectColour(event);\" onmousedown=\"doStoreColour(event);\">";
		for (i=0, h=h1, s=s1, l=l1; i <= scaleStep; ++i) {
			var objRGB = getHSLtoRGB(h, s, l);
			var strHex = getHexFromRGB(objRGB.r, objRGB.g, objRGB.b)
			o[c++] = "<div class=\"c_" + Math.round(h) + "_" + Math.round(s) + "_" + Math.round(l) + "\" style=\"background-color:" + strHex + "; width: " + sliceWidth +"px;\"></div>";
			h += (h2 - h1) / scaleStep;
			s += (s2 - s1) / scaleStep;
			l += (l2 - l1) / scaleStep;
		}
		o[c++] = "</div>";


		document.getElementById("effects").innerHTML = o.join("");
	}
}


function getSLSquareForHue(hue, granularity) {
	var colourSquare = document.getElementById("colourSquare");
	if (colourSquare) {
		colourSquare.innerHTML = doGenerateSLSquare(hue, granularity);
	}
}


function getEventHSL(objEvent) {
	var objCell = getEventSourceNode(objEvent);
	if (objCell) {
		var strClass = objCell.className;
		if (strClass && window.reSlCell.test(strClass)) {
			return {h:+RegExp.$1, s:+RegExp.$2, l:+RegExp.$3}
		}
	}
}

function doSpoutColour(objEvent) {
	objHSL = getEventHSL(objEvent);
	if (objHSL) {
		var objRGB = getHSLtoRGB(objHSL.h, objHSL.s, objHSL.l);
		var strHex = getHexFromRGB(objRGB.r, objRGB.g, objRGB.b)
		window.spouters.elements['colourSpouter'].value = doSpoutDisplayFormat(objHSL, strHex, objRGB);
		window.spouters.elements['colourSpouterCanvas'].style.backgroundColor = strHex;
	}
}


function doSpoutEffectColour(objEvent) {
	objHSL = getEventHSL(objEvent);
	if (objHSL) {
		var objRGB	= getHSLtoRGB(objHSL.h, objHSL.s, objHSL.l);
		var strHex	= getHexFromRGB(objRGB.r, objRGB.g, objRGB.b)
		window.spouters.elements['colourEffectSpouter'].value = doSpoutDisplayFormat(objHSL, strHex, objRGB);
		window.spouters.elements['colourEffectSpouterCanvas'].style.backgroundColor = strHex;
	}
}


function doSpoutDisplayFormat(objHSL, strHex, objRGB) {
	switch (displayFormat) {
		case 1	: return "" + objRGB.r + "|" + objRGB.g + "|" + objRGB.b;
		case 2	: return "" + Math.floor(objHSL.h) + "|" + Math.floor(objHSL.s) + "|" + Math.floor(objHSL.l);
		default	: return strHex;
	}
}


function doStoreColour(objEvent) {
	objHSL = getEventHSL(objEvent);
	if (objHSL) {
		var objRGB	= getHSLtoRGB(objHSL.h, objHSL.s, objHSL.l);
		var strHex	= getHexFromRGB(objRGB.r, objRGB.g, objRGB.b);

		window.spouters.elements["colourStore"].value = doSpoutDisplayFormat(objHSL, strHex, objRGB);
		window.spouters.elements["colourStoreCanvas"].style.backgroundColor = strHex;
		window["colourStore"] = {h:objHSL.h, s:objHSL.s, l:objHSL.l};
	}
}


function doCopyStoreToBank(bankNumber) {
	var objHSL = window["colourStore"];
	if (objHSL && objHSL.h >= 0) {
		window["bank" + bankNumber] = objHSL;

		var objRGB = getHSLtoRGB(objHSL.h, objHSL.s, objHSL.l);
		if (objRGB && objRGB.r >= 0) {
			var strHex = getHexFromRGB(objRGB.r, objRGB.g, objRGB.b);

			window.spouters.elements["bank" + bankNumber].value = doSpoutDisplayFormat(objHSL, strHex, objRGB);
			window.spouters.elements["bank" + bankNumber + "Canvas"].style.backgroundColor = strHex;
		}
	}
}


function CP_Init() {
	var granularity = Number(document.getElementById("granularity_1").value);
	if (granularity < 3) {
		if (!confirm("A fineness value this low may cause\r\nyour web browser to freeze / stall for\r\nseveral seconds.\r\n\r\nProceed anyway?")) return false;
	}

	if (document.getElementById) {
		window.spouters	= document.forms['spoutersform']; // Done for speed
		window.displayFormat = 0; // 0 == #RRGGBB, 1 == R|G|B, 2 == H|S|L
		window.reSlCell = new RegExp().compile("c_(\\d+)_(\\d+)_(\\d+)"); // Match individual HSL values encoded in a class
		if (!window.reSlCell) {
			// Work around webkit bug
			window.reSlCell = new RegExp("c_(\\d+)_(\\d+)_(\\d+)");
		}

		getHuePicker(1, granularity);
		getSLSquareForHue(0, granularity);
	}
	else {
		alert("Sorry, your web browser or internet device does not\r\nsupport W3C recommendations:\r\n\r\nMethod getElementById() is not supported.");
	}
}



/*
Function: getEventSourceNode()
Description: Cross-browser means to grab hold of an event's target node
Returns:
History:
20060223 1723GMT	v1		Andrew Urquhart		Copied from http://www.quirksmode.org/js/events_properties.html
*/
function getEventSourceNode(e) {
	var targ = null;
	if (!e) {
		var e = window.event;
	}
	if (e.srcElement) {
		targ = e.srcElement;
	}
	else if (e.target) {
		targ = e.target;
	}
	if (targ.nodeType == 3) { // defeat Safari bug
		targ = targ.parentNode;
	}
	return targ;
}


// Try not to commandeer the default onload handler if possible
if (window.attachEvent) {
	window.attachEvent('onload', CP_Init);
}
else if (window.addEventListener) {
	window.addEventListener("load", CP_Init, false);
}
else {
	window.onload = CP_Init;
}

