com={};
com.saltcollective={};
com.saltcollective.Phocus=
{
	register:function(object,nicename,instance)
	{
		if(com.saltcollective.Phocus[nicename]!=object)
			return false;
		if(typeof phocus!='object')
			phocus={};
		phocus[nicename]=instance ? new object : object;
	},
	extend:function(P)
	{
		function Dummy() {}
		Dummy.prototype = P.prototype;
		return new Dummy();
	}
}
phocus={};

// Utility functionality
com.saltcollective.Phocus.Util=
{
	isinstanceof:function(obj,classa)
	{
			while (obj != null)
			{
				if (obj == classa.prototype)
					return true;
				obj = obj.__proto__;
			}
			return false;
	},
	extend:function(classa,classb)
	{
		classa.__proto__=classb.prototype;
	},
	snapin:function(classa,classb)
	{
		for(var i in classa.prototype)
			classb.prototype[i]=classa.prototype[i];
	},
	isIE:function(qualifier)
	{
		if(!qualifier)
			qualifier='';
		var b=phocus.Util.makeBrowser();
		if(b.isIE && b['isIE'+qualifier])
			return true;
	},
	makeBrowser:function()
	{
		if(typeof phocus.Util.browser == 'undefined')
		{
			phocus.Util.browser={};
			var ua = navigator.userAgent.toLowerCase(); 
			phocus.Util.browser.ua = ua;
			phocus.Util.browser.isMozilla   = (phocus.Util.browser.isGecko && ua.indexOf("gecko/") + 14 == ua.length);
			phocus.Util.browser.isIE        = ( (ua.indexOf("msie") != -1) && (ua.indexOf("opera") == -1) && (ua.indexOf("webtv") == -1) ); 
			phocus.Util.browser.isOpera     = (ua.indexOf("opera") != -1); 
			phocus.Util.browser.isKonqueror = (ua.indexOf("konqueror") != -1);
			phocus.Util.browser.versionMinor = parseFloat(navigator.appVersion);
			if (phocus.Util.browser.isIE && phocus.Util.browser.versionMinor >= 4) {
				phocus.Util.browser.versionMinor = parseFloat( ua.substring( ua.indexOf('msie ') + 5 ) );
			}
			else if (phocus.Util.browser.isOpera) {
				if (ua.indexOf('opera/') != -1) {
					phocus.Util.browser.versionMinor = parseFloat( ua.substring( ua.indexOf('opera/') + 6 ) );
				}
				else {
					phocus.Util.browser.versionMinor = parseFloat( ua.substring( ua.indexOf('opera ') + 6 ) );
				}
			}
			
			phocus.Util.browser.versionMajor = parseInt(phocus.Util.browser.versionMinor); 
			phocus.Util.browser.geckoVersion = ( (phocus.Util.browser.isGecko) ? ua.substring( (ua.lastIndexOf('gecko/') + 6), (ua.lastIndexOf('gecko/') + 14) ) : -1 );
			phocus.Util.browser.isWin   = (ua.indexOf('win') != -1);
			phocus.Util.browser.isWin32 = (phocus.Util.browser.isWin && ( ua.indexOf('95') != -1 || ua.indexOf('98') != -1 || ua.indexOf('nt') != -1 || ua.indexOf('win32') != -1 || ua.indexOf('32bit') != -1) );
			phocus.Util.browser.isMac   = (ua.indexOf('mac') != -1);
			
			phocus.Util.browser.isIE4x = (phocus.Util.browser.isIE && phocus.Util.browser.versionMajor == 4);
			phocus.Util.browser.isIE4up = (phocus.Util.browser.isIE && phocus.Util.browser.versionMajor >= 4);
			phocus.Util.browser.isIE5x = (phocus.Util.browser.isIE && phocus.Util.browser.versionMajor == 5);
			phocus.Util.browser.isIE55 = (phocus.Util.browser.isIE && phocus.Util.browser.versionMinor == 5.5);
			phocus.Util.browser.isIE5up = (phocus.Util.browser.isIE && phocus.Util.browser.versionMajor >= 5);
			phocus.Util.browser.isIE6x = (phocus.Util.browser.isIE && phocus.Util.browser.versionMajor == 6);
			phocus.Util.browser.isIE6up = (phocus.Util.browser.isIE && phocus.Util.browser.versionMajor >= 6);
			phocus.Util.browser.isIE7up = (phocus.Util.browser.isIE && phocus.Util.browser.versionMajor >= 7);
			
			phocus.Util.browser.isIE4xMac = (phocus.Util.browser.isIE4x && phocus.Util.browser.isMac);
		}
		return phocus.Util.browser;
	}
}
com.saltcollective.Phocus.register(com.saltcollective.Phocus.Util,'Util');

