/*
 	The first part is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    A copy of the GNU General Public License can be obtained from http://www.gnu.org/licenses/.
*/

/*
* 	Copyright (c) 2002 Thinking Arts Ltd (contact via http://www.thinkingarts.com/).
*/
  

//--------------------------------------------------------------------

//NetCommunicator Class
//Requests and receives data from server

//Network Communicaor class constructor 
//url : URL of Server Program or File
//userCallbackFunc : User function to be called when request returned
//					 The function has one argument for the returned data
//onerrorFunc : User On error Function (Defaults to defaultErrorHandler)
//				If supplied the function has one argument for an error message
function NetCommunicator (url){
	
 	this.url = url;
	this.request = null;
	this.userCallbackFunc = null;
	this.onerror = null;
	this.sourceObject = null;
}	
	
//Method to send request
//params : Parameters to send with request
//userCallbackFunc: user function to call with data
//onerrorFunc: user function to call on error
//sourceObject: Object originating call - used for call back context
//httpMethod : HTTP Method to use (Defaults to POST)
NetCommunicator.prototype.sendRequest = function(params, userCallbackFunc, onerrorFunc, sourceObject, httpMethod){
	if(!httpMethod){
		httpMethod = "POST";
	}
	
	this.sourceObject = sourceObject;
	this.userCallbackFunc = userCallbackFunc;
	this.onerror = (onerrorFunc) ? onerrorFunc : this.defaultErrorHandler;
	this.request = this.initXMLHTTPRequest();
	
	if(this.request){
		try{

			var thisInstance = this;
			//The call means that the onload function is called with this object as its context;
			this.request.onreadystatechange = function(){thisInstance.onload.call(thisInstance);}; 
			
			this.request.open(httpMethod,this.url,true);
			//this.request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");		
			this.request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");		
			this.request.send(params);
		}
		catch(err){
			this.onerror("Failed to send request with error: " + err.message);
		}	
	}
	else{
		this.onerror("Failed to initialize XML HTTP Request");
	}
	
}

//Method to create an HTTP request object	
NetCommunicator.prototype.initXMLHTTPRequest = function () {
 	var xRequest = null;
	if(window.XMLHttpRequest){
		//Moziall/Safari
		xRequest = new XMLHttpRequest()	
	}
	else if(window.ActiveXObject != "undefined") {
		//IE
		xRequest = new ActiveXObject("Microsoft.XMLHTTP");
	}
	return xRequest;
 }
 
//Method called to handle server response
//When the data is complete the user's callback function is invoked.
NetCommunicator.prototype.onload = function () {
	var READY_STATE_UNINITIALIZED =0;
	var READY_STATE_LOADING = 1;
	var READY_STATE_LOADED = 2;
	var READY_STATE_INTERACTIVE = 3;
	var READY_STATE_COMPLETE = 4;
	
	var req = this.request;
	var ready = req.readyState;
	var data = null;
	
	
	if(ready == READY_STATE_COMPLETE){
		var httpStatus = req.status;
		if(httpStatus == 200 || httpStatus == 0){
			data = req.responseText;
			//data = req.responseXML;
			//Callback using call, where first argument is the context object
			this.userCallbackFunc.call(this.sourceObject, data);
		}
		else{
			this.onerror("HTTP Status Error " + httpStatus);
		}	
	}	 
	else{
	}
}  
 
//Method to act as default error handler 
//message : error message
NetCommunicator.prototype.defaultErrorHandler = function (message) {
	alert(message);
} 



//--------------------------------------------------------------------

//TaMap Class 

