

function TriMin(a, b, c)
{
    var abMin;
    if (a <= b)
        abMin = a;
    else
        abMin = b;
    
    if (abMin <= c)
        return abMin;
    
    return c;
}

function TriMax(a, b, c)
{
    var abMax;
    if (a > b)
        abMax = a;
    else
        abMax = b;
    
    if (abMax > c)
        return abMax;
    
    return c;
}


// this only deals with colors of the form "rgb(0, 255, 0)" and not
// arbitrary color names
function StringToRGBColor(s)
{
    var rgbColor = new Object();
        
    var pattern = /rgb\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/;

    var result = s.match(pattern);
    if (result)
    {
        rgbColor.red   = result[1] / 255;
        rgbColor.green = result[2] / 255;
        rgbColor.blue  = result[3] / 255;
    }
    else
    {
        rgbColor.red   = 0;
        rgbColor.green = 0;
        rgbColor.blue  = 0;
    }
    return rgbColor;
}

function RGBColorToString(rgbColor)
{
    return "rgb(" + Math.round(rgbColor.red   * 255) + ", " +
                    Math.round(rgbColor.green * 255) + ", " +
                    Math.round(rgbColor.blue  * 255) + ")";
}


// for debugging
function HSVColorToString(hsvColor)
{
    return "hue: " + hsvColor.hue +
            " saturation: " + hsvColor.saturation + 
            " value: " + hsvColor.value;
}

// r,g,b values are from 0 to 1
// h = [0,360], s = [0,1], v = [0,1]
//		if s == 0, then h = -1 (undefined)

// returns HSVObject
function RGBtoHSV(rgbColor)
{
    var hsvColor = new Object();

	var minVal, maxVal;

	minVal = TriMin(rgbColor.red, rgbColor.green, rgbColor.blue);
	maxVal = TriMax(rgbColor.red, rgbColor.green, rgbColor.blue);

	hsvColor.value = maxVal;

	var delta = maxVal - minVal;

	if (maxVal != 0)
	{
		hsvColor.saturation = delta / maxVal;		// s
    }
	else
	{
		// r = g = b = 0		// s = 0, v is undefined
		hsvColor.saturation = 1;
		hsvColor.hue = -1;
		return hsvColor;
	}

    if (delta == 0)
    {
        hsvColor.hue = 0;
    }
    else
    {
        if ( rgbColor.red == maxVal )
            hsvColor.hue = ( rgbColor.green - rgbColor.blue) / delta;	// between yellow & magenta
        else if (rgbColor.green == max)
            hsvColor.hue = 2 + (rgbColor.blue - rgbColor.red) / delta;	// between cyan & yellow
        else
            hsvColor.hue = 4 + (rgbColor.red - rgbColor.green) / delta;	// between magenta & cyan
    }
    
	hsvColor.hue *= 60;				// degrees
	if (hsvColor.hue < 0 )
		hsvColor.hue += 360;

    return hsvColor;
}

function HSVtoRGB(hsvColor)
{
    var rgbColor = new Object();
    
	if (hsvColor.saturation == 0)
	{
		// achromatic (grey)
		rgbColor.red    = hsvColor.value;
		rgbColor.green  = hsvColor.value;
		rgbColor.blue   = hsvColor.value;
		return rgbColor;
	}

    if (hsvColor.hue >= 360)
        hsvColor.hue -= 360;

	var h = hsvColor.hue / 60;			// sector 0 to 5
	var i = Math.floor(h);

	var v = hsvColor.value;
	var s = hsvColor.saturation;
	
	var f = h - i;			// factorial part of h
	var p = v * ( 1 - s );
	var q = v * ( 1 - s * f );
	var t = v * ( 1 - s * ( 1 - f ) );

	switch (i)
	{
		case 0:
			rgbColor.red    = v;
			rgbColor.green  = t;
			rgbColor.blue   = p;
			break;
		case 1:
			rgbColor.red    = q;
			rgbColor.green  = v;
			rgbColor.blue   = p;
			break;
		case 2:
			rgbColor.red    = p;
			rgbColor.green  = v;
			rgbColor.blue   = t;
			break;
		case 3:
			rgbColor.red    = p;
			rgbColor.green  = q;
			rgbColor.blue   = v;
			break;
		case 4:
			rgbColor.red    = t;
			rgbColor.green  = p;
			rgbColor.blue   = v;
			break;
		default:		// case 5:
			rgbColor.red    = v;
			rgbColor.green  = p;
			rgbColor.blue   = q;
			break;
	}

    return rgbColor;
}
