// alert("Module xmlParserLib.js [v20040427] has loaded.");
//  <!-- to use this module, copy following (commented) line to your html file -->
//	<!-- <script src="/{server_alias}/includes/xmlParserLib.js"></script> -->

/* 
	name:	xmlParserLib.js
	dir:	htdocs/includes
	by: 	OpenAsia Solutions Pte Ltd
	func:	this library provides mechanisms to load an XML presentation script, 
			and to receive the name of that script as a URL parameter;
			the 'parseURL' function retrieves all CGI parameters passed in the URL, 
			and then loads them into a new 'keyVals' property in the current window;
			the 'openXMLfile' function is designed to receive the filename, and attempt
			to load the XML file, assuming the browser is capable (IE5 or NS6 or later);
			the loading may be asynchronous, especially if the XML file is very large,
			so we have to wait for an 'onload' event before doing any parsing of the XML;
			once the XML is loaded, we can parse the metadata into a presentation object,
			and parse the events into an array, which is sorted based on start times;
			at this point, the other presentation functions may be launched;
			support for Javascript 1.3 is required
	rev: 	20030906, wmc, created this module 
			20031009, wmc, fixed bug in 'parseXML' to permit nodes with blank entries
			20031011, wmc, added check for null XML object in 'parseXML' function, and added
				more detailed error message for parsing errors (such as ampersand errors) 
			20040204, wmc, fixed bug in 'parseURL' to unescape the search string before parsing
			20040427, wmc, added new function 'parseXMLmanifest' to read the programme manifest;
				deprecated 'parseXML' in favor of 'parseXMLscript', and fixed an error in both
				functions to assure that missing or empty tags don't break the parsing process
			20050530, wmc, modified 'parseXMLmanifest' to capture only integer bitrate values
			20050830, wmc, added validation check for 'callbackStr' parameter in 'openXMLfile';
				added support for different baseURL for Windows Media and RealMedia
	
	--------------------------------------------------------------------------------
	Following are the common client-side functions defined in this module.
	--------------------------------------------------------------------------------
	parseURL			retrieves CGI params as name/value pairs, stores them in window frame
	openXMLfile			loads an XML file from local drive of URL, invokes handler
	parseXMLscript		parses the presentation script to extract metadata and events list
						(this is a special-purpose function for handling presentation scripts)
	parseXMLmanifest	parses the programme manifest to extract metadata and the show list
						(this is a special-purpose function for handling programme manifests)
	safeTryCatch		utility function to protect try-catch syntax from throwing errors in NS4
	countChildren		utility function to count the valid child nodes under some XML node
	createTable			utility function to create a browsable table of XML contents

*/

var global = (top.dataframe ? top.dataframe : this);
var xmlParserLib = this;
var xmlDoc;						// create XML document object
var pObj = new Object;			// create a presentation object
var mObj = new Object;			// create a manifest object
var cgiParams = new Object;		// create an object to contain the CGI parameters

function parseURL (url) {
		// adds a new 'keyVals' property to the window.location object
		// note that this implementation is case-sensitive when retrieving by key
		// for example, where 'name=value', 'keyVals["name"]' returns 'value';
		// you may also access the parmeter pairs in order, as keyVals[0], etc.
	if (!url) return (null);
	var urlSearchStr = url.substring(url.indexOf("?") + 1, url.length);
	if (urlSearchStr == "") return (null);

	cgiParams.keyVals = unescape(urlSearchStr).split('&');
	for (var i = 0, num = cgiParams.keyVals.length; i < num; i++) {
		var pair = cgiParams.keyVals[i].split('=');
		cgiParams.keyVals[pair[0].toLowerCase()] = pair[1];
	}
	return (cgiParams.keyVals);
}