//Constructor for Map class
//siteUrl : URL of application directory
//mapXMLFile : Map filename
//mapID : Optional ID of div
//consoleID : Optional ID of console div
//statusID : Optioanl ID of status div
//traceID : Optioanl ID of trace div
//clearTraceID : Optioanl ID trace clear button
function TaMap(siteUrl, mapXMLFile, mapID, consoleID, statusID, traceID, clearTraceID){

	this.map = null;
	this.mapId = null;
	this.siteUrl = siteUrl;
	this.appUrl = null;
	this.mapXMLFile = mapXMLFile;
	this.taServerProgram = "ObjectServerV2.php?";
	this.objectArray = new Array();
	this.initialLatitude = 0;
	this.initialLongitude =  0;
	this.initialZoom =  1;
	this.lowestMarkedZoomLevel = 1;
	this.lowestMarkedZoomLevel = 1;
	this.iconPath = null;
	this.traceOn = false;	
	this.currentlySelectedLatitude = null;
	this.currentlySelectedLongitude = null;
	this.dataManager = new TaDataManager(this);
	this.iconPath = null;
	this.crossIcon = null;
	this.singleIcon = null;
	this.singleSelectedIcon = null;
	this.multipleIcon = null;
	this.multipleSelectedIcon = null;
	this.selectedObjectHtmlArray = null;
	this.mapID = mapID ?  mapID : 'map';
	this.consoleID = consoleID ? consoleID : 'mapConsole';
	this.statusID = statusID ? statusID : 'mapStatus';
	this.traceID = traceID ? traceID : 'mapTrace';
	this.clearTraceID = clearTraceID ? clearTraceID : 'mapClearTrace';
	this.console = new TaConsole(this.consoleID);
	this.trace = new TaTrace(this.traceID, this.clearTraceID);
	this.status = new TaStatus(this.statusID);
	this.tooltipArray =  new Array();
	
	
	if(! this.siteUrl || ! this.mapXMLFile){
		//taReportError('Site URL or XML File not specified.');
		return;
	}	
	
	this.appUrl = this.siteUrl + this.taServerProgram;
	
	myParams = 'Service=FetchInitializationData&ParamFile=' + this.mapXMLFile; 

	var callBackFunc = this.initializationCallBack;
	var errorFunc = taReportError;
	var thisInstance = this;
	var net = new NetCommunicator (this.appUrl);
	net.sendRequest(myParams, callBackFunc, errorFunc, thisInstance); 
	net = null;
} 

