// Common
var Common = {
	Key: {
		LEFT: 37,
		UP: 38,
		RIGHT: 39,
		DOWN: 40,
		DEL: 8,
		TAB: 9,
		RETURN: 13,
		ESC: 27,
		PAGEUP: 33,
		PAGEDOWN: 34,
		SPACE: 32
	},
	Event: {
		aObservers: [],
		add: function (
		mElement, mEventType, fEventFunction) {
			if (mElement.length && mElement.sort) {
				for (var i = 0; i < mElement.length; i++) {
					this.add(mElement[i], mEventType, fEventFunction);
				}
				return;
			}
			if (!mEventType.match && mEventType.length) {
				for (var i = 0; i < mEventType.length; i++) {
					this.add(mElement, mEventType[i], fEventFunction);
				}
				return;
			}
			if (mElement.addEventListener) {
				mElement.addEventListener(
				mEventType, fEventFunction, false);
			} else if (mElement.attachEvent) {
				if (this.aObservers.length == 0) {
					this.aObservers.push([mElement, mEventType, fEventFunction]);
					this.add(
					window, 'unload', function () {
						Common.Event.detachObservers();
					});
				} else {
					this.aObservers.push([mElement, mEventType, fEventFunction]);
				}
				mElement.attachEvent('on' + mEventType, fEventFunction);
			}
		},
		remove: function (
		mElement, mEventType, fEventFunction) {
			if (mElement.length && mElement.sort) {
				for (var i = 0; i < mElement.length; i++) {
					this.remove(mElement[i], mEventType, fEventFunction);
				}
				return;
			}
			if (!mEventType.match && mEventType.length) {
				for (var i = 0; i < mEventType.length; i++) {
					this.remove(mElement, mEventType[i], fEventFunction);
				}
				return;
			}
			if (mElement.removeEventListener) {
				mElement.removeEventListener(
				mEventType, fEventFunction, false);
			} else if (mElement.detachEvent) {
				mElement.detachEvent('on' + mEventType, fEventFunction);
			}
		},
		detachObservers: function () {
			for (var i = 0, iLength = this.aObservers.length; i < iLength; i++) {
				this.remove(
				this.aObservers[i][0], this.aObservers[i][1], this.aObservers[i][2]);
				this.aObservers[i][0] = null;
			}
			this.aObservers.length = 0;
		},
		cancel: function (oEvent) {
			var oEvent = oEvent ? oEvent : window.event;
			oEvent.cancelBubble = true;
			oEvent.returnValue = false;
			if (oEvent.cancelable) {
				oEvent.preventDefault();
				oEvent.stopPropagation();
			}
			return false;
		},
		normalize: function (oEvent) {
			var oEvent = oEvent ? oEvent : window.event;
			if (oEvent && oEvent.srcElement && !window.opera) {
				oEvent.target = oEvent.srcElement;
			}
			if (oEvent) {
				oEvent.iKeyCode = oEvent.keyCode ? oEvent.keyCode : (oEvent.which ? oEvent.which : null);
				if (oEvent.wheelDelta) {
					oEvent.iMouseWheelDelta = oEvent.wheelDelta / 120;
					if (window.opera) {
						oEvent.iMouseWheelDelta *= -1;
					}
				} else if (oEvent.detail) {
					oEvent.iMouseWheelDelta = -oEvent.detail / 3;
				}
			}
			return oEvent;
		},
		getAbsoluteCoords: function (oEvent) {
			var oEvent = oEvent ? oEvent : window.event,
			oResult = {
				iLeft: 0,
				iTop: 0
			};
			if (oEvent.pageX || oEvent.pageY) {
				oResult.iLeft = oEvent.pageX;
				oResult.iTop = oEvent.pageY;
			} else if (oEvent.clientX || oEvent.clientY) {
				oResult.iLeft = oEvent.clientX + document.body.scrollLeft - document.body.clientLeft;
				oResult.iTop = oEvent.clientY + document.body.scrollTop - document.body.clientTop;
				if (document.body.parentElement && document.body.parentElement.clientLeft) {
					var oBodyParent = document.body.parentElement;
					oResult.iLeft += oBodyParent.scrollLeft - oBodyParent.clientLeft;
					oResult.iTop += oBodyParent.scrollTop - oBodyParent.clientTop;
				}
			}
			return oResult;
		}
	},
	// Common DOM's methods
	Dom: {
		NODE_TYPE_ELEMENT: 1,
		NODE_TYPE_TEXT: 3,
		getAbsoluteCoords: function (oElement, w) {
			var oResult = {
				iTop: 0,
				iLeft: 0
			};
			if (w) {
				oResult.iWidth = oElement.offsetWidth;
				oResult.iHeight = oElement.offsetHeight;
			}
			while (oElement) {
				oResult.iTop += oElement.offsetTop;
				oResult.iLeft += oElement.offsetLeft;
				oElement = oElement.offsetParent;
			}
			return oResult;
		},
		setOpacity: function (oElement, dValue) {
			if (oElement.runtimeStyle) {
				oElement.style.zoom = 1;
				oElement.style.filter = oElement.style.filter.replace(/alpha\([^)]*\)/, "") + "alpha(opacity=" + dValue * 100 + ")";
			} else {
				if (dValue == 1) {
					oElement.style.opacity = '';
				} else {
					oElement.style.opacity = dValue;
				}
			}
		}
	},
	// Common cookie's methods
	Cookie: {
		set: function (sName, sValue, sExpire, sPath) {
			document.cookie = sName + '=' + (window.encodeURI ? encodeURI(sValue) : escape(sValue)) + ((sExpire == null) ? '' : ('; expires=' + sExpire.toGMTString())) + ((sPath == null) ? '' : ('; path=' + sPath));
		},
		get: function (sName) {
			var sSearch = sName + '=';
			if (document.cookie.length > 0) {
				var iOffset = document.cookie.indexOf(sSearch);
				if (iOffset != -1) {
					iOffset += sSearch.length;
					var iEnd = document.cookie.indexOf(';', iOffset);
					if (iEnd == -1) {
						iEnd = document.cookie.length;
					}
					return window.decodeURI ? decodeURI(document.cookie.substring(iOffset, iEnd)) : unescape(document.cookie.substring(iOffset, iEnd));
				}
			}
			return '';
		}
	}
};