// Phocus colour object - performs colour calculations
com.saltcollective.Phocus.Colour=function(dec)
{
	if(dec)
	{
		if(typeof dec == 'object' && typeof dec.setHEX != 'undefined')
			this.setHEX(dec.toString());
		else if(typeof dec == 'string' && dec.indexOf('#')!=-1)
			this.setHEX(dec);
		else
			this.setDEC(dec);
	}
}
$pr=com.saltcollective.Phocus.Colour.prototype;
$pr.r=0;
$pr.g=0;
$pr.b=0;
$pr.toString=function()
{
	return '#'+this.getHEX();
}
$pr.setRGB=function(r,g,b)
{
	this.r=isNaN(r) ? 0 : r;
	this.g=isNaN(g) ? 0 : g;
	this.b=isNaN(b) ? 0 : b;
}
$pr.setHEX=function(hex)
{
	if(hex.indexOf("#")>-1)
		hex=hex.split("#")[1];

	if(hex.length == 6)
	{
		r=hex.substr(0,2);
		g=hex.substr(2,2);
		b=hex.substr(4,2);
	} else if(hex.length == 3)
	{
		r=hex.substr(0,1);
		r+=r;
		g=hex.substr(1,1);
		g+=g;
		b=hex.substr(2,1);
		b+=b;
	} else if(hex.length == 2)
	{
		r=hex.substr(0,2);
		g=r;
		b=g;
	} else if(hex.length == 1)
	{
		r=hex.substr(0,1);
		r+=r;
		g=r;
		b=g;
	}
	
	var r=parseInt(r,16);
	var g=parseInt(g,16);
	var b=parseInt(b,16);
	this.setRGB(r,g,b);
}
$pr.setDEC=function(dec)
{
	if(isNaN(dec)) var dec = 0;
	var hex='000000';
	hex+=Math.round(dec).toString(16);
	hex=hex.substr(hex.length-6,6);
	
	this.setHEX(hex);
}
$pr.getRGB=function()
{
	return [this.r,this.g,this.b];
}
$pr.getHEX=function()
{
	var hex='000000';
	hex+=Math.round(this.getDEC()).toString(16);
	return hex.substr(hex.length-6,6);
}
$pr.getDEC=function()
{
	return (this.getr() << 16 | this.getg() << 8 | this.getb());
}
$pr.getr=function()
{
	return this.r<0 || isNaN(this.r) ? 0 : this.r>255 ? 255 : this.r;
}
$pr.getg=function()
{
	return this.g<0 || isNaN(this.g) ? 0 : this.g>255 ? 255 : this.g;
}
$pr.getb=function()
{
	return this.b<0 || isNaN(this.b) ? 0 : this.b>255 ? 255 : this.b;
}
$pr.add=function(c)
{
	var rtn=new com.saltcollective.Phocus.Colour();
	rtn.setRGB(this.r+c.r,this.g+c.g,this.b+c.b);
	return rtn;
}
$pr.subtract=function(c)
{
	var rtn=new com.saltcollective.Phocus.Colour();
	rtn.setRGB(this.r-c.r,this.g-c.g,this.b-c.b);
	return rtn;
}
$pr.scale=function(per)
{
	var rtn=new com.saltcollective.Phocus.Colour();
	rtn.setRGB(this.r/100*per,this.g/100*per,this.b/100*per);
	return rtn;
}
$pr.invert=function()
{
	this.setRGB(255-this.getr(),255-this.getg(),255-this.getb());
}
com.saltcollective.Phocus.register(com.saltcollective.Phocus.Colour,'Colour');