//Function called with initialization data
//dataIn : data from server
TaMap.prototype.initializationCallBack = function (dataIn){
	
	//Extract initialization values from data
	obj = new Object;
	var statusObj = this.dataManager.processInitializationData(dataIn, obj);
	if(statusObj.responseCode > 0){
		taReportError(statusObj.message);
		return;
	}	
	if(obj.TitleColumnToShowWhenCursorOverIcon){	
		this.titleColumnToShowWhenCursorOverIcon = obj.TitleColumnToShowWhenCursorOverIcon;
	}		
	if(obj.DescriptionColumnToShowWhenCursorOverIcon){	
		this.descriptionColumnToShowWhenCursorOverIcon = obj.DescriptionColumnToShowWhenCursorOverIcon;
	}
	if(obj.ImageColumnToShowWhenCursorOverIcon){	
		this.imageColumnToShowWhenCursorOverIcon = obj.ImageColumnToShowWhenCursorOverIcon;
	}
	if(obj.ImagePathForImageToShowWhenCursorOverIcon){	
		this.imagePathForImageToShowWhenCursorOverIcon = obj.ImagePathForImageToShowWhenCursorOverIcon;
	}
	this.initialLatitude = parseFloat(obj.InitialLatitude);
	this.initialLongitude =  parseFloat(obj.InitialLongitude);
	this.initialZoom =  parseInt(obj.InitialZoom);
	this.lowestMarkedZoomLevel = parseInt(obj.LowestMarkedZoomLevel);	
	this.iconPath = obj.IconPath;
	if(obj.TraceOn.toLowerCase() == 'yes' || obj.TraceOn == 1){
		this.traceOn = true;
	}			
	if(obj.SingleIconName){
		this.singleIcon = this.dataManager.createIcon(this.siteUrl, this.iconPath, obj.SingleIconName, obj.SingleIconSize, obj.SingleIconAnchorPoint);
	}
	if(obj.SingleSelectedIconName){
		this.singleSelectedIcon = this.dataManager.createIcon(this.siteUrl, this.iconPath, obj.SingleSelectedIconName, obj.SingleSelectedIconSize, obj.SingleSelectedIconAnchorPoint);
	}
	if(obj.MultipleIconName){
		this.multipleIcon = this.dataManager.createIcon(this.siteUrl, this.iconPath, obj.MultipleIconName, obj.MultipleIconSize, obj.MultipleIconAnchorPoint);
	}
	if(obj.MultipleSelectedIconName){
		this.multipleSelectedIcon = this.dataManager.createIcon(this.siteUrl, this.iconPath, obj.MultipleSelectedIconName, obj.MultipleSelectedIconSize, obj.MultipleSelectedIconAnchorPoint);
	}

	//Apply Overrides if present
	if(document.getElementById("OverrideInitialLatitude")){
		if(document.getElementById("OverrideInitialLatitude").value){
			this.initialLatitude = parseFloat(document.getElementById("OverrideInitialLatitude").value);
		}
	}
	if(document.getElementById("OverrideInitialLongitude")){	
		if(document.getElementById("OverrideInitialLongitude").value){
			this.initialLongitude = parseFloat(document.getElementById("OverrideInitialLongitude").value);
		}
	}	
	if(document.getElementById("OverrideZoom")){
		if(document.getElementById("OverrideZoom").value){
			if(document.getElementById("OverrideInitialLatitude") && document.getElementById("OverrideInitialLongitude")){
				if(document.getElementById("OverrideInitialLatitude").value && document.getElementById("OverrideInitialLongitude").value){		
					this.initialZoom = parseInt(document.getElementById("OverrideZoom").value);
				}
			}		
		}
	}	
	
	if(document.getElementById("SetAsCcurrentlySelected")){
		var value = document.getElementById("SetAsCcurrentlySelected").value;
		if( value == 1 || value.tolower == 'yes'){
			this.currentlySelectedLatitude = this.initialLatitude;
			this.currentlySelectedLongitude = this.initialLongitude;
		}
	}
		
	//Create map and add std zoom and map type contrlols
	this.map = new GMap2(document.getElementById(this.mapID));  
	this.map.addControl(new GSmallMapControl());
	this.map.addControl(new GMapTypeControl());	

	//Position map on page
	this.map.setCenter(new GLatLng(this.initialLatitude, this.initialLongitude), this.initialZoom);
	
	//Add listner function for map moved (zoomed) and click events
	var	thisInstance = this;
	var func = function(){thisInstance.mapMoved.call(thisInstance);}; 
	GEvent.addListener(this.map, "moveend", func );
	GEvent.addListener(this.map, 'click', function(){thisInstance.mapClicked.call(thisInstance,arguments[0],arguments[1]);});

	if(this.traceOn){
		text = taReplaceSpecialChars(dataIn);
		text = text.replace( /\n/g, '<br>' );
		this.trace.output(text);
	}
	
	//Display map objects
	var center = this.map.getCenter();
	var zoomLevel = this.map.getZoom();
	if(zoomLevel >= this.lowestMarkedZoomLevel){
		this.requestAllMapObjectsInRange();
	}	
	
}

//Function to initiate request for a new set of objects from server
TaMap.prototype.requestAllMapObjectsInRange = function(){
	//Get Bounds
	//Add centre lat and long info
	var center = this.map.getCenter();
	var bounds =  this.map.getBounds();
	var span = bounds.toSpan();
	
	var centreLat = center.lat();
	var centreLong = center.lng();
	
	var topLat = centreLat + (span.lat()/ 2);
	var botLat = centreLat - (span.lat()/ 2);
	var lhsLong = centreLong - (span.lng()/ 2);
	var rhsLong = centreLong + (span.lng()/ 2);
	
	//Request objects from server
	var myParams = "Service=FetchAllServerObjectsInRange&ParamFile=" + this.mapXMLFile;
	myParams += "&UpperLatLimit=" + topLat;
	myParams +=	"&LowerLatLimit=" + botLat;
	myParams += "&LHSLongLimit=" + lhsLong;
	myParams += "&RHSLongLimit=" + rhsLong;
	
	var callBackFunc = this.matchingObjectsCallbackFunc;
	var errorFunc = taReportError;
	var thisInstance = this;
	var net = new NetCommunicator (this.appUrl);
	net.sendRequest(myParams, callBackFunc, errorFunc, thisInstance); 
	net = null;
}

