if (typeof reddjs == "undefined")
	reddjs = {};

reddjs.images = {};

//
//	image management	

reddjs.images.load = function (src, width, height, alt, onload) {
	//var img = new Image(width?width:null, height?height:null);
	var img = reddjs.d.ce("img");
	
	if (alt && img.setAttribute !== undefined)
	{
		img.setAttribute("alt", alt);
		img.setAttribute("title", alt);
	}
	
	if (src)
		img.src = src;
	
	if (typeof onload == "function")
	{
		if (typeof dojo == "object")
		{
			dojo.require("dojo.event.*");
			dojo.event.connect(img, "onload", onload);
		}
		else if (typeof Prototype == "object")
			Event.observe(img, 'load', onload);
		else
			img.onload = onload;
	}
	
	return img;
};

//
//	DOM manipulation shortcuts

reddjs.d = {
	ce: function (t,c) { var n = document.createElement(t); if (c) { n.className = c; } return n; },
	ct: function (t) { return document.createTextNode(t); },
	ac: function (p,n) { p.appendChild(n); return n; },
	ceac: function (p,t,c) { var n = reddjs.d.ce(t,c); reddjs.d.ac(p,n); return n; },
	ctac: function (p,t) { var n = reddjs.d.ct(t); reddjs.d.ac(p,n); return n; },
	ceact: function (p,t,txt,c) { var n = reddjs.d.ceac(p,t,c); reddjs.d.ctac(n,txt); return n; },
	clac: function (p,h,t,c) { var n = reddjs.d.ceac(p,"a",c); n.href = h; reddjs.d.ctac(n,t); return n; },
	oblit: function (n,t) {
		if (!n) { return; }
		//	use dojo to destroy node n's children (and their children, etc.) and optionally node n itself (if bool t is true)
		//	dojo.dom.destroyNode prevents memory leaks in IE when removing nodes that are no longer needed
		for (var i = n.childNodes.length; i--;) { reddjs.d.oblit(n.childNodes[i],true); }	// destroy children
		if (t)
		{
			if (typeof dojo == "object")
			{
				dojo.dom.destroyNode(n);	//	destroy self
			}
			else if (typeof Prototype == "object")
			{
				//	FIXME: Investigate removing JS func/object references from dom nodes in IE here, dojo handles it in destroyNode
				if (n.parentNode)
					n = Element.remove(n);
				if (document.all && n.nodeType != 3)	//	ignore TEXT_NODE
					n.outerHTML = '';
			}
		}
	},
	ent: function (str, mode) {
		//	http://blog.skyzyx.com/2006/02/25/document-createtextnode-and-entities/
		//	e.g.: var text = 'blah blah '+ reddjs.d.ent('»');
		var str = (str) ? str : "";
		var mode = (mode) ? mode : "string";

		var e = document.createElement("div");
		e.innerHTML = str;

		if (mode == "numeric") {
			return "&#" + e.innerHTML.charCodeAt(0) + ";";
		}
		else if (mode == "utf16") {
			var un = e.innerHTML.charCodeAt(0).toString(16);
			while (un.length < 4) un = "0" + un;
			return "\\u" + un;
		}
		else return e.innerHTML;
	}
};

//
//	String manipulation

reddjs.s = {};

/**
 * Trim whitespace from 'str'. If 'wh' > 0,
 * only trim from start, if 'wh' < 0, only trim
 * from end, otherwise trim both ends
 */

reddjs.s.trim = function (str, wh) {
	if(!str.replace){ return str; }
	if(!str.length){ return str; }
	var re = (wh > 0) ? (/^\s+/) : (wh < 0) ? (/\s+$/) : (/^\s+|\s+$/g);
	return str.replace(re, "");
};

reddjs.strings = reddjs.s;

//
//	Forms support (using Dojo)

reddjs.forms = {};

reddjs.forms.highlightClassName = "reddjshighlight";
reddjs.forms.defaultAction = "submit.asp";

reddjs.forms.bind = function (node, handler, action) {
	if (action === undefined)
		var action = reddjs.forms.defaultAction;

	if (typeof dojo != "object") { alert('reddjs.forms.bind requires dojo'); return; };
	
	if (typeof node == "string")
		node = dojo.byId(node);
	
	if (!node)
		return;

	if (handler === undefined)
		var handler = reddjs.forms.defaultResponseHandler;
	
	node.action = action;
	var binding = new dojo.io.FormBind
	({
		formNode: node,
		handle: handler,
		mimetype: "text/json",
		sendTransport: true
	});
	
	dojo.event.connect(binding, "onSubmit", reddjs.forms, "defaultSubmitHandler");
	
	return binding;
};

reddjs.forms.submitDisableForm = function (form) {
	var e;
	for (var i = form.elements.length; i--;)
	{
		e = form.elements[i];

		switch (e.type)
		{
			case "hidden":
				break;

			default:
				if (!e.disabled)
				{
					e._reddjs_forms_enableme = true;
					e.disabled = true;
				}
				break;
		}
	}
};

