/* RGB <-> HSV */
/* R. McFarland 20060601 */

function RGBHSV(cache){
	this.R=0;
	this.G=0;
	this.B=0;
	this.H=0;
	this.S=0;
	this.V=0;
	this.caching=cache;

	this.rgbdict=Array();
	this.hsvdict=Array();

	this.hash=function(arr){
		h=360*360*arr[0]+256*arr[1]+arr[2];
		return h;
	}		
	
	this.setRGB=function(r,g,b){ // rgb 0-255
		this.R=r;
			if(this.R<0)this.R=0;
			if(this.R>255)this.R=255;
		this.R /= 255.0;
		this.G=g;
			if(this.G<0)this.G=0;
			if(this.G>255)this.G=255;
		this.G /= 255.0;
		this.B=b;
			if(this.B<0)this.B=0;
			if(this.B>255)this.B=255;
		this.B /= 255.0;
		h=this.hash(Array(r,g,b));
		if(this.caching && this.hsvdict[h]){
			this.H=this.hsvdict[h][0];
			this.S=this.hsvdict[h][1];
			this.V=this.hsvdict[h][2];
		}else{
			this.calcHSV();
			this.hsvdict[h]=Array(this.H,this.S,this.V);
		}
	}

	this.setHSV=function(h,s,v){ // hsv is hue (0-360),saturation (0-100),value (0-100)
		this.H=h%360; //degrees
		this.S=s;
			if(this.S<0)this.S=0;
			if(this.S>100)this.S=100;
		this.S /= 100.0;
		this.V=v;
			if(this.V<0)this.V=0;
			if(this.V>100)this.V=100;
		this.V /= 100.0;
		h=this.hash(Array(h,s,v));
		if(this.caching && this.rgbdict[h]){
			this.R=this.rgbdict[h][0];
			this.G=this.rgbdict[h][1];
			this.B=this.rgbdict[h][2];
		}else{
			this.calcRGB();
			this.rgbdict[h]=Array(this.R,this.G,this.B);
		}
	}
	
	this.calcRGB=function(){
		if (this.S==0.0){   // color is on black-and-white center line
			R=this.V;          // achromatic: shades of gray
			G=this.V;          // supposedly invalid for h=0 but who cares
			B=this.V;
		}else{ // chromatic color
			if (this.H==360.0){// 360 degrees same as 0 degrees
				hTemp=0.0;
			}else{
				hTemp=this.H;
			}
			hTemp=hTemp/60.0;   // h is now in [0,6)
		    
			fi=Math.floor(hTemp);  // largest integer <= h
			fr=hTemp-fi;          // fractional part of h 
			p=this.V*(1.0-this.S);
			q=this.V*(1.0-(this.S*fr));
			t=this.V*(1.0-(this.S*(1.0-fr)));
		
			if(fi==0){
				R = this.V;
				G = t;
				B = p;
			}else if(fi==1){
				R = q;
				G = this.V;
				B = p;
			}else if(fi==2){
				R = p;
				G = this.V;
				B = t;
			}else if(fi==3){
				R = p;
				G = q;
				B = this.V;
			}else if(fi==4){
				R = t;
				G = p;
				B = this.V;
			}else{
				R = this.V;
				G = p;
				B = q;
			}
		}
		this.R=R;
		this.G=G;
		this.B=B;
		return;		
	}
	
	this.calcHSV=function(){
		minVal=Math.min(Math.min(this.R, this.G), this.B);
		V=Math.max(Math.max(this.R, this.G), this.B);
		Delta=V-minVal;

		// Calculate saturation: saturation is 0 if r, g and b are all 0
		if (V==0.0){
			S=0.0;
		}else{
			S=Delta / V;
		}
		if (S==0.0){
			H=0.0;    // Achromatic: When s = 0, h is undefined but who cares
		}else{       // Chromatic
			if (this.R==V){ // between yellow and magenta [degrees]
				H=60.0*(this.G-this.B)/Delta;
			}else{
				if (this.G==V){ // between cyan and yellow
					H=120.0+60.0*(this.B-this.R)/Delta;
				}else{ // between magenta and cyan
					H=240.0+60.0*(this.R-this.G)/Delta;
				}
			}
		}
		if (H<0.0) H=H+360.0;
  		this.H=H; this.S=S; this.V=V;
		return;
	}
	
	this.value=function(){
		string='rgb('
			+Math.floor(this.R*255)+','
			+Math.floor(this.G*255)+','
			+Math.floor(this.B*255)+')';
		return string;
	}
}