//Function called back with server information on new objects
//datatIn : server data
TaMap.prototype.matchingObjectsCallbackFunc = function(dataIn) {

	var statusObj = this.dataManager.refreshObjectArrayFromData(dataIn);
	if(statusObj.responseCode > 0){
		taReportError(statusObj.message);
		return;
	}	
	this.outputObjectArray();
}

//Function to display objects in map
TaMap.prototype.outputObjectArray = function(){	
	
	this.map.clearOverlays();
	this.hideTooltips();
	this.tooltipArray =  new Array();
	
	var latLngObj = new Object;
	var latLngMatchObj = new Object;
	var objectArrayIn = this.objectArray;
	var objectArray = new Array();
	
	//Search for mutlipe occurrences at sam lat/lng
	//If found do not add to obj array.
	for(var i=0; i < objectArrayIn.length; i++){
		obj = objectArrayIn[i];
		if(latLngObj[obj.Latitude]){
			if(latLngObj[obj.Latitude] == obj.Longitude){
				latLngMatchObj[obj.Latitude] = obj.Longitude;
			}
			else{
				objectArray.push(obj);
			}	
		}
		else{
			objectArray.push(obj);
		}		
		latLngObj[obj.Latitude] = obj.Longitude;
	}
	
	for(var i=0; i < objectArray.length; i++){
		obj = objectArray[i];
		
		var mIcon = this.multipleIcon;
		var sIcon = this.singleIcon;
		
		if(obj.Latitude == this.currentlySelectedLatitude && obj.Longitude == this.currentlySelectedLongitude){
			mIcon = this.multipleSelectedIcon;
			sIcon = this.singleSelectedIcon;
		}
		
		var toolTipTextTitle = obj[this.titleColumnToShowWhenCursorOverIcon];
		var toolTipTextDescription = obj[this.descriptionColumnToShowWhenCursorOverIcon];
		var toolTipTextImage = obj[this.imageColumnToShowWhenCursorOverIcon];
		var toolTipTextImagePath = obj[this.imagePathForImageToShowWhenCursorOverIcon];
		
		//Add back location marker
		var point = new GLatLng(obj.Latitude, obj.Longitude);
 		if(latLngMatchObj[obj.Latitude]){
			if(latLngMatchObj[obj.Latitude] == obj.Longitude){
				//Repleated lat/long
				this.addMarker(point,mIcon,toolTipTextTitle,toolTipTextDescription,toolTipTextImage,toolTipTextImagePath);
			}
			else{
				this.addMarker(point,sIcon,toolTipTextTitle,toolTipTextDescription,toolTipTextImage,toolTipTextImagePath);
			}	
		}
		else{
			this.addMarker(point,sIcon,toolTipTextTitle,toolTipTextDescription,toolTipTextImage,toolTipTextImagePath);
			//alert("Add " + toolTipTextTitle);
		}
	}	
	
	if(this.traceOn){
		//this.trace.clearTrace();
		linesArray = this.dataManager.printFormatServerData(this.objectArray);
		for(var i=0; i < linesArray.length; i++){
			this.trace.output(linesArray[i]);
		}
	}
}


//Function to add marker
TaMap.prototype.addMarker = function(point, iconType, toolTipTextTitle,toolTipTextDescription,toolTipTextImage,toolTipTextImagePath) {
	var marker = new GMarker(point,iconType);

	//To give the icon a title use the following
	//var marker = new GMarker(point,{icon: iconType, clickable: true, title: toolTipText}); 
	this.map.addOverlay(marker);
	var thisInstance = this;
	GEvent.addListener(marker, "mouseover", function(){thisInstance.showTooltip.call(thisInstance,marker,toolTipTextTitle,toolTipTextDescription,toolTipTextImage,toolTipTextImagePath, point);});
	GEvent.addListener(marker, "mouseout", function(){thisInstance.hideTooltips.call(thisInstance);});	
	//GEvent.addListener(marker, "mousemove", function(){thisInstance.hideWindow.call(thisInstance);});

}

TaMap.prototype.hideTooltips = function(){
	for(var i=0; i < this.tooltipArray.length; i++){
		this.tooltipArray[i].style.visibility="hidden";
	}
}	


//TaMap.prototype.hideWindow = function(){	
//	this.map.closeInfoWindow();	
//}		

