//Extensions
String.prototype.has = function(){
	for (var i=0, l=arguments.length; i<l; i++){
		if (this.indexOf(arguments[i]) != -1){
			return true;
		}
	}
	return false;
}

//global stubhub object
window.stubhub = {};
stubhub.makeNamespace = function(){
	var args = arguments,
	l = args.length;
	for (var i=0; i<l; i++){
		var aNs = args[i].split("."),
		aNsLen = aNs.length,
		ns = stubhub;
		
		for (var j=(aNs[0] == "stubhub") ? 1 : 0; j<aNsLen; j++){
			if (!ns[aNs[j]])
				ns[aNs[j]] = {};
			ns = ns[aNs[j]];
		}
	}
}

stubhub.getElementsByClassName = function(name){
	return this.getElementsByClassNameHelper(document, name);
}

stubhub.getElementsByClassNameHelper = function(context, name){
	var elems = [];
	var className = new RegExp("\\b"+name+"\\b", i);
	var all = context["getElementsByTagName"]("*"),
	len = all.length;
	for (var i=0; i<len; i++){
		var elem = all[i];
		if (className.test(elem.className)){
			elems[elems.length] = elem;
		}
	}
	return elems;
}

stubhub.includeCSS = function(sUrl){
	var s = document.createElement("link");
	s.type = "text/css";
	s.rel = "stylesheet";
	s.href = sUrl;
	document.getElementsByTagName("head")[0].appendChild(s);
}

//Douglas Crockford
//http://javascript.crockford.com/prototypal.html
stubhub.extend = function(obj){
	function F(){};
	F.prototype = obj;
	return new F();
}

//define namespaces
stubhub.makeNamespace(
	"stubhub.env",
	"stubhub.globals",
	"stubhub.utils",
	"stubhub.objs",
	"stubhub.ui.core",
	"stubhub.evts"
);

//obj cache
stubhub.pageObjs = [];
stubhub.getObj = function(id, type){
	var o = null;
	var l = stubhub.pageObjs.length;
	for (var i=0; i<l; i++){
		var itm = stubhub.pageObjs[i];
		if (itm.id == id && itm.objType == (new type().objType)){
			o = itm;
			break;
		}
	}
	if (!o){
		o = new type(id);
		stubhub.pageObjs[l] = o;
	}
	return o;
}

/**
* BaseObject
* Base StubHub Object
* @namespace stubhub.objs
*/
stubhub.objs.BaseObject = (function(){

	var events = {};
	
	function F(){};
	F.objType = "stubhub.objs.BaseObject";
	
	F.addEventListener = function(pEvent, pListener){
		var aListeners = events[pEvent];
		if (!aListeners){
			aListeners = events[pEvent] = [];
		}
		aListeners[aListeners.length] = pListener;
	};
	
	F.dispatchEvent = function(pEvent, pMsg){
		if (!pMsg){
			pMsg = new stubhub.objs.EventMessage(pEvent, this);
		}
		
		var aListeners = events[pEvent];
		if (aListeners){
			var l = aListeners.length;
			for (var i=0; i<l; i++){
				fHandle = aListeners[i];
				fHandle.apply(this, [pMsg]);
			}
		}
	};
	
	F.removeEventListener = function(pEvent, pListener){
		var aListeners = (events[pEvent] ? events[pEvent] : []);
		var retListener = null;
		if (aListeners){
			var l = aListeners.length;
			for (var i=0; i<l; i++){
				if (aListeners[i] === pListener){
					aListeners.splice(i,1);
					retListener = pListener
					break;
				}
			}
		}
		
		return retListener;
	};
	
	F.removeAllEventListeners = function(pEvent){
		if (pEvent){
			events[pEvent] = [];
		} else {
			events = [];
		}
	}
	
	F.registerEvent = function(nativeEvent, handlerName){
		var obj = this;
		if (this.elem){
			this.elem[nativeEvent] = function(evt){return obj[handlerName](evt||window.event);};
		}
	}

	return F;
});

//set up event handling for window.onload
stubhub.window = new stubhub.objs.BaseObject();

stubhub.window.registerEvent("resize", "onResize");
stubhub.window.onResize = function(evt){this.dispatchEvent("resize", new stubhub.objs.EventMessage("resize", this, evt));};

stubhub.window.registerEvent("load", "onLoad");
stubhub.window.onLoad = function(evt){this.dispatchEvent("load", new stubhub.objs.EventMessage("onload", this, evt));};
if (window.onload){
	stubhub.onloadCache = window.onload;
}
window.onload = function(){
	if (stubhub.onloadCache){
		stubhub.onloadCache();
	}
	stubhub.window.onLoad();
};


/**
* EventMessage
* Passed around in event handling
* @constructor
* @namespace stubhub.objs
* @base stubhub.objs.BaseObject
* @param {String} id The id of the event
* @param {String} src Origin of event
* @param {event} evt Native js event object
* @return EventMessage object
*/
stubhub.objs.EventMessage = function(id, src, evt){
	
	var o = stubhub.extend(new stubhub.objs.BaseObject);		
	o.id = id;
	o.source = src;
	o.nativeEvent = evt;
	
	return o;
};


