/**
 * Copies from one div to another and changes the id of the form
 */
function copyToDiv( sourceDiv, targetDiv, formID )
{
	var sel = document.getElementById( sourceDiv );
	var tel = document.getElementById( targetDiv );
	tel.innerHTML = sel.innerHTML;
	
	//set a formID on this form
	var tform = tel.getElementsByTagName( 'form' )[0];
	tform.id = formID;
}


function getResourceLink( img )
{
	//TODO: version
	return entryURL + '/media/' + img;
}

function uiEndLoad()
{
	document.getElementsByTagName('body')[0].className = '';
}

function uiStartLoad()
{
	document.getElementsByTagName('body')[0].className = 'loading';
}

/* this is called on page load to force the inner body to expand to the available browser space.
 There is *NO* way to do this properly in CSS, and this is also prone to problem with dynamic
 content -- called once. */
function extendInnerBody()
{
	var fel = document.getElementById( 'footer' );
	var iel = document.getElementById( 'outerbody2' );
	var lel = document.getElementById( 'leftpanel' );
	var ipos = getPagePos( iel );
	var fpos = getPagePos( fel );
	var lpos = getPagePos( lel );
	
	var wHeight = getViewHeight();
	var ielPadding = 20; //subtract padding since minHeight excludes it
	
	var fillHeight = iel.offsetHeight + (wHeight - (fel.offsetHeight + fpos[1])) - ielPadding;
	
	//extend to ensure left tabs are attached to something
	var diffLeft = (lel.offsetHeight + lpos[1]) - (fillHeight + ipos[1]);
	if( diffLeft > 0 )
		fillHeight += diffLeft;
		
	iel.style.minHeight = fillHeight + "px";
}

function pageResize()
{
	extendInnerBody();
}

/**
 * Obtain the height of the browser viewport (where the document is being displayed)
 */
function getViewHeight()
{
	//http://snipplr.com/view/2638/height-of-window/
	return window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight;
}

/**
 * Get the page position of an element.
 */
function getPagePos( el )
{
	var x = 0;
	var y = 0;
	
	while( el )
	{	
		x += el.offsetLeft;
		y += el.offsetTop;
		
		el = el.offsetParent;
	}
	
	return [ x, y ];
}

/**
 * Translate absolute coordinates into those needed to position an element there. This
 * is important when some div's have absolute or relative sizing.
 */
function pageToOffset( el, pos )
{
	el = el.offsetParent;
	while( el )
	{
		pos[0] -= el.offsetLeft;
		pos[1] -= el.offsetTop;
		el = el.offsetParent;
	}
	return pos;
}


/*
	Developed by Robert Nyman, http://www.robertnyman.com
	Code/licensing: http://code.google.com/p/getelementsbyclassname/
*/
var getElementsByClassName = function (className, tag, elm){
	if (document.getElementsByClassName) {
		getElementsByClassName = function (className, tag, elm) {
			elm = elm || document;
			var elements = elm.getElementsByClassName(className),
				nodeName = (tag)? new RegExp("\\b" + tag + "\\b", "i") : null,
				returnElements = [],
				current;
			for(var i=0, il=elements.length; i<il; i+=1){
				current = elements[i];
				if(!nodeName || nodeName.test(current.nodeName)) {
					returnElements.push(current);
				}
			}
			return returnElements;
		};
	}
	else if (document.evaluate) {
		getElementsByClassName = function (className, tag, elm) {
			tag = tag || "*";
			elm = elm || document;
			var classes = className.split(" "),
				classesToCheck = "",
				xhtmlNamespace = "http://www.w3.org/1999/xhtml",
				namespaceResolver = (document.documentElement.namespaceURI === xhtmlNamespace)? xhtmlNamespace : null,
				returnElements = [],
				elements,
				node;
			for(var j=0, jl=classes.length; j<jl; j+=1){
				classesToCheck += "[contains(concat(' ', @class, ' '), ' " + classes[j] + " ')]";
			}
			try	{
				elements = document.evaluate(".//" + tag + classesToCheck, elm, namespaceResolver, 0, null);
			}
			catch (e) {
				elements = document.evaluate(".//" + tag + classesToCheck, elm, null, 0, null);
			}
			while ((node = elements.iterateNext())) {
				returnElements.push(node);
			}
			return returnElements;
		};
	}
	else {
		getElementsByClassName = function (className, tag, elm) {
			tag = tag || "*";
			elm = elm || document;
			var classes = className.split(" "),
				classesToCheck = [],
				elements = (tag === "*" && elm.all)? elm.all : elm.getElementsByTagName(tag),
				current,
				returnElements = [],
				match;
			for(var k=0, kl=classes.length; k<kl; k+=1){
				classesToCheck.push(new RegExp("(^|\\s)" + classes[k] + "(\\s|$)"));
			}
			for(var l=0, ll=elements.length; l<ll; l+=1){
				current = elements[l];
				match = false;
				for(var m=0, ml=classesToCheck.length; m<ml; m+=1){
					match = classesToCheck[m].test(current.className);
					if (!match) {
						break;
					}
				}
				if (match) {
					returnElements.push(current);
				}
			}
			return returnElements;
		};
	}
	return getElementsByClassName(className, tag, elm);
};

