// ********************************************************************************************
// User-Agent detection and cross-browser interop routines © Ben Johnson, 2004
// 	- REQUIRES: [core]
// ********************************************************************************************
SetModStatus("xb.core", "loaded");

// MODULE INITIALISE **************************************************************************
if(!window.MANUAL_MODULE_INITIALISE) InitXBrowserModule();
function InitXBrowserModule() {
	window.UA = new BrowserFeatures();
	UA.Report(4);
	SetModStatus("xb.core", "ready");
}

function RunXBCompatRoutines() {
	if(UA.ie && !UA.ecma3) AFModInc("xb.fixIE5");
	if(UA.moz) AFModInc("thirdParty/ieemu");
}


// USER AGENT CAPABILITIES DETECT *************************************************************

// User Agent capability flags (better practice than sniff browser versions) and other info/methods
// 		e.g., var UA = new BrowserFeatures(); if(UA.dom0) ..
function BrowserFeatures() {
	try {
		// temp support notes:
		// Mozilla (NS7?) as at 2001 supports: DOM1 core, DOM1 html, DOM2 core, DOM2 views, DOM2 events
		// IE6 = all DOM1 ("Document Object Model (DOM) Level 1") properties, methods, and collections, according to MS
		// IE5 = DHTML Object Model + partial DOM1
	
		// IE-compatible DHTML (IE4+)
		this.ieDhtml = Boolean(D.all && window.showHelp);
	
		// basic DOM support - DOM0 (IE5+, NS6+)
		this.dom0 = Boolean(D.getElementsByTagName && D.createElement);
	
		// W3C DOM1 + DOM1 HTML (NS6+?, NS7+, IE6+)
		this.dom1 = Boolean(this.dom0 && D.implementation && D.implementation.hasFeature("HTML","1.0"));
	
		// W3C DOM2 (IE6+, NS6+)
		this.dom2core = Boolean(this.dom1 && D.createAttribute);
	
		// IE5+ compatible stylesheet manipulation (NOT DOM2 CSS)
		this.ieCss = Boolean(this.dom0 && D.createStyleSheet);
	
		// W3C compatible (but NOT full DOM2 CSS) stylesheet manipulation (NS6?, NS7+)
		this.domCss = Boolean(this.dom1 && window.getComputedStyle);
	
		// whether supports IE5+ compatible events model (NOT DOM2 Events. Note that IE5.0 doesn't support fireEvent)
		this.ieEvents = Boolean(this.dom0 && window.attachEvent);
	
		// W3C compatible (but not full DOM2 Events) events model (NS6+)
		this.domEvents = Boolean(window.addEventListener && window.removeEventListener);
	
		// whether browser is in 'W3C standards' mode, rather than 'quirks' mode (NS6?, IE6+, NS7+, Opera)
		this.standardsMode = Boolean(D.compatMode && (D.compatMode == "CSS1Compat"));
	
		// whether browser supports ECMA3 (Javascript 5)
		this.ecma3 = Boolean(Array.prototype.push && Function.prototype.apply);
		
		
		// down n' dirty IE/Mozilla flags (tests taken from ieEmu)
		this.ie = (this.ieDhtml) && /MSIE/.test(navigator.userAgent);
		this.moz = (!this.ie) && (navigator.product == "Gecko");
	
		this.jscriptVer = (typeof ScriptEngineMajorVersion=="function")? parseFloat(ScriptEngineMajorVersion() +"."+ ScriptEngineMinorVersion()) : null;
	
	
		this.Report = function Report(iDbgLevel) {
			if(!iDbgLevel) iDbgLevel = 2;									// default to debug level 2
			var bDbgAvail = Boolean(Mod("dbg"));					// adapt to whether debug window is available
			
			if(DBG_LEVEL >= iDbgLevel) {
				if(!Mod("js.strings")) { WarnMsg("[js.strings] required by Report()"); return false; }

				var asFeatures = ["ieDhtml", "dom0", "dom1", "dom2core", "ieCss", "domCss", "ieEvents", "domEvents", "standardsMode"];
				var lstFeatures = new ListBuilder(bDbgAvail? "<br>" : "\n");
				var sTitle = "Your browser supports/has enabled:"
		
				lstFeatures.Add(bDbgAvail? "<span style='line-height:18pt'>"+sTitle.bold()+"</span>" : sTitle);
				for(var x in asFeatures)
					if(bDbgAvail)
						lstFeatures.Add("<span style='cursor:no-drop;' onclick='this.parentNode.removeNode(true)' style='"+ (this[asFeatures[x]]? "color:blue; font-weight:bold;" : "color:gray;") +"'>"+ asFeatures[x] +"</span>");
					else
						lstFeatures.Add(asFeatures[x] +" = "+ this[asFeatures[x]]);
		
				// display via debug win or alert
				if(bDbgAvail)
					DbgMsg(lstFeatures, iDbgLevel);
				else 
					if(DBG_LEVEL > iDbgLevel) alert(lstFeatures);		// if going to have to use intrusive alert, increment required dbg level
	
				return true; 
			}
		}

		// returns true if userAgent string includes sText, otherwise false
		this.IsUA = function IsUA(sText) {  return navigator.userAgent.contains(sText)? true : false;  }
	}
	catch(oErr) {
		// error occurred in browser detect routine
	}
}


// MISC XBROWSER ROUTINES *********************************************************************

// if global pointer to element with specified ID doesn't exist (non-IE), create one. Either way, return pointer to the element
//   returns null if element with matching ID doesn't exist
function Ptr(sElemId) {
	if(!window[sElemId]) window[sElemId] = document.getElementById(sElemId);
	return window[sElemId];
}


// TO DO: just always use getAttribute() instead??
// allows access/set specified attribute via an IE-like expando property on the specified element (needed in NS6, but not 7?)
// 	e.g.:	 	AddAttrib( myElem, "oldvalue" ); alert(myElem.oldvalue); myElem.oldvalue = "cat";
function AddAttrib( oElem, sAttribName ) {
	if(!oElem[sAttribName]) {
		DbgMsg("Adding '" + sAttribName + "' attribute to "+ (oElem.id? "element '"+ oElem.id +"'" : "specified element"), 4);
		oElem[sAttribName] = function() { return this.getAttribute(sAttribName); }
	}
}


// Explicitly attaches onclick event handler using script specified by onclick attribute
//   This fixes problem in Netscape 6 where onclick handler wasn't firing for cloned elements
function FixNS6OnClick(oElem) {
	oClone.addEventListener("click", Function( oElem.getAttribute("onclick"), false) );
}



/* OLD (use 'xb.fixIE5' instead):

	// JAVASCRIPT FIX ROUTINES ********************************************************************
	
	// TO DO: seperate to IE5 compatibility module and load via dynamic script include
	
	// routines for setting up standard push()/pop() methods on all Array objects (missing in JS5.0)
	function ExtendJS5ArrayObject() {
		if(typeof [].push != "function") {
			Array.prototype.push = ArrayPush;
			Array.prototype.pop = ArrayPop;
		}
	}
	function ArrayPush(sText) {	this[this.length] = sText; return this.length; }
	function ArrayPop() { var vLast = this[this.length-1]; this.length--; return vLast; }

*/