// Domready
addDOMLoadEvent = (function () {
	// create event function stack
	var load_events = [],
		load_timer, script, done, exec, old_onload, init = function () {
		done = true;
		// kill the timer
		clearInterval(load_timer);
		// execute each function in the stack in the order they were added
		while (exec = load_events.shift())
		exec();
		if (script) script.onreadystatechange = '';
	};
	return function (func) {
		// if the init function was already ran, just run this function now and stop
		if (done) return func();
		if (!load_events[0]) {
			// for Mozilla/Opera9
			if (document.addEventListener) document.addEventListener("DOMContentLoaded", init, false);
			// for Internet Explorer
			/*@cc_on @*/
			/*@if (@_win32)
                document.write("<script id=__ie_onload defer src=//0><\/scr"+"ipt>");
                script = document.getElementById("__ie_onload");
                script.onreadystatechange = function() {
                    if (this.readyState == "complete")
                        init(); // call the onload handler
                };
            /*@end @*/
			// for Safari
			if (/WebKit/i.test(navigator.userAgent)) { // sniff
				load_timer = setInterval(function () {
					if (/loaded|complete/.test(document.readyState)) init(); // call the onload handler
				},
				10);
			}
			// for other browsers set the window.onload, but also execute the old window.onload
			old_onload = window.onload;
			window.onload = function () {
				init();
				if (old_onload) old_onload();
			};
		}
		load_events.push(func);
	}
})();