function openXMLfile (filename, callbackStr) {
	var loadStatus = false;
	if (typeof(callbackStr) != "string") {
		alert("Error in xmlParserLib.openXMLfile - expects callback parameter as string.");
		return (false);
	} else if (eval("this." + callbackStr) == undefined) {
		alert("Error in xmlParserLib.openXMLfile - could not find callback function: '" + callbackStr + "'.");
		return (false);
	}
		// try reading the file using Navigator 6.x and IE 5.x object model (others not supported)
	if (document.implementation && document.implementation.createDocument) {
		xmlDoc = document.implementation.createDocument("", "", null);
		xmlDoc.onload = callbackStr;		// Netscape loads asynchronously
		var errMsg = "Error in 'xmlParserLib' - the XML file '" + filename + "' could not be found, or was invalid.";
		safeTryCatch ("xmlDoc.load('" + filename + "?rev=20031102_02');", errMsg);
		loadStatus = true;
	} else if (window.ActiveXObject) {
		xmlDoc = new ActiveXObject("Microsoft.XMLDOM");		
		xmlDoc.async = true;	// if set to 'false', script execution is blocked until load completes
		xmlDoc.onreadystatechange = function () {
			if (xmlDoc.readyState == 4) 
				eval(callbackStr + "()");
		};		// need semicolon, you're declaring a function
		xmlDoc.load(filename + "?rev=20031102_02");		// change revision date to clear any caches
		if (xmlDoc.parseError.errorCode != 0) {
			var strErrMsg = (global.commonLib ? trim(xmlDoc.parseError.srcText) : xmlDoc.parseError.srcText);
			alert("Error in 'xmlParserLib' - the XML file '" + filename + "' could not be found, or was invalid.\n" +
				"Reason: " + xmlDoc.parseError.reason + 
				"Line: " + xmlDoc.parseError.line + ", position: " + xmlDoc.parseError.linepos + "\n" +
				"Source text: " + strErrMsg + "\n");
		} else {
			loadStatus = true;
		}
 	} else {
		alert("Error in 'xmlParserLib' - Your browser is not able to read XML, required for this application. " + 
		  "\nPlease try using Internet Explorer 5+ or Netscape 6+.");
	}
	return (loadStatus);
}