TaMap.prototype.showTooltip = function(marker,toolTipTextTitle,toolTipTextDescription,toolTipTextImage,toolTipTextImagePath, latlng){


	//Create tooltip element and add to map
	var tooltip = document.createElement("div");
	//tooltip.style.border = "2px solid green"; 
	this.tooltipArray.push(tooltip);
	tooltip.innerHTML = this.makeTooltipHtml(toolTipTextTitle,toolTipTextDescription,toolTipTextImage,toolTipTextImagePath);
	tooltip.className = "tooltip";
    document.getElementById(this.mapID).appendChild(tooltip); 
    
  	
	//Locate position of tip
	var point=this.map.getCurrentMapType().getProjection().fromLatLngToPixel(this.map.getBounds().getSouthWest(),this.map.getZoom());
	var offset=this.map.getCurrentMapType().getProjection().fromLatLngToPixel(marker.getPoint(),this.map.getZoom());
	var anchor=marker.getIcon().iconAnchor;
	var height=tooltip.clientHeight;
	var width=parseInt(marker.getIcon().iconSize.width);
	var x = offset.x - point.x - anchor.x + width;
	var y =  point.y - offset.y  -anchor.y - parseInt(height/2);

	var pos = new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(x, y)); 
		
	//Add tip
	pos.apply(tooltip);
	tooltip.style.visibility="visible";

	
	//test code to creat bubble
	//this.map.closeInfoWindow();
	//this.map.openInfoWindow(latlng,document.createTextNode(toolTipText));	
	
	
}

//Make tooltip HTML 
TaMap.prototype.makeTooltipHtml = function(toolTipTextTitle,toolTipTextDescription,toolTipTextImage,toolTipTextImagePath){
	var url =  this.siteUrl + this.imagePathForImageToShowWhenCursorOverIcon + toolTipTextImage;	
	var html = '';	
	var titleHtml = '<span class="tooltipTitle">' + toolTipTextTitle + '</span>';
	var imageHtml = '<img src="' + url + '" width="50"  align="left" border="0" vspace="5px" name="Image" alt="Image">';
	var descriptionHtml = '<span class="tooltipText">' + toolTipTextDescription + '</span>';
	
	if(toolTipTextImage && toolTipTextDescription){
		html = '<table class="tooltipText" cellpadding="2" cellspacing="0" border="0">';
		html += '<tr><td align="center" colspan = "2">' + titleHtml + '</td></tr>';
		html += '<tr><td>' + imageHtml + '</td><td align="left" valign="top">' + descriptionHtml + '</td></tr>';
		html += '</table>';
	}	
	else if(toolTipTextImage){
		//Image, no description 
		html = '<table class="tooltipText" cellpadding="2" cellspacing="0" border="0">';
		html += '<tr><td align="center">' + titleHtml + '</td></tr>';
		html += '<tr><td>' + imageHtml + '</td></tr>';
		html += '</table>';
	}
	else{
		html = '<table class="tooltipText" cellpadding="2" cellspacing="0" border="0">';
		html += '<tr><td align="center">' + titleHtml + '</td></tr>';
		html += '<tr><td align="left">' + descriptionHtml + '</td></tr>';
		html += '</table>';
	}
	
	return html;
}


//Function called for map moved event
TaMap.prototype.mapMoved = function() {
	this.map.clearOverlays();	
	this.status.clearStatus();
	
	//Get map objects from server if with permitted zoom leve
	var center = this.map.getCenter();
	var zoomLevel = this.map.getZoom();
	if(zoomLevel >= this.lowestMarkedZoomLevel){
		this.requestAllMapObjectsInRange();
	}	
	
}

//Function called for map click event
TaMap.prototype.mapClicked = function (overlay, point) {
	
	this.hideTooltips();
	
	if (overlay) {
		this.status.clearStatus();
	 	this.selectedObjectHtmlArray = new Array();
		point = overlay.getPoint()
		var longitude = point.x;
		var latitude = point.y;
		this.console.clearConsole();
		 
		resultsArray = this.findObjectsForLatLong(this.objectArray, latitude, longitude);
   		
		if(resultsArray){
			this.currentlySelectedLatitude = latitude;
			this.currentlySelectedLongitude = longitude;
			
			for(var i=0; i < resultsArray.length; i++){
				obj = resultsArray[i];
				var keyField = obj.DBKeyField;
				var table = obj.DBTable;
				var keyValue = obj[keyField];
				this.requestSelectedObject(keyValue);
			}
		}
	} 
	else if (point) {
    }
}

