// FUNCTIONS
							   
/**
 * Get element by id
 */
function get(e) {
	if(typeof e == 'string')
    	return document.getElementById(e);
	return e;
}

/**
 * Get element value by id
 */
function getValue(e) {
	if(typeof e == 'string')
    	return document.getElementById(e).value;
	return e.value;
}

/**
 * Set display configuration
 */
function setDisplay(e, display) {
	get(e).style.display = display;
}

/**
 * Hide element
 */
function hide(e) {
	if (e)
	setDisplay(e, 'none');
}

/**
 * Show element
 */
function show(e) {
	if (e)
	setDisplay(e, '');
}

/**
 * Current element visibility
 */
function visible(e) {
	return get(e).style.display != 'none';
}

/**
 * Toggle visibility element configuration
 */
function toggle(e) {
	(visible(e) ? hide : show)(e);
}

/**
 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
 * @param {String} value The string to encode
 * @return {String} The encoded text
 */
function htmlspecialchars(value)
{
   return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
}

/**
 * AJAX Content Loader
 */
var net = new Object();
net.READY_STATE_UNINITIALIZED = 0;
net.READY_STATE_LOADING = 1;
net.READY_STATE_LOADED = 2;
net.READY_STATE_INTERACTIVE = 3;
net.READY_STATE_COMPLETE = 4;

net.ContentLoader = function(url, onload, params, onerror) {
	this.url = url;
	this.req = null;
	this.onload = onload;
	this.params = (params) ? this.parseParams(params) : false;
	this.onerror = (onerror) ? onerror : this.defaultError;
	this.responseObj = false;
	this.loadXMLDoc(url);
}
net.ContentLoader.prototype = {
	loadXMLDoc:function(url) {
		if (window.XMLHttpRequest) {
			this.req = new XMLHttpRequest();
		} else if (window.ActiveXObject) {
			this.req = new ActiveXObject("Microsoft.XMLHTTP");
		}
		if (this.req) {
			try {
				var loader = this;
				this.req.onreadystatechange = function() {
					loader.onReadyState.call(loader);
				}
				this.req.open('post', url, true);
				this.req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); 
				this.req.send(this.params);
			} catch (err) {
				this.onerror.call(this);
			}
		}
	},
	onReadyState:function() {
		var req = this.req;
		var ready = req.readyState;
		if (ready == net.READY_STATE_COMPLETE) {
			var httpStatus = req.status;
			if (httpStatus == 200 || httpStatus == O) {
				this.defaultOnload.call(this);
			} else {
				this.onerror.call(this); 
			}
		}
	},
	parseParams:function(params) {
		var newParams = '';
		for (var i = 0; i < params.length; i++) {
			if (i > 0) newParams += '&';
			newParams += params[i][0] + '=' + escape(params[i][1]);
		}
		return newParams;
	},
	defaultOnload:function() {
		eval('this.responseObj = ' + this.req.responseText);		
		if (this.responseObj.errors) {
			for (var i in this.responseObj.errors) {
				alert(this.responseObj.errors[i]);
			}
		}
		this.onload.call(this);
	},
	defaultError:function() {
		alert("error fetching data!" +"\n\nreadyState:"+this.req.readyState +"\nstatus: "+this.req.status+"\nheaders: "+this .req.getAHResponseHeaders ());
	}
}

// Check Element Traversal
var traversal = typeof document
                           .createElement('div')
                               .childElementCount != 'undefined';
var children = typeof document
                          .createElement('div')
                              .children != 'undefined';

var firstChild = traversal ? function(node) {
    return node.firstElementChild;
} : function(node) {
    node = node.firstChild;
    while(node && node.nodeType != 1) node = node.nextSibling;
    return node;
};

var lastChild = traversal ? function(node) {
    return node.lastElementChild;
} : function(node) {
    node = node.lastChild;
    while(node && node.nodeType != 1) node = node.previousSibling;
    return node;
};

var next = traversal ? function(node) {
    return node.nextElementSibling;
} : function(node) {
    while(node = node.nextSibling) if(node.nodeType == 1) break;
    return node;
};

var previous = traversal ? function(node) {
    return node.previousElementSibling;
} : function(node) {
    while(node = node.previousSibling) if(node.nodeType == 1) break;
    return node;
};