function parseXMLscript () {
	var str = "";
	var node;
	var presentation = xmlDoc.documentElement;
	if (presentation == null) return;
	
		// get all the metadata (if a tag is not present, that variable will become an empty string)
	pObj.version = ((node = presentation.getElementsByTagName('version').item(0)) != null ? node.text : "");
	pObj.playerType = ((node = presentation.getElementsByTagName('playerType').item(0)) != null ? node.text : "");
	pObj.seriesTitle = ((node = presentation.getElementsByTagName('seriesTitle').item(0)) != null ? node.text : "");
	pObj.title = ((node = presentation.getElementsByTagName('title').item(0)) != null ? node.text : "");
	pObj.presenterName = ((node = presentation.getElementsByTagName('presenterName').item(0)) != null ? node.text : "");
	pObj.description = ((node = presentation.getElementsByTagName('description').item(0)) != null ? node.text : "");
	pObj.author = ((node = presentation.getElementsByTagName('author').item(0)) != null ? node.text : "");
	pObj.copyright = ((node = presentation.getElementsByTagName('copyright').item(0)) != null ? node.text : "");
	pObj.recordingDate = ((node = presentation.getElementsByTagName('recordingDate').item(0)) != null ? node.text : "");
	pObj.publicationDate = ((node = presentation.getElementsByTagName('publicationDate').item(0)) != null ? node.text : "");
	pObj.mediaSource = ((node = presentation.getElementsByTagName('mediaSource').item(0)) != null ? node.text : "");
	pObj.slideSource = ((node = presentation.getElementsByTagName('slideSource').item(0)) != null ? node.text : "");
	pObj.duration = ((node = presentation.getElementsByTagName('duration').item(0)) != null ? node.text : "");
	pObj.eventListSize = countChildren(presentation.getElementsByTagName('events').item(0));
	pObj.eventListArray_index_id = 0;
	pObj.eventListArray_index_time = 1;
	pObj.eventListArray_index_filename = 2;
	pObj.eventListArray_index_topic = 3;
	pObj.eventListArray_index_caption = 4;
	// alert(commonLib.peekInside(pObj, 'presentation'));
	
		// get the information for each event
	events = presentation.getElementsByTagName('events').item(0);
	if (events && events.hasChildNodes()) {
		var eventListArray = new Array();
		eventList = events.getElementsByTagName('event');
		for (var i = 0; i < eventList.length; i++) {
			var event = eventList[i];
			eventListArray[i] = new Array();
			eventListArray[i][pObj.eventListArray_index_id] = event.getAttribute('id');
			eventListArray[i][pObj.eventListArray_index_time] = event.getAttribute('startTime');
			if (event.hasChildNodes()) {
				for (var j = 0; j < event.childNodes.length; j++) {
					if (event.childNodes[j].nodeType != 1) continue;	// for Netscape to skip over formatting
					if (!event.childNodes[j].firstChild) continue;		// skip if entry is blank
					switch (event.childNodes[j].nodeName) {
						case "imageSlide":
							eventListArray[i][pObj.eventListArray_index_filename] = event.childNodes[j].firstChild.nodeValue;
							break;
						case "topic":
							eventListArray[i][pObj.eventListArray_index_topic] = event.childNodes[j].firstChild.nodeValue;
							break;
						case "caption":
							eventListArray[i][pObj.eventListArray_index_caption] = event.childNodes[j].firstChild.nodeValue;
							break;
						default:
					}
				}
			}
		}
		if (global.commonLib)
			commonLib.sortArray(eventListArray, 1);
		else 
			alert("Error in 'xmlParserLib' - slide events could not be sorted.")
		pObj.eventListArray = eventListArray;
		pObj.isLoaded = true;
		// alert(commonLib.peekInside(eventListArray, 'eventListArray'));
	} else {
		alert("Error in 'xmlParserLib' - no scripted events were found.");
	}
}

function parseXMLmanifest () {
	var str = "";
	var node;
	var manifest = xmlDoc.documentElement;
	if (manifest == null) return;
	
		// get all the metadata (if a tag is not present, that variable will become an empty string)
	mObj.version = ((node = manifest.getElementsByTagName('version').item(0)) != null ? node.text : "");
	mObj.seriesTitle = ((node = manifest.getElementsByTagName('seriesTitle').item(0)) != null ? node.text : "");
	mObj.description = ((node = manifest.getElementsByTagName('description').item(0)) != null ? node.text : "");
	mObj.WM_baseMediaURL = ((node = manifest.getElementsByTagName('WM_baseMediaURL').item(0)) != null ? node.text : "");
	mObj.RM_baseMediaURL = ((node = manifest.getElementsByTagName('RM_baseMediaURL').item(0)) != null ? node.text : "");
	mObj.bitrateMinimum = ((node = manifest.getElementsByTagName('bitrateMinimum').item(0)) != null ? node.text : "");
	mObj.showListSize = countChildren(manifest.getElementsByTagName('shows').item(0));
	mObj.showListArray_index_id = 0;
	mObj.showListArray_index_name = 1;
	mObj.showListArray_index_presentationFile = 2;
	mObj.showListArray_index_scriptFile = 3;
	mObj.showListArray_index_mediaFile = 4;
	mObj.showListArray_index_mediaType = 5;
	mObj.showListArray_index_bitrate = 6;
	mObj.showListArray_index_isRestricted = 7;
	// alert(commonLib.peekInside(mObj, 'showList'));
	
		// get the information for each show
	shows = manifest.getElementsByTagName('shows').item(0);
	if (shows && shows.hasChildNodes()) {
		var showListArray = new Array();
		showList = shows.getElementsByTagName('show');
		for (var i = 0; i < showList.length; i++) {
			var show = showList[i];
			showListArray[i] = new Array();
			showListArray[i][mObj.showListArray_index_id] = show.getAttribute('id');
			showListArray[i][mObj.showListArray_index_name] = show.getAttribute('name');
			if (show.hasChildNodes()) {
				for (var j = 0; j < show.childNodes.length; j++) {
					if (show.childNodes[j].nodeType != 1) continue;	// for Netscape to skip over formatting
					if (!show.childNodes[j].firstChild) continue;		// skip if entry is blank
					switch (show.childNodes[j].nodeName) {
						case "presentationFile":
							showListArray[i][mObj.showListArray_index_presentationFile] = show.childNodes[j].firstChild.nodeValue;
							break;
						case "scriptFile":
							showListArray[i][mObj.showListArray_index_scriptFile] = show.childNodes[j].firstChild.nodeValue;
							break;
						case "mediaFile":
							showListArray[i][mObj.showListArray_index_mediaFile] = show.childNodes[j].firstChild.nodeValue;
							break;
						case "mediaType":
							showListArray[i][mObj.showListArray_index_mediaType] = show.childNodes[j].firstChild.nodeValue;
							break;
						case "bitrate":
							showListArray[i][mObj.showListArray_index_bitrate] = parseInt(show.childNodes[j].firstChild.nodeValue);
							break;
						case "isRestricted":
							showListArray[i][mObj.showListArray_index_isRestricted] = show.childNodes[j].firstChild.nodeValue;
							break;
						default:
					}
				}
			}
		}
		mObj.showListArray = showListArray;
		mObj.isLoaded = true;
		// alert(commonLib.peekInside(showListArray, 'showListArray'));
	} else {
		alert("Error in 'xmlParserLib' - no shows were found in the manifest.");
	}
}

