var SERVICE_MANAGER_INSTANCE = 0;

function ServiceManager(EventManager, ServiceMap) {
	var ServiceFormParent = null;
	var ServiceChildren = new Array();
	
	var activeServices = new Array();
	var knownServices = new Array();

	var ServiceManagerId = 'ServiceManager'+SERVICE_MANAGER_INSTANCE;
	SERVICE_MANAGER_INSTANCE++;

	this.addService = function(servXMLobj) {
		var title = servXMLobj.getAttribute('title');
		activeServices[title] = servXMLobj;
	}

	this.removeService = function(servTitle) {
		if(activeServices[servTitle]) {
			delete activeServices[servTitle];
		}
	}

	/* Create a hash of known services */

	this.onloadMapbook = function(mapbookXML) {
		var services  = mapbookXML.getElementsByTagName('service');
		for(var s = 0; s < services.length; s++) {
			var title = services[s].getAttribute('title');
			knownServices[title] = services[s];
		}
	}
	/* set the spawn parent function to do something other than this default 
	 * for specific interfaces
	 */
	this.spawnParent = function(title) {
		var div = document.createElement('div');
		div.id = 'serviceForm-'+title;
		document.getElementById(ServiceFormParent).appendChild(div);
		return div;
	}

	/* set if a parent from a custom spawn function needs to be removed
	*/
	this.clearParent = function(title) {
		return false;
	}

	var MySelf = this;

	function renderServiceForm(serviceXMLObj) {
		var serviceTitles = new Array();

		if(serviceXMLObj.getAttribute('type') == 'multiform') {
			var services = serviceXMLObj.getElementsByTagName('subform');
			for(var i = 0; i < services.length; i++) {
				serviceTitles.push(services[i].getAttribute('title'));
			}
		} else {
			serviceTitles.push(serviceXMLObj.getAttribute('title'));
			knownServices[serviceXMLObj.getAttribute('title')] = serviceXMLObj;
		}
		document.getElementById(ServiceFormParent).innerHTML = '';
		for(var i = 0; i < serviceTitles.length; i++) {
			var servTitle = serviceTitles[i];
			var serviceForm = new ServiceForm(EventManager, knownServices[servTitle], ServiceMap);
			var formParent = MySelf.spawnParent(servTitle);
			if(formParent) {
				ServiceChildren[servTitle] = serviceForm;
				serviceForm.setParent(formParent.getAttribute('id'));
			} else {
				alert('Service Form Parent not set! Unable to render service object!');
			}
		}
		serviceXMLObj = null;
	}

	this.serviceForm = function(serviceXMLObj) {
		var servTitle = serviceXMLObj.getAttribute('title');
//		if(serviceXMLObj.getAttribute('type') && serviceXMLObj.getAttribute('type').match(/inspect/i)) {
		if(serviceXMLObj.getAttribute('shape') && !serviceXMLObj.getAttribute('shape').match(/none/i)) {
			var mapBook = serviceXMLObj;
			while(mapBook.parentNode) {
				mapBook = mapBook.parentNode;
			}
/*
			var specificType = serviceXMLObj.getAttribute('type').split('-');
			if(!specificType[1]) {
				specificType[1] = 'default';
			}*/
			if(ServiceFormParent) {
				var shape = new String(serviceXMLObj.getAttribute('shape')).toLowerCase();
				if(!shape || shape == 'null') { shape = 'point'; }
				document.getElementById(ServiceFormParent).innerHTML = '<b>'+SHAPE_MESSAGES[shape]+'</b>';
			}
			EventManager.addEventListener('changetool','ServInspect', function () {
				EventManager.removeEventListener('changetool','ServInspect');
				EventManager.removeEventListener('finishdrawing', 'ServInspect');

			});
			EventManager.addEventListener('finishdrawing','ServInspect', function (p) {
					document.getElementById(ServiceFormParent).innerHTML = '';
					EventManager.triggerEvent('changetab', servTitle.toUpperCase());

					var serviceXML = mapBook.createElement('service');
					//serviceXML.setAttribute('title', serviceXMLObj.getAttribute('title'));

					var shape = serviceXMLObj.getAttribute('shape');

					var url = mapBook.createElement('url');
					url.appendChild(mapBook.createTextNode(serviceXMLObj.getElementsByTagName('url')[0].firstChild.nodeValue));
					serviceXML.appendChild(url);

					var inputs = serviceXMLObj.getElementsByTagName('input');
					var copyAttributes = ['name','title','value','delim','display','return','selectable','shape','target','validate','div','checked'];

					for(var i = 0; i < copyAttributes.length; i++) {
						var v = serviceXMLObj.getAttribute(copyAttributes[i]);
						if(v) {
							serviceXML.setAttribute(copyAttributes[i], v);
						}
					}
					if(shape=='box') {
						shape = 'poly';
					}
			

					var latLong = new Point();
					if(window.toLatLong) {
						var sysArr = (new String(MAP_COORDINATE_SYSTEM)).split('-');
						var unitConversion = new Point(p[0].x, p[0].y);
						var llPoint = window.toLatLong(sysArr[1], unitConversion);
						latLong = llPoint;
					}



					for(var i = 0; i < inputs.length; i++) {
						var newInput = mapBook.createElement('input');
						var inputType = new String(inputs[i].getAttribute('type')).toLowerCase();
						for(var attr = 0; attr < copyAttributes.length; attr++) {
							newInput.setAttribute(copyAttributes[attr], new String(inputs[i].getAttribute(copyAttributes[attr])));
						}
						if(inputType == 'point') {
							var delim = inputs[i].getAttribute('delim');
							if(!delim) { delim = ','; }
							var pValue = p[0].toString(delim);
							newInput.setAttribute('type','hidden');
							newInput.setAttribute('value', pValue);
						} else if(inputType.match(/point.x/)) {
							newInput.setAttribute('type','hidden');
							newInput.setAttribute('value', p[0].x);
						} else if(inputType.match(/point.y/)) {
							newInput.setAttribute('type','hidden');
							newInput.setAttribute('value', p[0].y);
						} else if(inputType.match(/point.lat/)) {
							newInput.setAttribute('type','hidden');
							newInput.setAttribute('value', latLong.y);
						} else if(inputType.match(/point.long/)) {
							newInput.setAttribute('type','hidden');
							newInput.setAttribute('value', latLong.x);
						} else if(inputType.match(/multipoint/)) {
							var delim = inputs[i].getAttribute('delim');
							var pairDelim = inputs[i].getAttribute('pointdelim');
							if(!delim) { delim = ','; }
							if(!pairDelim) { pairDelim = ' '; }
							var value = '';
//							var shape = serviceXMLObj.getAttribute('shape');
							if(shape && (shape.match(/poly/i)  || shape.match(/measurearea/i))) {
								p[p.length] = p[0];
							}
							for(var pi = 0; pi < p.length; pi++) {
								var pValue = p[pi].toString(delim);
								value = value+pairDelim+pValue;
							}
							value = value.substring(1);
							newInput.setAttribute('type','hidden');
							newInput.setAttribute('value', value);
						} else if(inputType.match(/multipoint.x/)) {
							var delim = inputs[i].getAttribute('delim');
							if(!delim) { delim = ','; }
							var value = '';
							p[p.length] = p[0];
							for(var pi = 0; pi < p.length; pi++) {
								var pValue = p[pi].x;
								value = value+delim+pValue;
							}
							value = value.substring(1);
							newInput.setAttribute('type','hidden');
							newInput.setAttribute('value', value);
						} else if(inputType.match(/multipoint.y/)) {
							var delim = inputs[i].getAttribute('delim');
							if(!delim) { delim = ','; }
							var value = '';
							p[p.length] = p[0];
							for(var pi = 0; pi < p.length; pi++) {
								var pValue = p[pi].y;
								value = value+delim+pValue;
							}
							value = value.substring(1);
							newInput.setAttribute('type','hidden');
							newInput.setAttribute('value', value);
						} else if(inputType.match(/select$/i)) {
							newInput.setAttribute('type', 'select');
							var options = inputs[i].getElementsByTagName('option');
							for(var o = 0; o < options.length; o++) {
								var opt = mapBook.createElement('option');
								newInput.appendChild(opt);
								opt.setAttribute('value', options[o].getAttribute('value'));
								opt.appendChild(mapBook.createTextNode(options[o].firstChild.nodeValue));
								
							}
						} else if(inputType.match(/today/i) || inputType.match(/date/i)) {
							var formatString = inputs[i].getAttribute('format');
							if(!formatString) {
								formatString = '%M/%D/%Y';
							}
							var offset = inputs[i].getAttribute('offset');
							if(offset) {
								offset = parseInt(offset) * 86400000;
							} else {
								offset = 0;
							}
							var d = new Date();
							var dateString = inputs[i].getAttribute('date');
							if(dateString) {
								d = new Date(dateString);
							}

							newInput.setAttribute('type','hidden');
							newInput.setAttribute('value',strfdate(new Date(d.getTime() + offset), formatString));
						} else {
							newInput.setAttribute('type', inputs[i].getAttribute('type'));
						}
						serviceXML.appendChild(newInput);
					}
					//serviceXML.setAttribute('type', 'default');
					//serviceXML.setAttribute('type', specificType[1]);
					//EventManager.removeEventListener('changetool','ServInspect');
					//EventManager.removeEventListener('finishdrawing', 'ServInspect');
					renderServiceForm(serviceXML);
					serviceXML = null;
					ServiceMap.clearDrawingArea();
			});
			//ServiceMap.pointDrawTool();
			//ServiceMap.loadDrawTool('measurearea', true);
			if(!shape || shape == 'null') {
				shape = 'poly';
			}
			ServiceMap.loadDrawTool(shape, true);
			if(serviceXMLObj.getAttribute('cursor')) {
				ServiceMap.setMapCursor(serviceXMLObj.getAttribute('cursor'));
			}
			return false;
		}
		renderServiceForm(serviceXMLObj);

	}

	this.clearServiceForm = function(serviceXMLObj) {
		var servTitle = serviceXMLObj.getAttribute('title');
		if(ServiceChildren[servTitle]) {
			ServiceChildren[servTitle].clearForm();
		}
		MySelf.clearParent(serviceXMLObj);
	}

	this.setParent = function(p) {
		ServiceFormParent = p;
	}

	this.serviceCount = function() {
		var i = 0;
		for(var l in activeServices) {
			i++;
		}
		alert(i+' active services.');
	}

	this.startupService = function(title) {
		var serviceXML = knownServices[title];

		var inputs = serviceXML.getElementsByTagName('input');
		var cgi = new CGI();
		var url = serviceXML.getElementsByTagName('url')[0].firstChild.nodeValue;
		url = url + '?';
		for(var i = 0; i < inputs.length; i++) {
			var iType = inputs[i].getAttribute('type');
			var iName = inputs[i].getAttribute('name');
			if(iType.match(/user/i)) {
				inputs[i].setAttribute('value', cgi.param(iName));
			}
		}
		EventManager.triggerEvent('callservice', serviceXML);
	}


	var resultsContainerId = '';
	this.setResultsContainerId = function (rid) {
		resultsContainerId = rid;
	}

	this.startService = function(title) {
		EventManager.triggerEvent('serviceform', knownServices[title]);
	}

	this.callService = function(serviceXMLObj) {

		if(SERVICE_WAITING_DIV) {
			var msg = document.getElementById(SERVICE_WAITING_DIV);
			if(msg) {
				document.getElementById(ServiceFormParent).innerHTML = msg.innerHTML;
			}
		}

		var url = ProcessURL(ServiceMap,serviceXMLObj);
		logDebugMessage('Service Call', false, url);

		var serviceType = new String(serviceXMLObj.getAttribute('type'));
		var returnType = serviceXMLObj.getAttribute('return');
		var displayType = serviceXMLObj.getAttribute('display');

		var postRequired = serviceType.match(/xmlpost/);

		if(!returnType || returnType == 'null') { returnType = 'xml'; }
		if(!displayType || displayType == 'null') { displayType = 'div'; }

		if(displayType.match(/window/i)) {
			/* Fabricate a return event and open the window */
			var elm = document.createElement('return');
			elm.setAttribute('display','window');
			elm.setAttribute('title', serviceXMLObj.getAttribute('title'));
			var winElm = document.createElement('window');
			var winTarget = serviceXMLObj.getAttribute('target');
			winElm.setAttribute('target', winTarget);
			winElm.appendChild(document.createTextNode(url));
			elm.appendChild(winElm);
			EventManager.triggerEvent('servicereturn', elm);
			//EventManager.triggerEvent('lasttab','');
			winElm = null
			elm = null;

			if(winTarget) {
				window.open(url, winTarget);
			} else {
				window.open(url);
			}
			EventManager.triggerEvent('lasttab','');
		} else {
			var http = getHTTPObject();
			var method = 'GET';
			var postInfo = null;
			if(url.length > 1000 || postRequired) {
				method = 'POST';
				var urlArr = url.split('?');
				url = urlArr[0];
				postInfo = urlArr[1];
			}
			if(postRequired) {
				var xmlDoc = new xmlDocument();
				var inputs = serviceXMLObj.getElementsByTagName('input');
				for(var i = 0; i < inputs.length; i++) {
					var inputType = new String(inputs[i].getAttribute('type'));
					var root = xmlDoc.cleanPath(inputs[i].getAttribute('name'));
					if(inputType.match(/layerslist/)) {
						var layers = ServiceMap.getLayersByZIndex();	
						var urls = ServiceMap.getLayerURLs();
						var preprocessed = !(new String(inputs[i].getAttribute('processed')).match(/false/));
						for(var l = 0; l < layers.length; l++) {
							if(layers[l] != 'NAVIGATION') {	/* Exclude the navigation layer, which is just a blank image. */
								var mapRoot = root+'/map['+l+']/';
								xmlDoc.buildPath(mapRoot+'@title', layers[l]);
								xmlDoc.buildPath(mapRoot+'@zindex', l+1);
								xmlDoc.buildPath(mapRoot+'@opacity', Map.getLayerOpacity(layers[l]));
								if(preprocessed) {
									xmlDoc.buildPath(mapRoot+'file[0]', ServiceMap.preprocessURL('image',layers[l]));
									xmlDoc.buildPath(mapRoot+'legend[0]', ServiceMap.preprocessURL('legend',layers[l]));
								} else {
									xmlDoc.buildPath(mapRoot+'file[0]', urls[layers[l]]);
									var params = ServiceMap.getLayerParameters(layers[l]);
									var p = 0;
									for(var pName in params) {
										xmlDoc.buildPath(mapRoot+'param['+p+']/@name', pName);
										xmlDoc.buildPath(mapRoot+'param['+p+']/@value', params[pName]);
										p++;
									}
								}
							}
						}
					} else if(inputType.match(/popups/)) {
						var popupRoot = root+'/popups[0]/';
						var popups = ServiceMap.getVisiblePopupIds();
						for(var p = 0; p < popups.length; p++) {
							var popup = document.getElementById(popups[p]);
							var popupTitle = ServiceMap.getPopupTitle(popups[p]);
							var contents = document.getElementById(popups[p]+'-Contents');
							var title = document.getElementById(popups[p]+'-Title');
							var map = document.getElementById(ServiceMap.getParent());
							var mapXY = objectClientPosition(map);
							var popupXY = objectClientPosition(popup);

							var popupEntry = popupRoot+'popup['+p+']';
							var gXY = ServiceMap.pointToGroundUnits(new Point(popupXY.x-mapXY.x, popupXY.y-mapXY.y+40));
							var gmaxXY = ServiceMap.pointToGroundUnits(new Point(popup.offsetLeft+popup.offsetWidth, popup.offsetTop+popup.offsetHeight));
							/*xmlDoc.buildPath(popupEntry, contents.innerHTML);*/
							var contentsString = '';
							var waitingForValue = 0;
							var xx = 0;
							for(var node = 0; node < contents.childNodes.length; node++) {
								var n = contents.childNodes[node];
								if(n.className) { /* Ignore the node if it does not have a classname */
									if(n.className == 'itemTitle') {
										contentsString += n.innerHTML;
									} else if(n.className == 'itemValue') {
										contentsString += n.innerHTML + '\n';
									}
									waitingForValue++;
								}
								
								xx++;
							}
							xmlDoc.buildPath(popupEntry, contentsString);
							xmlDoc.buildPath(popupEntry+'/@title', popupTitle);
							xmlDoc.buildPath(popupEntry+'/@x', gXY.x);
							xmlDoc.buildPath(popupEntry+'/@y', gXY.y);
							xmlDoc.buildPath(popupEntry+'/@maxx', gmaxXY.x);
							xmlDoc.buildPath(popupEntry+'/@maxy', gmaxXY.y);
							xmlDoc.buildPath(popupEntry+'/@contentscolor', contents.style.backgroundColor);
							xmlDoc.buildPath(popupEntry+'/@titlecolor', title.style.backgroundColor);
						}
					} else {
						xmlDoc.buildPath(root,inputs[i].getAttribute('value'));
					}
				}
				postInfo = xmlDoc.getXMLText();

			}
			http.open(method, url, true);
			if(method == 'POST' && !serviceType.match(/xmlpost/)) {
				http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");	
			} else if (serviceType.match(/xmlpost/)) {
				http.setRequestHeader("Content-type", "text/xml");	
			}

			http.onreadystatechange = function () { 
				if(http.readyState == 4) {
					var results = null;
					var contentType = http.getResponseHeader('Content-Type');
					if(returnType.match(/html/i) || contentType.match(/html/i)) { // HTML Processing
						var htmlSrc = http.responseText;
						
						/* Allow HTML Return Documents To Perform Mapbook Controls */
						/* If it fails "nevermind" and move on with life... */
						try {
							var xmlObj = new xmlDocument();
							xmlObj.createXMLFromString(http.responseText);
							var xmlDoc = xmlObj.getDocument();
							if(xmlDoc) {
								var mapbookFragment = getElementsByTagNameNS(xmlDoc, MAPBOOK_NAMESPACE_URI, MAPBOOK_NAMESPACE_PREFIX, 'mapbook');
								var mbXML = new xmlDocument();
								mbXML.setRoot(mapbookFragment[0]);
								mbXML.createXMLFromString(mbXML.stripNamespace(MAPBOOK_NAMESPACE_PREFIX));
								var mbDoc = mbXML.getDocument();
								loadDefaultsFromMapBook(mbDoc, mbDoc, EventManager, ServiceMap, true);
								var body = xmlDoc.getElementsByTagName('body')[0];
								if(body.childNodes[0].nodeName == '#cdata-section') {
									htmlSrc = xmlDoc.getElementsByTagName('body')[0].childNodes[0].data;
								} else {
									htmlSrc = xmlObj.getXMLText();
								}
							} else {
								htmlSrc = xmlObj.getXMLText();
							}
						} catch(e) {
						//	alert('Could not process HTML return.\n'+e.message);	
						}


						/* Trigger the artificial return in order to make all of the status clocks disappear */
						var elm = document.createElement('return');
						elm.setAttribute('display','div');
						elm.setAttribute('title', serviceXMLObj.getAttribute('title'));
						EventManager.triggerEvent('servicereturn', elm);

						/* Display the results, should have the NS specific stuff stripped */
						document.getElementById(resultsContainerId).innerHTML = htmlSrc;
						EventManager.triggerEvent('changetab', TABS_RESULTS_NAME);
					} else if(returnType.match(/text/i) || contentType.match(/plain/i)){ // Plain Text Return
						var results = document.getElementById('content_results_form');
						var text = http.responseText;
						if(!(text.match(/\<html/))) {
							text = text.replace(/\n/g,'<br/>\n');
							text = '<tt>'+text+'</tt>';
						}
						results.innerHTML = text;
						EventManager.triggerEvent('changetab',TABS_RESULTS_NAME);
					} else if(returnType.match(/csv/i) || contentType.match(/csv/i)) { // CSV return type
						var results = document.getElementById(resultsContainerId);
						results.innerHTML = '';
						var text = http.responseText;
						var arr = ParseCSV(text);
						var table = document.createElement('table');
						results.appendChild(table);
						var p = document.createElement('tbody');
						table.appendChild(p);
						var headerRow = document.createElement('tr');
						p.appendChild(headerRow);

						for(var col = 0; col < arr[0].length; col++) {
							var th = document.createElement('th');
							headerRow.appendChild(th);
							th.appendChild(document.createTextNode(arr[0][col]));
							th.innerHTML = th.innerHTML+'&nbsp;';
							th = null;
						}
						headerRow = null;

						for(var row = 1; row < arr.length-1; row++) {
							var tr = document.createElement('tr');
							p.appendChild(tr);
							for(var col = 0; col < arr[0].length; col++) {
								var td = document.createElement('td');
								tr.appendChild(td);
								td.appendChild(document.createTextNode(arr[row][col]));
								td.innerHTML = td.innerHTML+'&nbsp;';
								td = null;
							}
							tr = null;
						}

						EventManager.triggerEvent('changetab',TABS_RESULTS_NAME);
						results = null;
						table = null;
						p = null;

					} else { // XML Return Type
						var returnXML = http.responseXML;
						var servTitle = serviceXMLObj.getAttribute('title');

						if(http.responseXML) {
							document.getElementById(resultsContainerId).innerHTML = '';
							processXMLWithXSLT(http.responseXML, XSL_RESULTS, resultsContainerId);

							results = http.responseXML.getElementsByTagName('return')[0];
							if(!results) {
								results = http.responseXML.getElementsByTagName('results')[0];
							}

							var windowsToOpen = http.responseXML.getElementsByTagName('window');
							for(var i = 0; i < windowsToOpen.length; i++) {
								var url = windowsToOpen[i].firstChild.nodeValue;
								if(url) {
									var target = windowsToOpen[i].getAttribute('target');
									if(target && target != 'null' && target != 'blank') {
										window.open(url, target);
									} else {
										window.open(url);
									}
								}
							}

							var maps = http.responseXML.getElementsByTagName('map');


							loadDefaultsFromMapBook(http.responseXML, null, EventManager, ServiceMap);
							for(var m = 0; m < maps.length; m++) {
								EventManager.triggerEvent('refreshlayer',maps[m].getAttribute('title'));
							}
						} else {
							alert('The service "'+servTitle+'" did not return XML!');
						}
						results.setAttribute('title', serviceXMLObj.getAttribute('title'));
						if(serviceXMLObj.getAttribute('display')) {
							results.setAttribute('display', serviceXMLObj.getAttribute('display'));
						}

						/* Determine whether there were errrors or rows to display */
						var rows = returnXML.getElementsByTagName('row');
						var errors = returnXML.getElementsByTagName('error');
						var showTest = rows.length + errors.length;

						if(showTest > 0) {
							EventManager.triggerEvent('changetab',TABS_RESULTS_NAME);
						} else if(serviceXMLObj.getAttribute('display') != 'none'){
							EventManager.triggerEvent('lasttab','');
						}

						EventManager.triggerEvent('servicereturn', results);
					}
				}
			};
			http.send(postInfo);
		}
	}

	this.initializeEvents = function() {
		EventManager.addEventListener('addservice', ServiceManagerId, MySelf.addService);
		EventManager.addEventListener('removeservice', ServiceManagerId, MySelf.removeService);
		EventManager.addEventListener('callservice', ServiceManagerId, [MySelf.clearServiceForm, MySelf.callService]);
		EventManager.addEventListener('cancelservice', ServiceManagerId, MySelf.clearServiceForm);
	}



}