reddjs.forms.defaultSubmitHandler = function (form) {
	setTimeout((function () { reddjs.forms.submitDisableForm(form); }), 1);

	if (typeof dojo != "undefined" && dojo.html && dojo.html.addClass)
	{
		for (var i = form.elements.length; i--;)
		{
			var element = form.elements[i];
			dojo.html.removeClass(element, reddjs.forms.highlightClassName);
		}
	}

	return true;
};

reddjs.forms.responseEnableForm  = function (form) {
	var e;
	for (var i = form.elements.length; i--;)
	{
		e = form.elements[i];

		switch (e.type)
		{
			case "hidden":
				break;

			default:
				if (e.disabled && e._reddjs_forms_enableme)
				{
					e._reddjs_forms_enableme = false;
					e.disabled = false;
				}
				break;
		}
	}
};

reddjs.forms.defaultIframeIOResponseHandler = function (type, result, request) { reddjs.forms.defaultResponseHandler(type, result, null, request); };

reddjs.forms.defaultResponseHandler = function (type, result, evt, request) {
	switch (type)
	{
		case "load":
		
			if (result.alert)
				alert(result.alert);	// show an alert using the browser's built-in dialog
			else if (result.message)
				alert(result.message);	// alternative for backwards compat.

			try { window.focus(); } catch (e) {}
			
			if (request.formNode)
			{
				reddjs.forms.responseEnableForm(request.formNode);	// if this response is bound to a form, re-enable the form elements
				
				if (result.highlight && result.highlight.length && typeof dojo != "undefined" && dojo.html && dojo.html.addClass)
				{
					for (var i = result.highlight.length; i--;)
					{
						var highlight = result.highlight[i];
						var node = request.formNode.elements[highlight];
						dojo.html.addClass(node, reddjs.forms.highlightClassName);
					}
				}
				
				if (result.reset)
					request.formNode.reset();
			}

			if (result.windowOpen)
			{
				switch (typeof result.windowOpen)
				{
					case "array":
						var w = open(result.windowOpen[0], result.windowOpen[1], result.windowOpen[2], result.windowOpen[3]);
						break;

					default:
						var w = open(result.windowOpen)
						break;
				}
			}

			if (result.eval)
				eval(result.eval);
			
			if (result.evaldelay)
				setTimeout(function(){ eval(result.evaldelay); }, 1);

			if (result.redirect)
			{
				var before = location;
				location.href = result.redirect;
				var after = location;
				if (before === after)
					result.reload = true;	//	HACK - should this be it's own setTimeout call, or is overriding result.reload here OK?
				break;
			}

			if (result.reload)
			{
				//	should always be checked after result.redirect due to the 'result.reload' setting in result.redirect above
				setTimeout(function(){location.reload();},1);
				break;
			}

			break;

		case "error":
			alert("An error occurred when attempting to perform this action. Please try again later.");
			if (request.formNode)
				reddjs.forms.responseEnableForm(request.formNode);
			break;

		default:
			alert("Unhandled form result type: "+ type);
			if (request.formNode)
				reddjs.forms.responseEnableForm(request.formNode);
			break;
	}
};

//
//	location.hash manipulation

reddjs.hash = {};

reddjs.hash.get = function (key, getIndex) {
	//
	//	assumes window.location.hash is a request-style query string (blah=foo&abc=123...) and returns the value of the given key
	//	e.g.: reddjs.hash.get("blah") == "foo"
	
	if (getIndex === undefined) { var getIndex = false; }
	
	var hash = location.hash;
	if (hash)
	{
		if (hash.substr(0, 1) == "#")
			hash = hash.substr(1);
		
		hash = hash.split("&");
		
		var item;
		for (var i = hash.length; i--;)
		{
			item = hash[i].split("=");
			if (item[0] = key)
				return getIndex ? i : item[1];
		}
	}
	return undefined;
};

reddjs.hash.set = function (key, value) {
	//
	//	assumes	window.location.hash is a request-style query string (blah=foo&abc=123...) and sets the value of the given key, altering window.location.hash for you
	//	e.g.: reddjs.hash.set("blah", "bar") changes location.hash to == "#blah=bar&abc=123..."
	
	var hash = location.hash;
	if (!hash)
		var newHash = key +"="+ value;
	else
	{
		var newHash = [];
		
		if (hash.substr(0, 1) == "#")
			hash = hash.substr(1);
		
		hash = hash.split("&");
		
		var item;
		var found = false;
		for (var i = 0, I = hash.length; i < I; i++)
		{
			if (i > 0)
				newHash.push("&");
				
			item = hash[i].split("=");
			newHash.push(item[0]);
			newHash.push("=");
			if (!found && item[0] == key)
			{
				newHash.push(value);
				found = true;
			}
			else
				newHash.push(item[1]);
		}
		
		if (!found)
		{
			if (I > 0)
				newHash.push("&");
				
			newHash.push(key);
			newHash.push("=");
			newHash.push(value);
		}
		
		newHash = newHash.join("");
	}
	
	location.replace("#"+ newHash);
	return location.hash;
};
