// Supporting script for an HTML+JS+DOM Color Picker applet
// By Daniel J. Grace
// Version 1.0 - 20040504
// RGB to HSL color conversion functions based on documentation at http://130.113.54.154/~monger/hsl-rgb.html


function dupe() {
	var i;
	rv = new Array();
	for(i in this) {
		rv[i] = this[i];
	}
	return(rv);
}
Object.prototype.dupe = dupe;

ColorMapper = new Array(
	new Array("r", 0, 255), 
	new Array("g", 0, 255), 
	new Array("b", 0, 255),
	new Array("h", 1, 360), 
	new Array("s", 1, 100), 
	new Array("l", 1, 100)
);
CurrentColor = convertRGBToHSL(new Array(0,0,0,0,0,0));
function setColorById(obj) {
	var cstr, cval, cidx;
	cstr = obj.id.slice(0,1);
	for(cidx = 0 ; cidx < ColorMapper.length ; ++cidx) {
		if(ColorMapper[cidx][0] == cstr) break;
	}
	cval = (parseInt(obj.id.slice(1)) / 255) * ColorMapper[cidx][2];
	if(cidx < ColorMapper.length) {
		CurrentColor[cidx] = cval;
		if(ColorMapper[cidx][1]) {
			CurrentColor = convertHSLToRGB(CurrentColor);
		} else {
			CurrentColor = convertRGBToHSL(CurrentColor);
		}
	}

	updateColorChart(CurrentColor);
}
function setColorCompomentFromText(obj, cidx) {
	var nv = parseInt(obj.value);
	if(nv == null || nv < 0 || isNaN(nv)) {
		nv = 0;
	} else if(nv > ColorMapper[cidx][2]) {
		nv = ColorMapper[cidx][2];
	}
	obj.value = nv;
	CurrentColor[cidx] = nv;
	if(ColorMapper[cidx][1]) {
		CurrentColor = convertHSLToRGB(CurrentColor);
	} else {
		CurrentColor = convertRGBToHSL(CurrentColor);
	}
	updateColorChart(CurrentColor);
}

function setColorByBG(obj) {
	// Mozilla's obj.style.backgroundColor returns colors in rgb(x, y, z) format.
	// IE's returns them in #rrggbb format.  I find this really annoying...
	// Check for the IE format first as it is more likely.
	
	// Check IE first as its more likely.
	if(obj.style.backgroundColor.slice(0,1) == "#" && obj.style.backgroundColor.length == 7) {
		CurrentColor[0] = parseInt(obj.style.backgroundColor.slice(1,3), 16);
		CurrentColor[1] = parseInt(obj.style.backgroundColor.slice(3,5), 16);
		CurrentColor[2] = parseInt(obj.style.backgroundColor.slice(5,7), 16);
	} else {
		var re = /([0-9]+)[\s,]+([0-9]+)[\s,]+([0-9]+)/;
		var result = re.exec(obj.style.backgroundColor);
		if(result == null) {
			alert(obj.style.backgroundColor + " is not a color that I recognize.");
		}
		var x;
		for(x = 0 ; x < 3 ; ++x) {
			CurrentColor[x] = parseInt(result[x+1]);
		}
	}
	CurrentColor = convertRGBToHSL(CurrentColor);
	updateColorChart(CurrentColor);
}

function setColorCompomentFromCC(obj) {
	// Check for #rrggbb first
	var re = /^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i;
	var result = re.exec(obj.value);
	if(result != null && result.length == 4) {
		CurrentColor[0] = parseInt(result[1], 16);
		CurrentColor[1] = parseInt(result[2], 16);
		CurrentColor[2] = parseInt(result[3], 16);
	} else {
		var re = /^#?([0-9a-f])([0-9a-f])([0-9a-f])$/i;
		var result = re.exec(obj.value);
		if(result != null && result.length == 4) {
			CurrentColor[0] = parseInt(result[1], 16) * 17;
			CurrentColor[1] = parseInt(result[2], 16) * 17;
			CurrentColor[2] = parseInt(result[3], 16) * 17;
		} else {
			CurrentColor[0] = CurrentColor[1] = CurrentColor[2] = 0;
		}
	}
	CurrentColor = convertRGBToHSL(CurrentColor);
	updateColorChart(CurrentColor);
}