/**
* Client
* contains details of browser
* @base BaseObject
* @namespace stubhub.env
* @return Client object
*/
stubhub.env.Client = function(){
	
	var o = stubhub.extend(stubhub.objs.BaseObject);		

	o.bFirefox = o.bOpera = o.bIE = o.bSafari =
		o.bWin = o.bMac = o.bMacppc = o.bMactel = 
		o.bActiveXSupported = o.bWinXp = o.bXpSp2 = o.bAOL = o.bVista = false;
	o.iVer = o.fVer = -1;
	
	o.init = function()
	{
		var nv = navigator, agt = nv.userAgent.toLowerCase(), i = 0, ver;

		with (this)
		{
			//Browser and version detection
			//Do least common browsers first because many browsers report "msie"
			//as a compatible engine
			if (agt.has("firefox"))
			{
				bFirefox = true;
				i = agt.lastIndexOf("firefox") + 8;
			}
			else if (agt.has("safari"))
			{
				bSafari = true;
				i = agt.lastIndexOf("safari") + 7;
			}
			else if(typeof(window.opera)!="undefined")
			{
				bOpera = true;
				i = agt.lastIndexOf("opera") + 6;
			}
			/*
			else if (nv.appName.is("Netscape"))
			{
				bNav = true;
				i = agt.lastIndexOf("/") + 1;
			}
			*/
			else if (agt.has("msie"))
			{
				bIE = true;
				i = agt.indexOf("msie") + 4;
				if (agt.has('aol') || agt.has('america online'))
					bAOL = true;
			}
			ver = bOpera?window.opera.version():agt.substring(i);
			//ver = agt.substring(i);
			iVer = parseInt(ver);
			fVer = parseFloat(ver);
            fMinorVer = fVer - iVer;

			//Operating system detection
			bWin = agt.has("win");
			bWinXp = (bWin && agt.has("windows nt 5.1"));
			bVista = (bWin && agt.has("windows nt 6.0"));
			bXpSp2 = (bWinXp && agt.has("sv1"));
			bMac = agt.has("mac");
			bMacppc = (bMac && agt.has("ppc","powerpc"));
			bMactel = (bMac && agt.has("intel")); 
			
			//ActiveX support
			bActiveXSupported =	(!bMac && (typeof(ActiveXObject) == 'function'));
		}
		
		return this;
	}
	
	return o.init();
}();

/**
* Elem
* represents html element
* @constructor
* @base BaseObject
* @namespace stubhub.ui.core
* @param {String} id The html id of html element
* @return Elem object
*/
stubhub.ui.core.Elem = function(id){

	var o = stubhub.extend(new stubhub.objs.BaseObject);		
	o.objType = "Elem";
	o.isHidden = false;
	o.bind = function(pId){
		this.id = pId;
		var o = document.getElementById(this.id);
		this.elem = (o) ? o : null;
		
		return this;
	}
	o.hide = function(bNoDisplayChange){
		var e = this.elem;
		if (e){
			var s = e.style;
			s.visibility = "hidden";
			if (!bNoDisplayChange){
				s.display = "none";
			}
			this.isHidden = true;
			this.dispatchEvent("hide");
		}
	}
	o.show = function(bNoDisplayChange){
		var e = this.elem;
		if (e){
			var s = e.style;
			s.visibility = "visible";
			if (!bNoDisplayChange){
				s.display = "inline";
			}
			this.isHidden = false;
			this.dispatchEvent("show");

		}
	}
	o.getOffsetLeft = function(){
		return this.getAbsoluteOffset(this.elem, "offsetLeft");
	}
	o.getOffsetTop = function(){
		return this.getAbsoluteOffset(this.elem, "offsetTop");
	}
	o.getAbsoluteOffset = function(oElem, sProperty){
		var offset = 0;
		while (oElem){
			offset += oElem[sProperty];
			oElem = oElem.offsetParent;
		}
		return offset;
	}
	o.getElementsByClassName = function(sName){
		return stubhub.getElementsByClassNameHelper(this.elem, sName);
	}
	o.addClassName = function(sName){
		var sClasses = this.elem.className;
		if (sClasses.indexOf(sName)<0){
			this.elem.className = sClasses + " " + sName;
		}
		return this;
	}
	o.removeClassName = function(sName){
		var sClasses = this.elem.className;
		if (sClasses.indexOf(sName)>-1){
			var aClasses = sClasses.split(" ");
			var sNew = "";
			for (var i=0, l=aClasses.length; i<l; i++){
				if (aClasses[i]!=sName){
					sNew = sNew + (i!=0?" ":"") + aClasses[i];
				}
			}
			this.elem.className = sNew;
		}
		return this;
	}

	return o.bind(id);
};
