function setupEvents(e)
{
	var intro=document.getElementById('intro');
	addEvent(intro, 'click', fadeToNextPage, false);
//	var tm=new TransitionManager();
}

function TransitionManager()
{
	this.loadedDocs=new Object;

	this.setupTransEvents=function () {
		var as=document.getElementsByTagName('a');

		for (var i=0; i < as.length; i++)
		{
			var a=as[i];

			var trans=null;
			if (a.hasAttributeNS && a.hasAttributeNS('urn:mi:trans','trans'))
			{
				trans=a.getAttributeNS('urn:mi:trans', 'trans');
			}
			else if (a.hasAttribute('t:trans'))
			{
				trans=a.getAttribute('t:trans');
			}

			if (trans != null)
			{
				var matches=trans.match(/([^#]+)(#(.*))?/);
			}
		}
	}

	this.setupTransEvents();
}

function fadeToNextPage(e)
{
	loadAnimations('transitions.xml');

	if (window.event)
	{
		window.event.returnValue=false;
	}
	else if (e)
	{
		e.preventDefault();
	}
	
	var intro=document.getElementById('intro');

	intro.blur();
	removeEvent(intro, 'click', fadeToNextPage, false);
	
	animate();
}

var fps=20;

var currentframe=0;

var animations;

function isNumber(str)
{
	var firstchar=str.charCodeAt(0);

	return (firstchar >= '0'.charCodeAt(0) && firstchar <= '9'.charCodeAt(0));
		
}

function assignCSSProperty(el, property, value, unit)
{
	if (!(el && el.style))
		return;
		
	if (property == 'opacity' && navigator.appName == 'Microsoft Internet Explorer')
	{
		if (value == 1)
			el.style.filter='';
		else el.style.filter='alpha(Opacity='+parseInt(value*100)+')';
	}
	else el.style[property]=value+unit;
}

function AnimateProperty(node)
{
	this.el=node.getAttribute('el');
	this.property=node.getAttribute('property');
	this.start=node.getAttribute('start');
	if (isNumber(this.start))
		this.start=parseFloat(this.start);
	this.end=node.getAttribute('end');
	if (isNumber(this.end))
		this.end=parseFloat(this.end);
	this.unit=node.getAttribute('unit');
	if (this.unit == null)
		this.unit='';
	this.startframe=parseInt(node.getAttribute('startframe'));
	this.endframe=parseInt(node.getAttribute('endframe'));

	this.doFrame=function () {
	
		if (currentframe < this.startframe || currentframe > this.endframe)
			return;

		startval=evaluateValue(this.start);
		endval=evaluateValue(this.end);

		//fraction varies between 0 and 1
		var fraction=0.5-0.5*Math.cos(Math.PI*(currentframe-this.startframe)/(this.endframe-this.startframe));
	//	var fraction=currentframe/frames;
		if (startval.charAt && startval.charAt(0) == '#')
		{
			var value=blendColours(startval, endval, fraction);
		}
		else
		{
			var value=startval+(endval-startval)*fraction;
		}


		var els=evaluateSelector(this.el);

		for (var i=0; i < els.length; i++)
		{
			if (els[i] && els[i].style)
				assignCSSProperty(els[i], this.property, value, this.unit);
		}
	}

	this.isFinished=function () {
		return currentframe > this.endframe;
	}

	this.skipFrame=function () {
		//we need to set both the initial value and the final value - the interpolation is not so important
		if (currentframe == this.endframe || currentframe == this.startframe)
		{
			var els=evaluateSelector(this.el);
			var value=evaluateValue((currentframe == this.startframe) ? this.start : this.end);
			for (var i=0; i < els.length; i++)
			{
				assignCSSProperty(els[i], this.property, value, this.unit);
			}
		}
	}
}

function SetProperty(node)
{
	this.el=node.getAttribute('el');
	this.property=node.getAttribute('property');
	this.value=node.getAttribute('value');
	this.frame=parseInt(node.getAttribute('frame'));

	this.doFrame=function () {
		if (currentframe != this.frame)
			return;
			
		var els=evaluateSelector(this.el);

		for (var i=0; i < els.length; i++)
		{
			if (els[i] && els[i].style)
				assignCSSProperty(els[i], this.property, this.value, '');
		}
	}

	this.isFinished=function () {
		return currentframe > this.frame;
	}
}

function SetAttribute(node)
{
	this.el=node.getAttribute('el');
	this.attribute=node.getAttribute('attribute');
	this.value=node.getAttribute('value');
	this.frame=parseInt(node.getAttribute('frame'));

	this.doFrame=function () {
		if (currentframe != this.frame)
			return;
			
		var els=evaluateSelector(this.el);

		for (var i=0; i < els.length; i++)
		{
			if (els[i])
				els[i].setAttribute(this.attribute, this.value);
		}
	}

	this.isFinished=function () {
		return currentframe > this.frame;
	}
}

function ExecuteFunction(node)
{
	this.func=node.getAttribute('function');
	this.frame=parseInt(node.getAttribute('frame'));

	this.doFrame=function () {
		if (currentframe != this.frame)
			return;
	
		var parts = this.func.split('.');
		var obj = window;
		for (var i = 0; i < parts.length; i++)
			obj = obj[parts[i]]
			
		obj();
	}

	this.isFinished=function () {
		return currentframe > this.frame;
	}
}

function ImportContent(node)
{
	this.url=node.getAttribute('url');
	this.frame=parseInt(node.getAttribute('frame'));

	this.imports=new Array;
	
	for (var i=0; i < node.childNodes.length; i++)
	{
		var n=node.childNodes[i];

		if (n.nodeType == 1)
		{
			var imp=new Object;
			imp.op=n.nodeName;
			imp.source=n.getAttribute('sourceid');
			imp.dest=n.getAttribute('destid');

			this.imports[this.imports.length]=imp;
		}
	}

	this.doc = null;

	this.doFrame=function () {
		if (currentframe == 0)
		{
			//fire an Async XMLHTTP request now so that the data is (hopefully) ready when we need it
			if (window.XMLHttpRequest)
			{
				this.http_request=new XMLHttpRequest();
				this.http_request.open('GET', this.url, true);
				if (this.http_request.overrideMimeType)
					this.http_request.overrideMimeType('text/xml');
				var importcontent=this;
				this.http_request.onreadystatechange=function () {
					if (importcontent.http_request.readyState == 4)
					{
						importcontent.doc=importcontent.http_request.responseXML;
					}
				};
		
				this.http_request.send(null);
			}
			else 
			{
				this.http_request=new ActiveXObject("Microsoft.XMLDOM");
				this.http_request.async="true";
				this.http_request.validateOnParse="false";
				
				var importcontent=this;
				this.http_request.onreadystatechange=function () {
					if (importcontent.http_request.readyState == 4)
					{
						importcontent.doc=importcontent.http_request;
					}
				};

				this.http_request.load(this.url);
			}
	
		}

		if (currentframe != this.frame)
			return;

		var doc=this.doc;
		if (!doc || !doc.documentElement)
		{
			//no choice but to do it synchronously now
			doc=XMLHTTPGET(this.url);
			if (!doc || !doc.documentElement)
				return;
		}

		for (var i=0; i < this.imports.length; i++)
		{
			var imp=this.imports[i];
			if (doc.getElementById)
				var sourcenode=doc.getElementById(imp.source);	//god knows why IE doesn't support this
			else var sourcenode=getElementById(doc, imp.source);
			var destnode=document.getElementById(imp.dest);

			if (imp.op == 'replace')
			{
				while (destnode.childNodes.length > 0)
					destnode.removeChild(destnode.firstChild);
			}

			for (var j=0; j < sourcenode.childNodes.length; j++)
			{
				var imported;
				if (document.importNode)
				{
					imported=document.importNode(sourcenode.childNodes[j], true);
				}
				else
				{
					imported=myImportNode(document, sourcenode.childNodes[j]);
				}
				destnode.appendChild(imported);
			}
				
		}
	}
	
	this.isFinished=function () {
		return currentframe > this.frame;
	}
}

function getAnimations(node)
{
	var anims=new Array();

	for (var i=0; i < node.childNodes.length; i++)
	{
		var n=node.childNodes[i];

		if (n.nodeType == 1 /* ELEMENT_NODE */)
		{
			if (n.nodeName == 'animate-css')
			{
				anims[anims.length]=new AnimateProperty(n);
			}
			else if (n.nodeName == 'set-css')
			{
				anims[anims.length]=new SetProperty(n);
			}
			else if (n.nodeName == 'set-attribute')
			{
				anims[anims.length]=new SetAttribute(n);
			}
			else if (n.nodeName == 'import-content')
			{
				anims[anims.length]=new ImportContent(n);
			}
			else if (n.nodeName == 'execute-function')
			{
				anims[anims.length]=new ExecuteFunction(n);
			}
			else if (n.nodeName == 'browser')
			{
				var match = n.getAttribute('match');
				var notmatch = n.getAttribute('notmatch');

				var allow_match = true;
				if (match)
					allow_match = navigator.appVersion.match(match) != null;

				var allow_notmatch = true;
				if (notmatch)
					allow_notmatch = navigator.appVersion.match(notmatch) == null;

				if (allow_match && allow_notmatch)
				{
					var restricted_anims=getAnimations(n);
					for (var j=0; j < restricted_anims.length; j++)
						anims[anims.length]=restricted_anims[j];
				}
			}
			else if (n.nodeName == 'IE') 
			{
				if (navigator.appName == 'Microsoft Internet Explorer' && !window.opera)
				{
					var ieonly=getAnimations(n);
					for (var j=0; j < ieonly.length; j++)
						anims[anims.length]=ieonly[j];
				}
			}
			else if (n.nodeName == 'NotIE') 
			{
				if (navigator.appName != 'Microsoft Internet Explorer' || window.opera)
				{
					var notie=getAnimations(n);
					for (var j=0; j < notie.length; j++)
						anims[anims.length]=notie[j];
				}
			}

		}
	}

	return anims;
}

function loadAnimations(url)
{
	var header=document.getElementById('header');
	var p=document.createElement('p');
	p.appendChild(document.createTextNode('Loading animations...'));
	header.appendChild(p);
	p.style.color='white';
	p.style.margin='100px auto';
	p.style.width='350px';
	var doc=XMLHTTPGET(url);

	animations=getAnimations(doc.documentElement);

	header.removeChild(p);
}

var firstframemillis=null;

function animate()
{
	var lastframe=currentframe;
	var finished=true;

	var nowmillis=new Date().getTime();
	if (firstframemillis == null)
		firstframemillis=nowmillis;	
	//skip frames if we're more than 500ms behind
	var frameskip=((nowmillis-firstframemillis) > ((1000/fps)*currentframe+500));

	if (frameskip)
		firstframemillis+=100;	//give us some more time for the next frame

	for (var i=0; i < animations.length; i++)
	{
		var a=animations[i];

		if (frameskip && a.skipFrame)
			a.skipFrame();
		else a.doFrame();

		if (!a.isFinished())
			finished=false;
	}
		
	if (!finished)
	{
		currentframe++;
		setTimeout(animate, 1000/fps);
	}
}

function animateValue(element, atts)
{
	if (atts.length < 6)
	{
		var property=atts[1];
		var val=atts[2];
		var frame=atts[3];

		if (currentframe == frame)
			element.style[property]=val;

		return;
	}

	var property=atts[1];
	var startval=evaluateValue(atts[2]);
	var endval=evaluateValue(atts[3]);
	var unit=atts[4];
	var startframe=atts[5];
	var endframe=atts[6];
	
	if (currentframe < startframe || currentframe > endframe)
		return;

	//fraction varies between 0 and 1
	var fraction=0.5-0.5*Math.cos(Math.PI*(currentframe-startframe)/(endframe-startframe));
//	var fraction=currentframe/frames;
	if (startval.charAt && startval.charAt(0) == '#')
	{
		var value=blendColours(startval, endval, fraction);
	}
	else
	{
		var value=startval+(endval-startval)*fraction;
	}

	element.style[property]=value+unit;
}

function evaluateValue(val)
{
	if (val.substring && val.substring(0,5) == 'eval(')
	{
		var ret=eval(val.substring(5,val.length-1));
		return ret;
	}
	return val;
}

function evaluateSelector(sel)
{
	var matches=new Array;

	if (sel.charAt(0) == '#')
		matches[matches.length]=document.getElementById(sel.substring(1));
	else
	{
		var re = /([^.]+)(\.(.*))?/ ;
		var matches=sel.match(re);
		if (matches)
		{
			var tagname=matches[1];
			var classname=null;
			if (matches.length > 2)
			{
				var classname=matches[3];
			}

			var els=document.getElementsByTagName(tagname);

			for (var j=0; j < els.length; j++)
			{
				var el=els[j];

				if (classname != null)
				{
					if (!inClass(el, classname))
						continue;
				}

				matches[matches.length]=el;
			}
		}
	}

	return matches;
}

function blendColours(start, end, frac)
{
	var sr=parseInt(start.substring(1,3), 16);	
	var sg=parseInt(start.substring(3,5), 16);	
	var sb=parseInt(start.substring(5), 16);
	
	var er=parseInt(end.substring(1,3), 16);	
	var eg=parseInt(end.substring(3,5), 16);	
	var eb=parseInt(end.substring(5), 16);

	var or=parseInt(sr+(er-sr)*frac);
	var og=parseInt(sg+(eg-sg)*frac);
	var ob=parseInt(sb+(eb-sb)*frac);

	var chars=['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'];
	
	var col='#' + chars[(or & 0xf0) >> 4] + chars[or & 0x0f] +
		     chars[(og & 0xf0) >> 4] + chars[og & 0x0f] +
		     chars[(ob & 0xf0) >> 4] + chars[ob & 0x0f];

	return col;
}

addEvent(window, 'load', setupEvents, false);