var child = children ? function(node) {
    return node.children;
} : function(node) {
    var list = node.childNodes,
    length = list.length,
    i = -1,
    array = [];
    while(++i < length)
        if(list[i].nodeType == 1)
            array.push(list[i]);
    return array;
};


/* DEBUG */

/**
 * Shows all JavaScript object properties
 *
 * @param obj
 * @param str
 * @return void
 *
 * @author Alex Kondrashov <alexander.kondrashov@toasterbridge.com>
 * @since 2009/4/6
 */
var Core = {};
Core.showObj = function(obj, maxLevel)
{
	if (!Core.thisTimeout) {
		Core.thisTimeout = window.setTimeout(Core.showObj, 100, obj, maxLevel);
		return false;
	}

	if (!maxLevel) {
		maxLevel = 4;
	}

	var newWin = window.open('JS_Object_Debug', 'Object_debug' + new Date(), 'width=800,height=600,toolbar=no,menubar=no,scrollbars=yes');

	newWin.document.write('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">');
	newWin.document.write('<html>');
	newWin.document.write('<head>');
	newWin.document.write('<style type="text/css">* {cursor: default !important;}</style>');
	newWin.document.write('<meta http-equiv="Content-Type" content="text/html; charset=utf-8">');
	newWin.document.write('<title>JS Object Debug from ' + Date() + '</title>');
	newWin.document.write('</head>');
	newWin.document.write('<body style="background-color: #7E7E7E; font: normal 12px verdana; color: white">');

	newWin.document.write('</body>');
	newWin.document.write('</html>');

	newWin.document.body.style.color = 'white';
	newWin.document.body.style.backgroundColor = '#7E7E7E';
	newWin.document.body.style.fontSize = '76%';
	newWin.document.body.style.padding = '0';
	newWin.document.body.style.margin = '0';

	var content = Core.showObjRecursive(obj, maxLevel, newWin, 1);
	content.style.margin = '8px';

	newWin.document.body.appendChild(content);
}

