
ColorPicker = {};
ColorPicker.toHex = function(v) { 
	v=Math.round(Math.min(Math.max(0,v),255)); 
	return("0123456789ABCDEF".charAt((v-v%16)/16)+"0123456789ABCDEF".charAt(v%16)); 
}
ColorPicker.toDec = (function() {
	function dec(hx) {
		if(Math.abs(hx) <= 9) return hx;
		switch(hx) {
		case 'A':
			return 10;
		case 'B':
			return 11;
		case 'C':
			return 12;
		case 'D':
			return 13;
		case 'E':
			return 14;
		case 'F':
			return 15;
		}
		return null;
	}
	return (function hexToDec(hex) {
		hex = hex.toString();
		var out = 0;
		for(var i=0; i < hex.length; i++) {
			var d = dec(hex.substr(i,1));
			if(!d) return null;
			out += d * Math.pow(16, (hex.length-1)-i);
		}
		return out;
	});
})();
ColorPicker.RGB = {
	rgb2hex : function(rgb) {
		return(ColorPicker.toHex(rgb[0])+ColorPicker.toHex(rgb[1])+ColorPicker.toHex(rgb[2])); 
	},
	bitmaskToRGB : function(bm) {
		return [((bm >> 16) & 255), ((bm >> 8) & 255), (bm & 255)];
	},
	bitmaskToHex : function(bm) {
		return '#'+ColorPicker.RGB.rgb2hex(ColorPicker.RGB.bitmaskToRGB(bm));
	},
	darken : function(val, interval, units) {
		var out = [val[0],val[1],val[2]];
		for(var j=0; j < units; j++) {
			for(var i=0; i < val.length; i++) {
				var next = out[i] - interval;
				if(next < 0 || next > 255) continue;
				out[i] -= interval;
			}
		}
		return out;
	},
	isValidHex : function(hex) {
		if(!(hex.substring(0,1) == '#'))
			hex = '#' + hex;
		if(hex.length != 7) return false;
		hex = hex.toUpperCase();
		var rgb = [
			ColorPicker.toDec(hex.substr(1,2)), 
			ColorPicker.toDec(hex.substr(3,2)), 
			ColorPicker.toDec(hex.substr(5,2))];
		if(arguments[1])
			arguments[1][0] = rgb;
		if(!ColorPicker.RGB.isValidRGB(rgb)) return false;
		return hex;
	},
	isValidRGB : function(rgb) {
		if(rgb.length != 3) return false;
		for(var i=0; i < 3; i++) {
			if(!(typeof rgb[i] == 'number')) return false;
			if(rgb[i] < 0 || rgb[i] > 255)
				return false;
		}
		return true;
	}
}
ColorPicker.rainbow = function(interval) {
	var intv = interval;
	var rgb = [255,0,0];
	var index = 2;
	var phase = 1;
	function nextIndex() {
		if(index == 2) {
			index = 0;
			return;
		}
		index++;
	}
	this.next = function() {
		
		if(phase > 6) return false;
		
		var val = rgb;
		
		switch(phase%2) {
		case 1:
			if(val[index] + intv > 255) {
				phase++;
				nextIndex();
				return this.next();
			}
			val[index] += intv;
			return true;
		case 0:
			if(val[index] - intv < 0) {
				phase++;
				nextIndex();
				return this.next();
			}
			val[index] -= intv;
			return true;
		}
	}
	this.getValue = function() {
		return rgb;
	}
}
ColorPicker.init = function(conf) {
	
	var itv = conf.interval;
	var rows = conf.rows;
	var tileWidth = conf.tileWidth;
	var tileHeight = conf.tileHeight;
	var swatchWidth = conf.swatchWidth;
	var swatchHeight = conf.swatchHeight;
	var tileClickHandler = conf.tileClickHandler;
	var closeHandler = conf.closeHandler;
	var swatchDiv;
	var swatchInput;
	var selectedRGB;
	//var selectedTile;
	//var selectedColorHex;
	//var selectedColorRGBDec;
	
	return [ "div", { "class" : "ColorPickerWrapper" } ].parseJsonML(function(picker)  {
		[ "div", { "class" : "ColorPicker" } ].parseJsonML(function(el) {
			picker.appendChild(el);
			["div", {"class":"PanelWrapper"}].parseJsonML(function(panel) {
				el.appendChild(panel);
				panel.style.position = 'relative';
				["div", {"class":"Swatch"}].parseJsonML(function(swatch) {
					swatchDiv = swatch;
					panel.appendChild(swatch);
					swatch.style.fontSize = '0px';
					swatch.style.width = swatchWidth+'px';
					swatch.style.height = swatchHeight+'px';
					return swatch;
				});
				["div", {"class":"SwatchLabel"}, "Hex:"].parseJsonML(function(swatchLabel) {
					swatchLabel.style.position = 'absolute';
					swatchLabel.style.left = swatchWidth+'px';
					swatchLabel.style.top = '0px';
					[ "input" , { "type" : "text", "id" : "rgbVal", "name" : "rgbVal" } ].parseJsonML(function(ipt) {
						swatchInput = ipt;
						swatchLabel.appendChild(ipt);
						ipt.onkeyup = function() {
							var validHex;
							var rgb = [];
							if(swatchInput.value 
							   		&& (validHex=ColorPicker.RGB.isValidHex(swatchInput.value, rgb)) != false) {
								swatchInput.value = validHex;
								selectedRGB = rgb[0];
								swatchDiv.style.backgroundColor = validHex;
							}
						}
						return ipt;
					});
					panel.appendChild(swatchLabel);
					return swatchLabel;
				});
				["a", {"href":"#"}, "[ close ]"].parseJsonML(function(closeLink) {
					panel.appendChild(closeLink);
					closeLink.style.position = 'absolute';
					closeLink.style.right = '0px';
					closeLink.style.top = '0px';
					closeLink.onclick = function() {
						closeHandler.call(this);
						return false;
					}
					return closeLink;
				});
				return panel;
			});
			
			[ "div", { "class" : "Palette"} ].parseJsonML(function(palette) {
				el.appendChild(palette);
				palette.style.backgroundColor = '#000000';
				var rb = new ColorPicker.rainbow(itv);
				var cols = (255/itv)*6;
				var rows = ((255/itv)*2)+1;
		
				palette.style.position = 'relative';
				picker.style.width = palette.style.width = (tileWidth*(cols+1))+'px';
				palette.style.height = (tileHeight*(rows-2))+'px';
				
				for(var i=0; i < cols+1; i++) {
					var swatch = i < cols ? rb.getValue() : [(itv*(((255/itv)-1)/2)),(itv*(((255/itv)-1)/2)),(itv*(((255/itv)-1)/2))];
					inner:
					for(var j=0; j < rows; j++) {
						if(j == 0 || j == rows-1) continue inner;
						//$('dbg').innerHTML += j + ' ';
						[ "div" ].parseJsonML(function(tile) {
							palette.appendChild(tile);
							var u = j - ((rows-1)/2);
							var interval = u < 0 ? (itv*-1) : itv;
							var c = ColorPicker.RGB.darken(swatch, interval, Math.abs(u));
							
							//tile.style.lineHeight = '0px';
							tile.style.fontSize = '0px'; // ie
							tile.style.position = 'absolute';
							tile.style.width = tileWidth+'px';
							tile.style.height = tileHeight+'px';
							tile.style.top = ((j-1)*tileHeight)+'px';
							tile.style.left = (i*tileWidth)+'px';
							tile.colorRGBDec = c;
							tile.style.backgroundColor = (tile.colorHexString='#'+ColorPicker.RGB.rgb2hex(c));
							tile.onclick = function() {
								selectedRGB = tile.colorRGBDec;
								tileClickHandler.call(palette);
							}
							tile.onmouseout = function() {
								if(!selectedRGB) {
									swatchDiv.style.backgroundColor = null;
									swatchInput.value = '';
									return;
								}
								var selectedHex;
								swatchDiv.style.backgroundColor = (selectedHex='#'+ColorPicker.RGB.rgb2hex(selectedRGB));
								swatchInput.value = selectedHex;
							}
							return tile;
						}).onmouseover = function() {
							swatchDiv.style.backgroundColor = this.style.backgroundColor;
							swatchInput.value = this.colorHexString;
						};
					}
					//$('dbg').innerHTML += "<br/><br/>";
					rb.next();
				}
				//swatchInput.value = swatchDiv.style.backgroundColor = '#FFFFFF';
				return palette;
			});
			return el;
		});
		picker.setSelectedBitmask = function(bm) {
			swatchInput.value = ColorPicker.RGB.bitmaskToHex(bm);
			selectedRGB = ColorPicker.RGB.bitmaskToRGB(bm);
			swatchDiv.style.backgroundColor = swatchInput.value;
		}
		picker.clearSelected = function() {
			selectedRGB = null;
			swatchDiv.style.backgroundColor = null;
			swatchInput.value = '';
		}
		picker.getSelectedHexString = function() {
			if(!selectedRGB) return null;
			return '#'+ColorPicker.RGB.rgb2hex(selectedRGB);
		}
		picker.getSelectedBitmask = function() {
			if(!selectedRGB) return null;
			return ((selectedRGB[0] << 16) | (selectedRGB[1] << 8) | (selectedRGB[2] << 0));
		}
		return picker;
	});
}
