ColorPicker = new Class({
	initialize: function(objParent, InitialColor){
		//Check to see if the browser supports the canvas element.
		testcanvas = document.createElement("canvas");
		if(testcanvas.getContext){
			this.supportsCanvas = true;
			delete testelement;
		}else{
			this.supportsCanvas = false;
			delete testelement;
		}
		//if this is a color us it if not try to make a color out of it.
		if(InitialColor.isColor)
			this.CurColor = InitialColor;
		else
			this.CurColor = new Color(InitialColor);
		//If the object was passed as a string get and Element with that ID otherwise use the element.
		if(typeof objParent == 'string')
			this.Parent = $(objParent);
		else
			this.Parent = objParent;

		//These are member variables to hold function pointers to be called with the 
		//buttons in the color dialog.
		this.OKCallback = null;
		this.CancelCallback = null;

		//Create the main container for our color picker.
		this.Container = new Element("div");
		this.Container.setStyle("border", "solid 1px #000000");
		this.Container.setStyle("background-color", "#aaa");
		this.Container.setStyle("width", "460px");
		this.Container.setStyle("padding", "5px");
		this.Parent.appendChild(this.Container);

		//If the browser supports the canvas element create one instead of a container
		//for child divs
		if(this.supportsCanvas){
			//create the canvas Saturation Value Box.
			this.HueBar = new Element("canvas");
			this.HueBar.setStyle("cssFloat", "left");
			this.HueBar.setStyle("styleFloat", "left");
			this.HueBar.setStyle("margin-right", "5px");
			this.HueBar.width=30;
			this.HueBar.height=360;
			//Attach the event for clicks to the canvas element
			this.HueBar.addEvent("click", this.setCurrentHue.bind(this));
			this.Container.appendChild(this.HueBar);
		}else{
			//create the container for the hue bar.
			this.HueBar = new Element("div");
			this.HueBar.setStyle("width", "30px");
			this.HueBar.setStyle("cssFloat", "left");
			this.HueBar.setStyle("styleFloat", "left");
			this.HueBar.setStyle("margin-right", "5px");
			this.Container.appendChild(this.HueBar);
		}
		//If the browser supports the canvas element create one instead of a container
		//for child divs
		if(this.supportsCanvas){
			//create the canvas Saturation Value Box.
			this.SVBox = new Element("canvas");
			this.SVBox.setStyle("cssFloat", "left");
			this.SVBox.setStyle("styleFloat", "left");
			this.SVBox.width=350;
			this.SVBox.height=360;
			//Attach the event for clicks and mouse move to the canvas element
			this.SVBox.addEvent("click", this.setSelectedColor.bind(this));
			this.SVBox.addEvent("mousemove", this.setPreviewColor.bind(this));
			this.Container.appendChild(this.SVBox);
		}else{
			//create the container for the Saturation Value Box.
			this.SVBox = new Element("div");
			this.SVBox.setStyle("cssFloat", "left");
			this.SVBox.setStyle("styleFloat", "left");
			this.Container.appendChild(this.SVBox);
		}
		
		//create the container for the Color Swatches and Text Boxes.
		this.ColorInfo = new Element("div");
		this.ColorInfo.setStyle("cssFloat", "left");
		this.ColorInfo.setStyle("styleFloat", "left");
		this.ColorInfo.setStyle("text-align", "center");
		this.ColorInfo.setStyle("margin-left", "3px");
		this.Container.appendChild(this.ColorInfo);

		//Add an empty div to the end to clear the floats.
		this.ClearBreak = new Element("div");
		this.ClearBreak.setStyle("clear", "both");
		this.Container.appendChild(this.ClearBreak);

		//create the color swatches.
		this.SelectedColorLable = new Element("text");
		this.SelectedColorLable.textContent = "Color:";
		this.SelectedColor = new Element("div");
		this.SelectedColor.setStyle("width", "50px");
		this.SelectedColor.setStyle("height", "50px");
		this.SelectedColor.setStyle("margin-left", "auto");
		this.SelectedColor.setStyle("margin-right", "auto");
		this.ColorInfo.appendChild(this.SelectedColorLable);
		this.ColorInfo.appendChild(this.SelectedColor);

		this.PreviewColorLable = new Element("text");
		this.PreviewColorLable.textContent = "Preview:";
		this.PreviewColor = new Element("div");
		this.PreviewColor.setStyle("width", "50px");
		this.PreviewColor.setStyle("height", "50px");
		this.PreviewColor.setStyle("margin-left", "auto");
		this.PreviewColor.setStyle("margin-right", "auto");
		this.ColorInfo.appendChild(this.PreviewColorLable);
		this.ColorInfo.appendChild(this.PreviewColor);

		//Create the container for the hsv and rgb text boxes
		this.ColorInputsContainer = new Element("div");
		this.ColorInputsContainer.setStyle("width", "100%");
		this.ColorInputsContainer.setStyle("text-align", "left");
		this.ColorInputsContainer.setStyle("font-family", "Arial, Helvetica, sans-serif");
		this.ColorInputsContainer.setStyle("margin-left", "5px");
		this.ColorInfo.appendChild(this.ColorInputsContainer);

		//Create the hsv and rgb text fields.
		this.hLabel = new Element("text");
		this.hLabel.textContent = "H:";
		this.hInput = new Element("input");
		this.hInput.size = "3";
		this.hInput.name = "h";
		this.hInput.type = "text";
		this.hInput.addEvent('keyup', this.setHSL.bind(this));
		this.ColorInputsContainer.appendChild(new Element("br"));
		this.ColorInputsContainer.appendChild(this.hLabel);
		this.ColorInputsContainer.appendChild(this.hInput);
		this.ColorInputsContainer.appendChild(new Element("br"));

		this.sLabel = new Element("text");
		this.sLabel.textContent = "S:";
		this.sInput = new Element("input");
		this.sInput.size = "3";
		this.sInput.name = "s";
		this.sInput.type = "text";
		this.sInput.addEvent('keyup', this.setHSL.bind(this));
		this.ColorInputsContainer.appendChild(this.sLabel);
		this.ColorInputsContainer.appendChild(this.sInput);
		this.ColorInputsContainer.appendChild(new Element("br"));

		this.vLabel = new Element("text");
		this.vLabel.textContent = "V:";
		this.vInput = new Element("input");
		this.vInput.size = "3";
		this.vInput.name = "v";
		this.vInput.type = "text";
		this.vInput.addEvent('keyup', this.setHSL.bind(this));
		this.ColorInputsContainer.appendChild(this.vLabel);
		this.ColorInputsContainer.appendChild(this.vInput);
		this.ColorInputsContainer.appendChild(new Element("br"));

		this.rLabel = new Element("text");
		this.rLabel.textContent = "R:";
		this.rInput = new Element("input");
		this.rInput.size = "3";
		this.rInput.name = "r";
		this.rInput.type = "text";
		this.rInput.addEvent('keyup', this.setRGB.bind(this));
		this.ColorInputsContainer.appendChild(new Element("br"));
		this.ColorInputsContainer.appendChild(this.rLabel);
		this.ColorInputsContainer.appendChild(this.rInput);
		this.ColorInputsContainer.appendChild(new Element("br"));

		this.gLabel = new Element("text");
		this.gLabel.textContent = "G:";
		this.gInput = new Element("input");
		this.gInput.size = "3";
		this.gInput.name = "g";
		this.gInput.type = "text";
		this.gInput.addEvent('keyup', this.setRGB.bind(this));
		this.ColorInputsContainer.appendChild(this.gLabel);
		this.ColorInputsContainer.appendChild(this.gInput);
		this.ColorInputsContainer.appendChild(new Element("br"));

		this.bLabel = new Element("text");
		this.bLabel.textContent = "B:";
		this.bInput = new Element("input");
		this.bInput.size = "3";
		this.bInput.name = "b";
		this.bInput.type = "text";
		this.bInput.addEvent('keyup', this.setRGB.bind(this));
		this.ColorInputsContainer.appendChild(this.bLabel);
		this.ColorInputsContainer.appendChild(this.bInput);
		this.ColorInputsContainer.appendChild(new Element("br"));

		//create the ok button and set its onclick callback
		this.okInput = new Element("input");
		this.okInput.name = "OK";
		this.okInput.value = "OK";
		this.okInput.type = "button";
		this.okInput.addEvent('click', this.handleOK.bind(this));
		this.ColorInputsContainer.appendChild(this.okInput);
		this.ColorInputsContainer.appendChild(new Element("br"));
		
		//create the ok button and set its onclick callback
		this.cancelInput = new Element("input");
		this.cancelInput.name = "Cancel";
		this.cancelInput.value = "Cancel";
		this.cancelInput.type = "button";
		this.cancelInput.addEvent('click', this.handleCancel.bind(this));
		this.ColorInputsContainer.appendChild(this.cancelInput);
		this.ColorInputsContainer.appendChild(new Element("br"));

		//Draw the Hue Bar
		this.drawHueBar();
		//Draw the SVBox
		this.drawSVBox();
	},
	//Iterates through all 360 hues and creates a 1px by 30px div for each hue.
	drawHueBar: function (){
		if(this.supportsCanvas){
			//get the multiplyer for the hue range based on the height of the hue bar.
			hSteps = 360 / this.HueBar.height;
			hColor = new Color([0,100,100], 'hsb');
			//Get a 2d context to the hue bar canvas element.
			myCTX = this.HueBar.getContext('2d');
			strhHex = "";
			//Iterate over the hight of the hue bar filling 1px tall areas
			//with the proper hue.
			for(hi =  this.HueBar.height; hi > 0; hi--){
				//Get the color for the hew at this iteration.
				hColor.changeHue(hi*hSteps);
				//Get the hex string of the color.
				strhHex = hColor.rgbToHex();
				//Set the context's fillStyle to the color.
				myCTX.fillStyle = strhHex;
				//fill from the left of the hue bar, to the width of the hue bar
				//with the offset hi pixels from the bottom with a height of 1px.
				myCTX.fillRect(0, this.HueBar.height-hi, this.HueBar.width, 1);
			}		
		}else{		
			//Create a new color with hue at 0 and S and V at 100%
			hsvColor = new Color([0,100,100], 'hsb');
			//Create the one Hue element and set it's styles.
			fcoDiv = new Element("div");
			fcoDiv.setStyle("width","30px");
			fcoDiv.setStyle("height","1px");
			//Loop through the hues
			for(ci = 0; ci < 360; ci++){
				//User the changeHue to change the existing color object's hue.
				hsvColor.changeHue(ci);
				//Clone the Hue element and inject it inside the Hue Bar.
				coDiv = fcoDiv.clone().injectInside(this.HueBar);
				//Set the huse of the new Hue Element
				coDiv.setStyle("background-color", hsvColor);
				//Set the onClick callback function for the new Hue element.
				coDiv.addEvent('click', this.setCurrentHue.bind(this));
			}
		}
	},
	//Draw a SV box that is as tall as the HUE Bar.
	drawSVBox: function(objsvDiv){
		if(this.supportsCanvas){
			//Get the rgb multiplyer for the number of steps over the height of the SVBox
			vSteps = 255 / this.SVBox.height;
			//Get the value multiplyer for the number of steps over the height of the SVBox 
			svSteps = 100 / this.SVBox.height;
			//Create a new color for calculating each rows color ranges.
			svColor = new Color([this.CurColor.hsb[0], 100, 100], "hsb");
			//Get a 2d context to the SVBox canvas element.
			myCTX = this.SVBox.getContext('2d');
			strsvHex = "";
			//Iterate over the hieght of the SVBox.
			for(vi =  this.SVBox.height; vi > 0; vi--){
				//Set the brightness for this row
				svColor.changeBrightness(vi*svSteps);
				//Get the hex string for the current brightness.
				strsvHex = svColor.rgbToHex();
				//Create a new linear Gradient from the canvas context that goes
				//from the left to the right.
				myLinearGrad = myCTX.createLinearGradient(0, 0, this.SVBox.width, 0);
				//Add a color stop to the gradient that is the current
				//bright ness no need to to the HSV conversion here 
				myLinearGrad.addColorStop(0, "rgb("+vi+","+vi+","+vi+")"); 
				//Add a color stop that is based on the current Hue
				myLinearGrad.addColorStop(1, strsvHex); 
				//Set the canvas context's fill style to our current gradient.
				myCTX.fillStyle = myLinearGrad;
				//Fill the row at 1px high.
				myCTX.fillRect(0, this.SVBox.height-vi, this.SVBox.height, 1);
			}		
		}else{		
			//Specify the size of the SV Box svSize is used for both width and height.
			svSize = 35;
			//Set the size of the "pixels" for the SVBox.
			pixelSize = 10;
			//Get the multiple required to go from 0 to 100 is svSize steps.
			svStep = 100/svSize;
			
			//Create the color we will use to set the color of the SV Pixels
			svColor =  new Color([this.CurColor[0],this.CurColor[1],this.CurColor[2]]);
			
			//Create a div that will hold 1 row of pixels.
			// this is done to prevent to reduce the number of 
			// appends into the document.
			rcDiv = new Element("div");
			rcDiv.style.clear = "left";
			rcDiv.style.width = (svSize*pixelSize)+"px";
			rcDiv.style.height = pixelSize+"px";
			
			//Create the one pixel that we will clone for each pixel.
			fcoDiv = new Element("div");
			fcoDiv.setStyle("width", pixelSize + "px");
			fcoDiv.setStyle("height", pixelSize + "px");
			fcoDiv.setStyle("cssFloat", "left");
			fcoDiv.setStyle("styleFloat", "left");

			//Iterate over each step in the row injecting cloaned divs into it.
			for(ei = 0; ei < svSize; ei++){
				fcoDiv.clone().injectInside(rcDiv);
			}

			//Iterate over the height of the SV box setting each rows colors.
			for(vi = svSize; vi >= 0; vi -= 1){
				//set the brightness for this row.
				svColor.changeBrightness(vi*svStep);
				//Cloan the row into the SVBox container.
				trcDiv = rcDiv.clone().injectInside(this.SVBox);
				//Get the children of this row.
				arChildren = trcDiv.getChildren();
				//Iterate the children of this row.
				for(ci = 0; ci < arChildren.length; ci++){
					//Change the saturation for each pixe.
					svColor.changeSaturation(ci*svStep);
					arChildren[ci].setStyle("background-color", svColor);
					//Set the events for each pixels for color choice and preview.
					arChildren[ci].addEvent('click', this.setSelectedColor.bind(this));
					arChildren[ci].addEvent('mouseover', this.setPreviewColor.bind(this));
				}
			}
		}
	},
	//Update the pixels in the SVBox when the hue is clicked.
	UpdateSVBox: function (){
		if(this.supportsCanvas){
			vSteps = 255 / this.SVBox.height;
			svSteps = 100 / this.SVBox.height;
			svColor = new Color([this.CurColor.hsb[0], 100, 100], "hsb");
			myCTX = this.SVBox.getContext('2d');
			strsvHex = "";
			for(vi =  this.SVBox.height; vi > 0; vi--){
				svColor.changeBrightness(vi*svSteps);
				strsvHex = svColor.rgbToHex();
				myLinearGrad = myCTX.createLinearGradient(0, 0, this.SVBox.width, 0);
				myLinearGrad.addColorStop(0, "rgb("+vi+","+vi+","+vi+")"); 
				myLinearGrad.addColorStop(1, strsvHex); 
				myCTX.fillStyle = myLinearGrad;
				myCTX.fillRect(0, this.SVBox.height-vi, this.SVBox.height, 1);
			}		
		}else{		
			//Get the child rows in the SVBox
			arSVRows = this.SVBox.getChildren();
			//set the svSize to the number of rows.
			svSize = arSVRows.length;
			//Get the multiple required to go from 0 to 100 is svSize steps.
			svStep = 100/svSize;
			//Create a color for calculating the HSV of each pixel.
			svColor =  new Color([this.CurColor[0],this.CurColor[1],this.CurColor[2]]);
			
			//Loop over all of the rows.
			for(vi = svSize - 1; vi >= 0; vi -= 1){
				//set the brightness for this row.
				svColor.changeBrightness(vi*svStep);
				//Get the children of the row.
				siChildren = arSVRows[svSize - vi - 1].getChildren();
				//Iterate the children of this row.
				for(si = 0; si < siChildren.length; si++){
					//Change the saturation for each pixe.
					svColor.changeSaturation(si*svStep);
					siChildren[si].setStyle("background-color", svColor);		
				}	
			}
		}

	},
	setCurrentHue: function (e){
		//IE uses srcElement instead of target to specify the 
		//element that was clicked.
		if(!e.target)
			e.target = e.srcElement;
		
		if(this.supportsCanvas){
			//Get a 2d context to the SVBox canvas element.
			myCTX = this.HueBar.getContext('2d');
			//Get the coordinates for our hue bar.
			hBoxCoords = this.HueBar.getCoordinates();
			//subtract the left and top of the hue bar from the event.clentX and y then add the window.scrollX and Y
			// to get the click position in the Hue bar and pass those in to the contexts getImageData function.
			myImageData = myCTX.getImageData(e.clientX - hBoxCoords.left + window.scrollX, e.clientY - hBoxCoords.top + window.scrollY, 1, 1);
			//Create a hue color based of the ImageData returned by the getImageData function.
			CurHueColor = new Color([myImageData.data[0], myImageData.data[1], myImageData.data[2]]);
		}else{
			//Create a color object from the background of the target so we can
			//get its Hue.
			CurHueColor = new Color(e.target.getStyle("background-color"));
		}
		//Set the Hue of the current color.
		this.CurColor.changeHue(CurHueColor.hsb[0]);
		//Tell the SVBox to update.
		this.UpdateSVBox();
		//Set the selected color to the current color.
		this.SelectedColor.setStyle("background-color", this.CurColor);
		//Update the hsv and rgb text boxes.
		this.hInput.value = this.CurColor.hsb[0];
		this.sInput.value = this.CurColor.hsb[1];
		this.vInput.value = this.CurColor.hsb[2];
		this.rInput.value = this.CurColor[0];
		this.gInput.value = this.CurColor[1];
		this.bInput.value = this.CurColor[2];	
	},
	setPreviewColor: function (e){
		//IE uses srcElement instead of target to specify the 
		//element that was clicked.
		if(!e.target)
			e.target = e.srcElement;
		if(this.supportsCanvas){
			myCTX = this.SVBox.getContext('2d');
			SVBoxCoords = this.SVBox.getCoordinates();

			myImageData = myCTX.getImageData(e.clientX - SVBoxCoords.left + window.scrollX, e.clientY - SVBoxCoords.top + window.scrollY, 1, 1);
			nColor = new Color([myImageData.data[0], myImageData.data[1], myImageData.data[2]]);
			this.PreviewColor.setStyle("background-color", nColor);		
		}else{
			nColor = new Color(e.target.getStyle("background-color"));
			this.PreviewColor.setStyle("background-color", nColor);
		}
	},

	setSelectedColor: function (e){
		//IE uses srcElement instead of target to specify the 
		//element that was clicked.
		if(!e.target)
			e.target = e.srcElement;
		if(this.supportsCanvas){
			myCTX = this.SVBox.getContext('2d');
			SVBoxCoords = this.SVBox.getCoordinates();

			myImageData = myCTX.getImageData(e.clientX - SVBoxCoords.left + window.scrollX, e.clientY - SVBoxCoords.top + window.scrollY, 1, 1);
			nColor = new Color([myImageData.data[0], myImageData.data[1], myImageData.data[2]]);
		}else{
			nColor = new Color(e.target.getStyle("background-color"));
		}
		//nColor = new Color(e.target.getStyle("background-color"));
		this.CurColor = nColor;
		this.SelectedColor.setStyle("background-color", nColor);
		this.hInput.value = nColor.hsb[0];
		this.sInput.value = nColor.hsb[1];
		this.vInput.value = nColor.hsb[2];
		this.rInput.value = nColor[0];
		this.gInput.value = nColor[1];
		this.bInput.value = nColor[2];	

	},
	setRGB: function (){
		nc = new Color([this.rInput.value, this.gInput.value, this.bInput.value]);
		this.CurColor = nc;
		this.hInput.value = nc.hsb[0];
		this.sInput.value = nc.hsb[1];
		this.vInput.value = nc.hsb[2];
		this.SelectedColor.setStyle("background-color", nc);
		this.PreviewColor.setStyle("background-color", nc);
		this.UpdateSVBox();
	},
	setHSL: function (){
		nc = new Color([this.hInput.value, this.sInput.value, this.vInput.value], 'hsb');
		this.CurColor = nc;
		this.rInput.value = nc[0];
		this.gInput.value = nc[1];
		this.bInput.value = nc[2];	
		this.SelectedColor.setStyle("background-color", nc);
		this.PreviewColor.setStyle("background-color", nc);
		this.UpdateSVBox();
	},
	//When the ok button is clicked call this.OKCallBack();
	handleOK: function (){
		if(this.OKCallback != null)
			this.OKCallback();
	},
	//When the ok button is clicked call this.CancelCallback();
	handleCancel: function (){
		if(this.CancelCallback != null)
			this.CancelCallback();
	}

});