Core.showObjRecursive = function(obj, maxLevel, newWin, level, pi) {
	var rezultNode = createElement('div');
	rezultNode.style.font = '1em/2em Verdana';
	if (!pi) pi = '';

	for (var i in obj) {
		if (obj instanceof Array && typeof(obj[i]) != 'function') {
			var regExp = /^\d+$/;
			if (regExp.test(i)) {
				var parentIdentificator = (i) ? pi + "[" + i + "]" : '';
			} else {
				var parentIdentificator = (i) ? pi + "['" + i + "']" : '';
			}
		} else {
			var parentIdentificator = (i) ? pi + '.' + i : '';
		}

		var div = createElement('div');

		var def = createElement('strong');
		if (obj instanceof Array && typeof(obj[i]) != 'function') {
			def.appendChild(document.createTextNode('[' + i + ']'));
		} else if (typeof(obj[i]) == 'function') {
			def.appendChild(document.createTextNode(i + '()'));
		} else {
			def.appendChild(document.createTextNode(i));
		}
		div.appendChild(def);

		var objType = createElement('italic');
		if (obj[i] instanceof Array) {
			objType.appendChild(document.createTextNode(' (array) => '));
		} else if (obj[i] instanceof RegExp) {
			objType.appendChild(document.createTextNode(' (regular expression) => '));
		} else if (obj[i] && obj[i].tagName) {
			objType.appendChild(document.createTextNode(' (' + obj[i] + ') => '));
		} else {
			objType.appendChild(document.createTextNode(' (' + typeof(obj[i]) + ') => '));
		}
		div.appendChild(objType);

		var content = obj[i] + '';

		var objInstanse = createElement('div');
		objInstanse.style.margin = '10px 0 10px 20px';
		objInstanse.style.border = '1px solid #8E8E8E'
		objInstanse.style.outline = '1px solid #676767';
		objInstanse.style.padding = '5px';

		var piSpan = createElement('div');
		piSpan.style.color = 'yellow';
		piSpan.style.marginBottom = '5px';
		if (typeof(obj[i]) == 'function') {
			piSpan.appendChild(document.createTextNode(parentIdentificator + '()'));
		} else {
			piSpan.appendChild(document.createTextNode(parentIdentificator));
		}
		objInstanse.appendChild(piSpan);

		if ((content == '[object Object]' && level < maxLevel) || obj[i] instanceof Array || (obj[i] && obj[i].tagName) || typeof(obj[i]) == 'function') {
			var button = createElement('button');
			button.style.height = '20px';
			button.style.width = '20px';
			button.style.textAlign = 'center';
			button.style.verticalAlign = 'middle';

			button.onclick = function() {
				if (this.parentNode.lastChild.style.display == 'none') {
					this.parentNode.lastChild.style.display = '';
				} else {
					this.parentNode.lastChild.style.display = 'none';
				}
				if (this.innerHTML == '+') {
					this.innerHTML = '-';
				} else {
					this.innerHTML = '+';
				}
			}

			button.appendChild(document.createTextNode('+'));
			div.appendChild(button);

			objInstanse.style.display = 'none';
			objInstanse.style.font = '1em/1.5em Verdana';
		}

		if (obj[i] instanceof Array) {
			objInstanse.appendChild(Core.showObjRecursive(obj[i], maxLevel, newWin, level + 1, parentIdentificator));
		} else if (obj[i] instanceof RegExp) {
			objInstanse = createElement('span');
			objInstanse.style.color = '#99bbff';
			objInstanse.appendChild(document.createTextNode(content));
		} else if (content == '[object Object]' && level < maxLevel) {
			objInstanse.appendChild(Core.showObjRecursive(obj[i], maxLevel, newWin, level + 1, parentIdentificator));
		} else if (typeof(obj[i]) == 'string') {
			objInstanse = createElement('span');
			objInstanse.appendChild(document.createTextNode("'" + content + "'"));
		} else if (content == '[object Object]' && level == maxLevel) {
			objInstanse = createElement('span');
			objInstanse.appendChild(document.createTextNode(content));
		} else if (typeof(obj[i]) == 'boolean' || typeof(obj[i]) == 'number' || !obj[i]) {
			objInstanse = createElement('span');
			objInstanse.style.color = '#ff9999';
			objInstanse.appendChild(document.createTextNode(content));
		} else if (typeof(obj[i]) == 'function') {
			var el = createElement('pre', {}, content);
			style(el, {'font': '1em/1.5em Verdana'});
			objInstanse.appendChild(el);
		} else {
			if (obj[i] && obj[i].tagName) {
				var tempDiv = createElement('div');
				tempDiv.appendChild(obj[i]);
				objInstanse.appendChild(document.createTextNode(tempDiv.innerHTML));
			} else {
				objInstanse.appendChild(document.createTextNode(content));
			}
		}

		div.appendChild(objInstanse);

		objType.style.color = '#C2D959';
		objType.style.fontStyle = 'italic';
		def.style.marginLeft = '5px';
		piSpan.style.marginLeft = '5px';

		rezultNode.appendChild(div);
	}

	return rezultNode;
}

/**
 * @function `createElement` create and return a new element
 *
 * @string name     -- html name of new element
 * @array attrs     -- array of attributes
 * @DOM Element doc -- DOM element witch will contained new element
 * @t               -- append text
 *
 * @return DOM Element
 */
function createElement(name, attrs, text, doc) {
    var doc = doc ? doc : document;
    var elm = doc.createElement(name);
    if (text != null) elm.appendChild(doc.createTextNode(text));
    if (attrs) {
        for(attr in attrs) {
            elm.setAttribute(attr, attrs[attr]);
        }
    }
    return elm;
}

/**
 * set styles for element
 *
 * @DOM Element el  -- DOM element
 * @string styles -- array of styles, like `{color: 'red', margin: '0'}`
 *
 * @return void
 */
function style(el, styles) {
    for (var i in styles) {
        el.style[i] = styles[i];
    }
}

/**
 * Wates for function exist and executes it
 *
 * @string funcName -- Function name
 * @string funcEval -- Eval text
 *
 * @return void
 */
function ieReady(funcName, funcEval)
{
	eval('var funcType = typeof(' + funcName + ');');
	if (funcType == 'function') {
		eval(funcEval);
	} else {
		window.setTimeout('ieReady(\'' + funcName + '\', \'' + funcEval + '\');', 100);
	}
}