// Phocus point object - deals with points in all their glory
com.saltcollective.Phocus.Point=function(x,y)
{
	this.x=x;
	this.y=y;
}
$pr=com.saltcollective.Phocus.Point.prototype;
$pr.toString=function()
{
	var rx=Math.round(this.x*1000)/1000;
	var ry=Math.round(this.y*1000)/1000;
	return "point [x: "+rx+",y: "+ry+"]";
}
$pr.reset=function(x,y)
{
	this.x=x;
	this.y=y;
}
$pr.getClone=function(){return new com.saltcollective.Phocus.Point(this.x, this.y);}
$pr.equals=function(v){return (this.x==v.x && this.y==v.y);}
$pr.add=function(v)
{
	this.x+=v.x;
	this.y+=v.y;
}
$pr.addnew=function(v){return new com.saltcollective.Phocus.Point(this.x+v.x,this.y+v.y);}
$pr.subtract=function(v)
{
	this.x-=v.x;
	this.y-=v.y;
}
$pr.subtractnew=function(v){return new com.saltcollective.Phocus.Point(this.x-v.x,this.y-v.y);}
$pr.negate=function()
{
	this.x*=-1;
	this.y*=-1;
}
$pr.negatenew=function()
{return new com.saltcollective.Phocus.Point(this.x*-1,this.y*-1);}
$pr.scale=function(s)
{
	this.x*=s;
	this.y*=s;
}
$pr.scalenew=function(s)
{return new com.saltcollective.Phocus.Point(this.x*s,this.y*s);}
$pr.getlength=function(){return Math.sqrt(x*x+y*y);}
$pr.setlength=function(a)
{
	var r=this.getLength();
	if(r)
		this.scale(a/r);
	else
		this.x=a;
}
$pr.dot=function(v){return this.x*v.x + this.y*v.y;}
com.saltcollective.Phocus.register(com.saltcollective.Phocus.Point,'Point');

// Runtime, for animation, delays and events
com.saltcollective.Phocus.Runtime=
{
	frequency:40,
	c:0,
	length:0,
	runlist:{},
	
	// object, method, variabled, delay	, runtime, end object, end method, end variables, start object, start method
	addrun:function(o,m,v,d,r,eo,em,ev,so,sm)
	{
		var p=this;
		var id='run_'+(this.c++);
		var nv=[];
		if(v)
			for(var i=0;i<v.length;i++)
				nv.push(v[i]);
		nv.push(null);
		nv.push(null);
		
		this.runlist[id]={o:o,m:m,v:nv,d:d,r:r,rr:r,eo:eo,em:em,ev:ev,so:so,sm:sm,id:id,escape:function(){p.removerun(this.id);}};
		if(this.length==0)
			this.startrun();
		this.length++;
		return this.runlist[id];
	},
	removerun:function(id)
	{
		if(!this.runlist[id])
			return;
		
		delete this.runlist[id];
		this.length--;
		if(this.length==0)
			this.stoprun();
	},
	startrun:function(){var _method=this.run; var _object=this;this.timer=setInterval(function(){_method.apply(_object)}, this.frequency);},
	stoprun:function(){clearInterval(this.timer);},
	run:function()
	{
		for(var i in this.runlist)
		{
			var it=this.runlist[i];
			if(it.d-->0)continue;
			if(it.r>=0)
			{
				if(it.r==it.rr) it.so[it.sm]();				
				it.v[it.v.length-2]=it.r;
				it.v[it.v.length-1]=it.rr;
				var rtn=it.o[it.m].apply(it.o,it.v);
				it.r=typeof rtn=='number' ? rtn : it.r-1;
				if(it.r>=0)continue;
			}
			
			if(it.eo==null)
				it.eo=phocus;
			if(it.em==null)
				it.em='discard';
			if(it.ev==null)
				it.ev=[];
			
			it.eo[it.em].apply(it.eo,it.ev);
			
			this.endrun(i);
		}
	},
	endrun:function(i)
	{
		this.removerun(i);
	}
}
com.saltcollective.Phocus.register(com.saltcollective.Phocus.Runtime,'Runtime');

// cleanup
$pr=null;