//Find objects in array that match lat and long
//objectArray : array to search
//latitude : search latitude
//longitude : searcg longitude
//return : results array
TaMap.prototype.findObjectsForLatLong = function(objectArray, latitude, longitude){
	 var resultArray = new Array();
	 if( ! objectArray){
	 	alert("No objects");
		return null;
	 } 
	 
	 for(var i=0; i < objectArray.length; i++){
	 	obj = objectArray[i];
		if(obj.Latitude == latitude && obj.Longitude == longitude){
			resultArray.push(obj);
		}
	 }
	 
	 return  resultArray;
}

//Function to request information for a specified object's details
//keyValue : key of required record
TaMap.prototype.requestSelectedObject = function(keyValue){
	//alert('KEY ' + keyValue);	
	var callBackFunc = this.selectedObjectCallbackFunc;
	var errorFunc = taReportError;
	var thisInstance = this;
	myParams = 'Service=FetchSelectedServerObjectHTMLFormatted&ParamFile=' + this.mapXMLFile + '&Key=' + keyValue; 
	var net = new NetCommunicator (this.appUrl);
	net.sendRequest(myParams, callBackFunc, errorFunc, thisInstance); 
	net = null;

}	

//Function called back with specified object's details
//dataIn : server data
TaMap.prototype.selectedObjectCallbackFunc = function(dataIn){

	this.console.clearConsole();
	
	//Extract status info
	var dataObj = new Object;
	dataObj.data = dataIn;
	var statusObj = this.dataManager.isolateHTMLContent(dataObj);
	dataIn = dataObj.data;
	if(statusObj.responseCode > 0){
		taReportError(statusObj.message);
		return;
	}	
	
	//Add html object to selectedObjectHtmlArray
	var obj = new Object;
	this.selectedObjectHtmlArray[this.selectedObjectHtmlArray.length] = obj;
	obj.html = dataIn;
	obj.sortValue = statusObj.sortValue;
	
	//Sort table of HTML objects by sort value
	this.selectedObjectHtmlArray.sort(taSortFunc);
	
	//Display all HTML objects
	for(var i = 0; i < this.selectedObjectHtmlArray.length; i++){
		this.console.toConsoleHtml(this.selectedObjectHtmlArray[i].html);
		
		if(this.traceOn){
			var text = taReplaceSpecialChars(this.selectedObjectHtmlArray[i].html);
			text = text.replace( /\n/g, '<br>' );
			this.trace.output(text);
		}			
	}	
	
	this.outputObjectArray();
}




//--------------------------------------------------------------------

//TaDataManager class

//Class Constructor
function TaDataManager(map){
	//this.objectArray = null;
	this.map = map;
}

//Function to extract status object from server data and set dataIn to just HTML content
//dataIn : server data object to be updated
//return : status object
TaDataManager.prototype.isolateHTMLContent = function(dataObj){
	var statusObj = new TaResponseStatus();
	dataIn = dataObj.data;
	dataIn = statusObj.extractStatusInformation(dataIn);
	dataObj.data = dataIn;
	if(statusObj.responseCode > 0){
		return statusObj;
	}
	return statusObj;
}

//Function to process server data and extract initialization information
//dataIn : server data
//dataObj : data object updated to hold initialization properties
//return : status object
TaDataManager.prototype.processInitializationData = function(dataIn, dataObj){
	var statusObj = new TaResponseStatus();
	dataIn = statusObj.extractStatusInformation(dataIn);
	if(statusObj.responseCode > 0){
		return statusObj;
	}
	
	var objectArray =  this.getObjectArrayFromData(dataIn);
	if(objectArray && objectArray[0]){
		for(var property in objectArray[0]){
			var value = objectArray[0][property];
			if(typeof(value) == "function"){
				continue;
			}
			dataObj[property] = value;
		}	
		
		dataObj = objectArray[0];
	}
	else{
		statusObj.responseCode = 1;
		statusObj.message = "Initialization data not found";
	}	
	return statusObj;
}