function updateColorChart(color) {
	var cidx, value, e, tempcolor;
	if(!page_loaded) return;
	for(cidx = 0 ; cidx < ColorMapper.length ; ++cidx) {
		e = document.getElementById("component" + cidx);
		e.value = color[cidx];

		tempcolor = color.dupe();
		for(value = 0 ; value <= 255 ; value += 15) {
			e = document.getElementById(ColorMapper[cidx][0] + value.toString());
			tempcolor[cidx] = (value/255)*ColorMapper[cidx][2];
			if(tempcolor[cidx] > ColorMapper[cidx][2]) tempcolor[cidx] = ColorMapper[cidx][2];
			// If we're updating the RGB components (ColorMapper[cidx][1] is false), we don't need to perform
			// RGB->HSL conversions since only RGB is used in HTML color codes.  If we're updating the HSL
			// components, however, we must convert the HSL representation to RGB
			if(ColorMapper[cidx][1]) {
				tempcolor = convertHSLToRGB(tempcolor);
			}
			
			e.style.backgroundColor = getColorCode(tempcolor);
		}
	}
	e = document.getElementById("selected_color_b");
	e.style.backgroundColor = e.innerHTML = getColorCode(color);
	e = document.getElementById("selected_color_w");
	e.style.backgroundColor = e.innerHTML = getColorCode(color);
	e = document.getElementById("htmlcolorcode");
	e.value = getColorCode(color);
}

function getColorCode(color) {
	var r, g, b, rv;
	r = color[0].toString(16);
	g = color[1].toString(16);
	b = color[2].toString(16);
	if(r.length == 1) r = "0" + r;
	if(g.length == 1) g = "0" + g;
	if(b.length == 1) b = "0" + b;
	return "#" + r + g + b;
}

function normalizeColor(color) {
	var x, rv;
	rv = color.dupe();
	for(x = 0; x < rv.length ; ++x) {
		rv[x] /= ColorMapper[x][2];
	}
	return rv;
}

function scaleColor(color) {
	var x, rv;
	rv = color.dupe();
	for(x = 0; x < rv.length ; ++x) {
		rv[x] *= ColorMapper[x][2];
		rv[x] = parseInt(rv[x]);
		if(rv[x] > ColorMapper[x][2]) rv[x] = ColorMapper[x][2];
		
	}
	return rv;
}	

function convertRGBToHSL(color) {
	var ncolor = normalizeColor(color);
	var max = min = ncolor[0];

	// Lightness (5)
	if(ncolor[1] < min) min = ncolor[1];	else max = ncolor[1];
	if(ncolor[2] < min) min = ncolor[2];	else if(ncolor[2] > max) max = ncolor[2];
	ncolor[5] = (max+min)/2;

	// If it's gray, H and S are 0.
	if(min == max) {
		ncolor[3] = 0;
		ncolor[4] = 0;
	} else {
		// Saturation (4)
		if(color[5] < 0.5) {
			ncolor[4] = (max-min)/(max+min);
		} else {
			ncolor[4] = (max-min)/(2-max-min);
		}
		// Hue (3)
		if(max == ncolor[0]) {
			ncolor[3] =     (ncolor[1] - ncolor[2]) / (max-min);
		} else if(max == ncolor[1]) {
			ncolor[3] = 2 + (ncolor[2] - ncolor[0])/(max-min);
		} else {
			ncolor[3] = 4 + (ncolor[0] - ncolor[1])/(max-min);
		}
		ncolor[3] /= 6;
		if(ncolor[3] < 0) ncolor[3] += 1;
	}
	return scaleColor(ncolor);
}

function convertHSLToRGB(color) {
	var ncolor = normalizeColor(color), t1, t2, convArray, x;

	if(!ncolor[4]) {
		ncolor[0] = ncolor[1] = ncolor[2] = ncolor[5];
		return scaleColor(ncolor);
	}
	
	if(ncolor[5] < 0.5) {
		t2 = ncolor[5]*(1+ncolor[4])
	} else {
		t2 = (ncolor[5]+ncolor[4]) - (ncolor[5]*ncolor[4]);
	}

	t1 = (2*ncolor[5])-t2;
	
	convArray = new Array(
		ncolor[3] + 1/3,
		ncolor[3],
		ncolor[3] - 1/3
	);

	for(x = 0 ; x < convArray.length ; ++x) {
		if(convArray[x] > 1) convArray[x] -= 1;
		if(convArray[x] < 0) convArray[x] += 1;

		if(convArray[x] * 6 < 1) {
			ncolor[x] = t1 + (t2-t1)*6*convArray[x];
		} else if(convArray[x] * 2 < 1) {
			ncolor[x] = t2;
		} else if(convArray[x] * 3 < 2) {
			ncolor[x] = t1 + (t2-t1)*((2/3)-convArray[x])*6;
		} else {
			ncolor[x] = t1;
		}
	}
	return scaleColor(ncolor);
}
