//Copyright (C) Ben Parbury - All Rights Reserved. Unauthorized copying of this file, via any medium is strictly prohibited. Written by Ben Parbury <ben@gridlockinteractive.com> 2014
function RGB(r, g, b)
{
	this.Set = function(r, g, b)
	{
		this.r = Math.round(Math.clamp(r, 0, 255));
		this.g = Math.round(Math.clamp(g, 0, 255));
		this.b = Math.round(Math.clamp(b, 0, 255));
		gConsole.Assert(!isNaN(this.r) || !isNaN(this.g) || !isNaN(this.b));
	}
	
	this.Set(r,g,b);
	
	this.Copy = function(rgb)
	{
		this.Set(rgb.r, rgb.g, rgb.b);
	}
	
	this.Equal = function(rgb)
	{
		return this.r == rgb.r && this.g == rgb.g && this.b == rgb.b
	}
	
	this.Adjust = function(amount)
	{
		gConsole.Assert(!isNaN(amount));
		this.r += amount;
		this.g += amount;
		this.b += amount;
	}
	
	this.GetAdjusted = function(amount)
	{
		var r = this.r + amount;
		var g = this.g + amount;
		var b = this.b + amount;
		return new RGB(r, g, b);
	}
	
	this.GetScaled = function(scale)
	{
		var r = this.r * scale;
		var g = this.g * scale;
		var b = this.b * scale;
		return new RGB(r, g, b);
	}
	
	this.GetSaturated = function(amount)
	{
		var maximal = Math.max(this.r, this.g, this.b);
		var minimal = Math.min(this.r, this.g, this.b);
		var saturation = maximal - minimal;
		if(saturation > 0)
		{
			var r = this.r + (this.GetSaturationScale(this.r, minimal, saturation) * amount);
			var g = this.g + (this.GetSaturationScale(this.g, minimal, saturation) * amount);
			var b = this.b + (this.GetSaturationScale(this.b, minimal, saturation) * amount);
			return new RGB(r, g, b);
		}
		else
		{
			return new RGB(this.r, this.g, this.b);
		}
	}

	this.GetBrightness = function()
	{
		return (this.r + this.g + this.b)/3;
	}

	this.GetQuickBrightness = function()
	{
		return this.r;
	}
	
	this.GetInverted = function()
	{
		return new RGB(255-this.r, 255-this.g, 255-this.b);
	}
	
	this.GetSaturationScale = function(value, min, range)
	{
		return (((value - min)/range) * 2) - 1;
	}
	
	this.GetColor = function()
	{
		return "rgb(" + this.r + ", " + this.g + ", " + this.b + ")";
	}
	
	this.GetAlphaColor = function(alpha)
	{
		return "rgba(" + this.r + ", " + this.g + ", " + this.b + ", " + alpha + ")";
	}
	
	this.GetLerp = function(rgb, speed)
	{
		gConsole.Assert(!isNaN(speed));
		var r = this.r + Math.round((rgb.r - this.r) * speed);
		var g = this.g + Math.round((rgb.g - this.g) * speed);
		var b = this.b + Math.round((rgb.b - this.b) * speed);
		return new RGB(r, g, b);
	}
	
	this.GetBlend = function(rgb, blend)
	{
		blend = Math.min(Math.max(blend, 0), 1);
		var invBlend = 1 - blend;
		var r = Math.round((this.r * invBlend) + (rgb.r * blend));
		var g = Math.round((this.g * invBlend) + (rgb.g * blend));
		var b = Math.round((this.b * invBlend) + (rgb.b * blend));
		return new RGB(r, g, b);
	}
	
	this.Lerp = function(rgb, speed)
	{
		var distance = Math.abs(rgb.r - this.r) + Math.abs(rgb.g - this.g) + Math.abs(rgb.b - this.b);
		if(distance > 3)
		{
			gConsole.Assert(!isNaN(speed));
			this.r += Math.round((rgb.r - this.r) * speed);
			this.g += Math.round((rgb.g - this.g) * speed);
			this.b += Math.round((rgb.b - this.b) * speed);
			return true;
		}
		return false;
	}
	
	this.compare = function(rgb)
	{
		return rgb && (this.r == rgb.r && this.g == rgb.g && this.b == rgb.b);
	}
	
	this.GetHSV = function()
	{
		return new HSV(0, 0, 0).SetFromRGB(this.r, this.g, this.b);
	}
}

function RGBA(r, g, b, a)
{
	this.__proto__ = new RGB(r, g, b);
	this.a = a;
	
	this.GetColor = function()
	{
		return "rgba(" + this.r + ", " + this.g + ", " + this.b + ", " + this.a + ")";
	}
}

function HSV(h, s, v)
{
	this.h = h;
	this.s = s;
	this.v = v;

	this.SetFromRGB = function(r, g, b)
	{
		var n = Math.min(Math.min(r,g),b);
		var v = Math.max(Math.max(r,g),b);
		var m = v - n;
		if(m === 0) { return this; }
		var h = r===n ? 3+(b-g)/m : (g===n ? 5+(r-b)/m : 1+(g-r)/m);
		
		this.h = h===6?0:h
		this.s = m/v
		this.v = v;
		return this;
	}
	
	this.GetAdjustedHue = function(adjustment)
	{
		var h = (this.h + (adjustment/60)) % 6;
		return new HSV(h, this.s, this.v);
	}
	
	this.GetAdjustedVariance = function(adjustment)
	{
		var v = Math.clamp(this.v + adjustment, 0, 100);
		return new HSV(this.h, this.s, v);
	}
	
	this.GetAdjustedSaturation = function(adjustment)
	{
		var s = Math.clamp(this.s + adjustment, 0, 100);
		return new HSV(this.h, s, this.v);
	}

	this.GetRGB = function()
	{
		if(this.h === null) { new RGB(this.v, this.v, this.v); }
		var i = Math.floor(this.h);
		var f = i%2 ? this.h-i : 1-(this.h-i);
		var m = this.v * (1 - this.s);
		var n = this.v * (1 - this.s*f);
		switch(i)
		{
			case 1: return new RGB(n,this.v,m);
			case 2: return new RGB(m,this.v,n);
			case 3: return new RGB(m,n,this.v);
			case 4: return new RGB(n,m,this.v);
			case 5: return new RGB(this.v,m,n);
			default: return new RGB(this.v,n,m);
		}
	}
}