function safeTryCatch (functionDeclaration, errMsg) {
		// this is necessary to prshow 'try' syntax errors in NS4 browsers
		// if we simply lock out browsers that don't support JS1.4, we omit IE5
	if (document.implementation && document.implementation.createDocument) 
		eval ("try {" + functionDeclaration + "} catch(err){ if (errMsg) alert(\"" + errMsg + "\");}");
}

function countChildren (node) {
	if (!node) return (0);
	var i = 0;
	var j = 0;
	while (i < node.childNodes.length) 
		if (node.childNodes[i++].nodeType == 1) j++;
	return (j);
}

function createTable (displayElement, pageLocation) {
	if (!document.getElementById(pageLocation)) {
		alert("Error in 'xmlParserLib' - unable to find page location: '" + pageLocation + "'.\t");
	} else {
		var x = xmlDoc.getElementsByTagName(displayElement);
		var newEl = document.createElement('TABLE');
		newEl.setAttribute('cellPadding', 5);
		var tmp = document.createElement('TBODY');
		newEl.appendChild(tmp);
		var row = document.createElement('TR');
		for (j=0; j < x[0].childNodes.length; j++) {
			if (x[0].childNodes[j].nodeType != 1) 
				continue;
			var container = document.createElement('TH');
			var theData = document.createTextNode(x[0].childNodes[j].nodeName);
			container.appendChild(theData);
			row.appendChild(container);
		}
		tmp.appendChild(row);
		for (i = 0; i < x.length; i++) {
			var row = document.createElement('TR');
			for (j=0; j < x[i].childNodes.length; j++) {
				if (x[i].childNodes[j].nodeType != 1) 
					continue;
				var container = document.createElement('TD');
				var theData = document.createTextNode(x[i].childNodes[j].firstChild.nodeValue);
				container.appendChild(theData);
				row.appendChild(container);
			}
			tmp.appendChild(row);
		}
		document.getElementById(pageLocation).appendChild(newEl);
	}
}

	/* DEPRECATED FUNCTIONS */
function parseXML () {
	parseXMLscript ();
}