//Function to create a map icon
//siteUrl : site URL
//iconPath : path from site URL to images
//iconName : image filename
//sizeStr : size as string e.g. 12,16 (width height)
//anchorStr : ancjor as string e.g. 12,0 (start top left hand corner
//return : icon : 
TaDataManager.prototype.createIcon= function(siteUrl, iconPath, iconName, sizeStr, anchorStr) {		
		var width = null;
		var height = null;
		var widthHeightArray = null;
		
		icon = new GIcon();
		icon.image = siteUrl + iconPath + iconName;
		widthHeightArray = sizeStr.split(",");
		width = widthHeightArray[0];
		height = widthHeightArray[1];
		width.trim;
		height.trim;
		icon.iconSize = new GSize(width, height);
		
		//Anchor measured from top left tip of image
		widthHeightArray = anchorStr.split(",");
		width = widthHeightArray[0];
		height = widthHeightArray[1];
		width.trim;
		height.trim;
		icon.iconAnchor = new GPoint(width, height);	
		
		return icon;
}


//Function that extracts status info and a new object array from the server data
//dataIn : server data
//return : stasus object
TaDataManager.prototype.refreshObjectArrayFromData = function(dataIn){
	var statusObj = new TaResponseStatus();
	dataIn = statusObj.extractStatusInformation(dataIn);
	if(statusObj.responseCode > 0){
		return statusObj;
	}
	objectArray =  this.getObjectArrayFromData(dataIn);
	this.map.objectArray = objectArray;
	return statusObj;
}

//Function to process server data into an object array
//dataIn : server data
//return: object array
TaDataManager.prototype.getObjectArrayFromData = function(dataIn){
	var objectArray = new Array();
	var currentObject = null;
	
	var frag = document.createDocumentFragment();
	var rootElement = document.createElement("div");
	frag.appendChild(rootElement);
	rootElement.innerHTML = dataIn;
	this.parseServerData(rootElement, currentObject, objectArray);		
	return objectArray;
}

//recursive function to parse server data
//node : current node
//currentObj : current object
//objectArray : object array to update
TaDataManager.prototype.parseServerData = function(node, currentObj, objectArray){
 	for(var i=0; i < node.childNodes.length; i++){
		if(node.childNodes[i].nodeType == "1"){
			nodeClass = node.childNodes[i].className;
			if(node.childNodes[i].firstChild && node.childNodes[i].firstChild.nodeType == "3"){
				nodeValue = node.childNodes[i].firstChild.nodeValue;
			}
			else{
				nodeValue = undefined;
			}	
			if(nodeClass == 'ServerObject'){
				currentObj = new Object;
				objectArray.push(currentObj);
			}
			else if( currentObj){
				currentObj[nodeClass] = nodeValue;
			}
			else{
				alert("Error in parseServerData : No current server object");
				return;
			}
		}	
		if(node.childNodes[i].childNodes.length > 0){
   			this.parseServerData(node.childNodes[i], currentObj, objectArray);
   		}	
	}
 } 

//Function to format all objects in array for priniting
//objectArray : array of objects
//return : array of lines
TaDataManager.prototype.printFormatServerData = function(objectArray){
	var lineArray = new Array();
 	
	for(var i=0; i < objectArray.length; i++){
		line = '';
		obj = objectArray[i];
		for(var property in obj){
			var value = obj[property];
			if(typeof(value) == "function"){
				continue;
			}
			line += property  + ' = '+ value + " | ";
		}	
		lineArray[i] = line;
	}
	return lineArray;
}

//--------------------------------------------------------------------

//TaResponseStatus Class

//Constructor for status class
function TaResponseStatus (){
	this.responseCode = null;
	this.message = null;
	this.sortValue = null;
	
}	