/**
 * Obtains the width of the browser window.
//taken from many sources (combined until MSIE worked with resizing content)
//MSIE: clientWidth seems to expand to content, so resizing small never works (the large
//flash object keeps making this return higher sizes)
//NOTE: Make sure a DOCTYPE is present while testing otherwise MSIE will work even worse...
*/
function getInnerSize()
{
	var myWidth = 0, myHeight = 0;
	if( typeof( window.innerWidth ) != 'undefined' ) {
		//Non-IE, or IE7
		myWidth = window.innerWidth;
		myHeight = window.innerHeight;
	}
	else if ( typeof document.documentElement != 'undefined'
	 	&& typeof document.documentElement.clientWidth !=
	 	'undefined' && document.documentElement.clientWidth != 0)
	{
		myWidth = document.documentElement.clientWidth,
		myHeight = document.documentElement.clientHeight
 	}
	else
	{
		myWidth = document.getElementsByTagName('body')[0].clientWidth,
		myHeight = document.getElementsByTagName('body')[0].clientHeight
	}	
	
	return [myWidth, myHeight];
}

/**
 * Encodes CDATA output. this escapes only the < and & symbols.
 */
function xml( text )
{
	//JAVASCRIPT: *sigh* there is no standard function, odd ?
	return text.replace(/&/g,"&amp;").replace(/</g,"&lt;");
}

/**
 * Encodes the text to be used as an attribute. This will put the quotes on the
 * resulting value.
 */
function xmlattr( text )
{
	return "\"" + text.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/"/g,"&qout;") + "\"";
}

/**
 * Enscapsulates an entire request. A class is chosen over making the functions take
 * more parameters in order to give names and structure to the loading.
 */
function RequestLoader( url, method )
{
	this.url = url;
	if( typeof method == 'undefined' )
		this.method = 'GET';
	else
		this.method = method;
		
	this.onComplete = function( rawData ) { };
	this.onError = function() { };
	this.body = null;		
	this.headers = [];
	this.parseContent = true;
	this.expectJSON = false;

	//create the native request object
	var req = newXMLHttpRequest();
	var _this = this; //NOTE: I'm not so clear on why I need this just for the next function...
	req.onreadystatechange = function()
	{
		if( req.readyState == 4) //TODO: req.DONE ??
		{	
			var content;
			if( _this.parseContent )
				content = _this._parseContent();
			else
				content = req.responseText;
				
			var okay = req.status == 200;
			var msg = req.statusText;
			
			//do logical checking on JSON responses
			if( _this.expectJSON )
			{
				if( _this.getMIMEType() !== 'application/json' )
				{
					msg = 'Invalid data format returned';
					okay = false;
				}
				else if( content['status'] !== 0 && content['status'] !== 2 ) //OKAY and WARNING
				{
					msg = 'Failed request';
					okay = false;
				}
			}
			
			//dispatch to error or okay response
			if( okay )
			{
				_this.onComplete( content );
			}
			else
			{
				//not gaurantee we even have a structured response (but check JSON msg anyways)
				if( typeof content['msg'] == 'string' )
					err = content['msg'];
					
				_this.onError( msg, content );
			}
		}
	};
	
	this.getMIMEType = function() {
		var ct = req.getResponseHeader( 'Content-Type' );
		if( ct == null )
			ct = 'text/plain';
			
		var part = ct.split( ';' );
		return part[0];
	}
	
	this._parseContent = function()
	{
		var mt = _this.getMIMEType();
		
		if( mt == 'application/json' )
			return JSON.parse( req.responseText );
		else if( mt == 'text/xml' || mt == 'application/xml' 
			|| /.*\+xml/.test( mt ) )
			return req.responseXML;
			
		return req.responseText;
	}
	
	/**
	 * Performs the actual request.
	 */
	this.send = function()
	{
		req.open( _this.method, _this.url, true );
		//headers
		for( var i in _this.headers )
			req.setRequestHeader( _this.headers[i][0], _this.headers[i][1] );
		req.send( _this.body );
	}
	
	/**
	 * Sets the data for the request to the JSON encoded object and configure settings 
	 * appropriately.
	 */
	this.setJSONRequest = function( object ) 
	{
		_this.body = JSON.stringify( object );
		_this.method = 'POST';
		_this.setHeader( 'Content-Type', 'application/json; charset=utf-8' );
		_this.expectJSON = true;
	}
	
	this.setHeader = function( name, value )
	{
		_this.headers.push( [name, value] );
	}
}

/**
 * Loads a URL and then executes a piece of code with the result.
 */
function loadThen( url, code )
{
	var rl = new RequestLoader( url );
	rl.onComplete = code;
	rl.send();
}

function loadJSONThen( url, data, code )
{
	var rl = new RequestLoader( url );
	rl.setJSONRequest( data );
	rl.onComplete = code;
	rl.send();
}

/**
 * Replaces the innerHTML of a particular DOM node with the contents loaded
 * from the URL.
 */
function loadToDiv( _id, _url )
{ 
	loadThen( _url, function( data ) {
	  document.getElementById( _id ).innerHTML = data; 
		} );
} 

/**
 * Create teh XMLHttpRequest object.
 */
function newXMLHttpRequest()
{
	if (window.XMLHttpRequest)
		return new XMLHttpRequest();

	//try to find request object type
	try 
	{  
		return new ActiveXObject('Msxml2.XMLHTTP');   
	}
	catch( ex ) 
	{ }
		
	try 
	{   
		return new ActiveXObject('Microsoft.XMLHTTP');	
	}
	catch( ex2 ) 
	{ }
	
	throw new Error( "Cannot create XMLHttpRequest object." );
}