// JSON
if(!this.JSON){this.JSON={};}
(function(){function f(n){return n<10?'0'+n:n;}
if(typeof Date.prototype.toJSON!=='function'){Date.prototype.toJSON=function(key){return isFinite(this.valueOf())?this.getUTCFullYear()+'-'+
f(this.getUTCMonth()+1)+'-'+
f(this.getUTCDate())+'T'+
f(this.getUTCHours())+':'+
f(this.getUTCMinutes())+':'+
f(this.getUTCSeconds())+'Z':null;};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf();};}
var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==='string'?c:'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4);})+'"':'"'+string+'"';}
function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==='object'&&typeof value.toJSON==='function'){value=value.toJSON(key);}
if(typeof rep==='function'){value=rep.call(holder,key,value);}
switch(typeof value){case'string':return quote(value);case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null';}
gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==='[object Array]'){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||'null';}
v=partial.length===0?'[]':gap?'[\n'+gap+
partial.join(',\n'+gap)+'\n'+
mind+']':'['+partial.join(',')+']';gap=mind;return v;}
if(rep&&typeof rep==='object'){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==='string'){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}}
v=partial.length===0?'{}':gap?'{\n'+gap+partial.join(',\n'+gap)+'\n'+
mind+'}':'{'+partial.join(',')+'}';gap=mind;return v;}}
if(typeof JSON.stringify!=='function'){JSON.stringify=function(value,replacer,space){var i;gap='';indent='';if(typeof space==='number'){for(i=0;i<space;i+=1){indent+=' ';}}else if(typeof space==='string'){indent=space;}
rep=replacer;if(replacer&&typeof replacer!=='function'&&(typeof replacer!=='object'||typeof replacer.length!=='number')){throw new Error('JSON.stringify');}
return str('',{'':value});};}
if(typeof JSON.parse!=='function'){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==='object'){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v;}else{delete value[k];}}}}
return reviver.call(holder,key,value);}
cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return'\\u'+
('0000'+a.charCodeAt(0).toString(16)).slice(-4);});}
if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){j=eval('('+text+')');return typeof reviver==='function'?walk({'':j},''):j;}
throw new SyntaxError('JSON.parse');};}}());

function clone(object) { 
	function F(){};
	F.prototype = object;
	return new F();
}

function delegate(that, thatMethod, source){
    return function(e) {
		return thatMethod.call(that, source, e); 
	}
}

function arrayDifference(a1, a2) {
	var a=[], diff=[];
	for(var i=0, len=a1.length; i < len; i++)
		a[a1[i]]=true;
	for(var i=0, len=a2.length; i < len; i++)
		if(a[a2[i]]) 
			delete a[a2[i]];
		else 
			a[a2[i]]=true;
	for(var k in a)
		diff.push(k);
	return diff;
}

function objectKeys(obj) {
    var out = [];
    for (var i in obj)
    	out.push(i);
    return out;
}

function objectValues(obj) {
    var out = [];
    for (var i in obj)
    	out.push(obj[i]);
    return out;
}

function setStyles(oElem, oStyles) {
	for(var i in oStyles)
		if(oElem)oElem.style[i] = oStyles[i]
}

function $id(n) {return document.getElementById(n)}


//

function activateMenus(objs) {
	var dropdowns = []
	Common.Event.add(document, 'click', clearDropdowns)
	for(var i = objs.length-1 ; i >= 0 ; i--)
		if((c=objs[i].childNodes).length > 1) {
			Common.Event.add(c[0].childNodes[0], 'mouseover', function(e){
				Common.Event.cancel(e)
			})
			Common.Event.add(c[0], 'mouseover', function(e){
				clearDropdowns()
				var trg = Common.Event.normalize(e).target
				var coords = Common.Dom.getAbsoluteCoords(trg, true)
				
				setStyles(trg.nextSibling, {display:'block', top:coords.iTop+coords.iHeight, left:coords.iLeft})
			})
			Common.Event.add(c[1], 'click', function(e){
				Common.Event.cancel(e)
			})
			dropdowns.push(c[1])
		} else 
			Common.Event.add(c[0], 'mouseover', clearDropdowns)
			
	function clearDropdowns() {
		for(var i = dropdowns.length-1 ; i >= 0 ; i--)
			setStyles(dropdowns[i], {display:'none'})
	}
}