//Function that sets status values and returns server data less status information
//dataIn : server data
//return : server data less status data
TaResponseStatus.prototype.extractStatusInformation = function(dataIn){
	var endIndex = dataIn.indexOf('</fwStatus>');
	if(endIndex < 1){
		this.responseCode = 999;
		this.message = 'Error: No response status information. Data Returned: ' + dataIn
		 return;
	}
	
	var statusData = dataIn.substring(0, endIndex);
	var appData = dataIn.substring(endIndex + 11);
	
	endIndex = statusData.indexOf('>');
	statusData = statusData.substring(endIndex + 1);
	
	this.responseCode = this.extractValue(statusData, 'ResponseCode');
	this.message = this.extractValue(statusData, 'Message');
	this.sortValue = this.extractValue(statusData, 'SortValue');
	return appData;
}

//Function to extract individual tag value from statys data
//statusData : status data
//tagName : tag name
//return : tag value
TaResponseStatus.prototype.extractValue = function (statusData, tagName){
	var tag = '</' + tagName + '>';
	var endIndex = statusData.indexOf(tag);
	statusData = statusData.substring(0, endIndex);
	
	tag = '<' + tagName + '>';
	endIndex = statusData.indexOf(tag);
	statusData = statusData.substring(endIndex + tag.length );
	return statusData;
}

//--------------------------------------------------------------------

// TaConsole class

//Class constructor for console 
//consoleID : ID of console div
function TaConsole (consoleID){
	this.console = document.getElementById(consoleID);
}

//Output html to console
//html : html to display
TaConsole.prototype.toConsoleHtml = function(html){
 
	if(this.console != null){
		var newLine = document.createElement("div");
		newLine.innerHTML = html;
		var br = document.createElement("br");
		newLine.appendChild(br);
		this.console.appendChild(newLine);
	}
 }
 
 //Function to clear console
 TaConsole.prototype.clearConsole = function(){
 	if(this.console){
		this.console.innerHTML = " ";
	}
 }

 //--------------------------------------------------------------------
 
 //TaTrace class

//Constructor for trace area
//traceID : ID of trace Div
//clearTraceID :  ID of clear trace button
function TaTrace (traceID, clearTraceID){
	this.trace = document.getElementById(traceID);
	this.clearTraceID = clearTraceID;
}

//Function to output text to trace
//text : text to add to trace
TaTrace.prototype.output = function(text){
	if(this.trace){
		this.trace.style.visibility = 'visible';
		if(document.getElementById(this.clearTraceID)){
			document.getElementById(this.clearTraceID).style.visibility = 'visible';
		}	
		var newLine = document.createElement("div");
		newLine.innerHTML = text;
		var br = document.createElement("br");
		newLine.appendChild(br);
		var br = document.createElement("br");
		newLine.appendChild(br);		
		this.trace.appendChild(newLine);	
	}
}	

//Function to clear trace
TaTrace.prototype.clearTrace = function(){
	if(this.trace){
		this.trace.innerHTML = " ";
	}
 }

 //--------------------------------------------------------------------
 
 //TaStatus class
 
 //Constructor for status bar object
 //statusID : ID of status div
 function TaStatus (statusID){
	this.status = document.getElementById(statusID);
}

//Function to output status data
//text : daat to output
TaStatus.prototype.output = function(text){
	if(this.status){
		this.status.style.visibility = 'visible';
		var newLine = document.createElement("div");
		newLine.innerHTML = text;
		this.status.appendChild(newLine);
	}
}	

//Function to clear status area
TaStatus.prototype.clearStatus = function(){
 	if(this.status){
		this.status.innerHTML = " ";
	}
 }

//--------------------------------------------------------------------

//General Functions

//Function to report error
//message : error message
function taReportError(message){
	alert("Error: " + message);	
}	

//Function to help sort by comparing two values
//a : value to compare
//b : value to compare 
function taSortFunc(a,b){
	if(a.sortValue < b.sortValue ){
		return -1;
	}
	return 0;
}

//Function to clear an HTML element
//id : ID of element
function clearControl(id){
	if(document.getElementById(id)){
		document.getElementById(id).innerHTML ='';
	}	
}	

//Function to replace certain XML/HTML chars with their display code
//text : text to process
//return : text with chars replaced
function taReplaceSpecialChars(text){
	text = text.replace(/</g,'&lt;'); 
	text = text.replace(/>/g,'&gt;'); 
	return text;
}

//--------------------------------------------------------------------

