/* 
 * Written by Chris Schroeder 6/22/2007
 * Copyright 2007 Johns Hopkins University. All rights reserved.
 * 
 * This is our group of Ajax functions.
 * 
 * Edited and expanded on 7/21/2007 CS
 */

/* vars initialized */

/* the map */
    var map = null; //Google API object

/* the Google geocoder */
    var geocoder = null; //Google API object

/* 
 * all the points on the map stored in an array.
 * 
 * this way, we can easily - and quickly - clear the map. 
 */
	var mapPoints= []; //array of points plotted with marker data
	
/* counter */
	counter = null; //counts points

/* bubble content info is stored in this */	
	var textMessage = null;
	
/* 
 * this tells our functions whether a 
 * point has been plotted yet or not. 
 * right now, we're not using it at all.
 */
	var pointPlotted = false;

/*
 * These are the current latitude and longitude for each point.
 * We re-use this set for each point instance.
 */
	var currLatitude = null;
	var currLongitude = null;
	
/* the countries array */
	var countriesList = []; //Array of Category JSON data
	var country_code = null;
	var project_id = null;

/* 
 * the AJAX includes.
 * 
 * These are initialized here and 
 * set in the "setURLs(pages)" function 
 */
	var countryInclude = null;//for detailed info about a country
	var projectInclude = null;//for detailed info about a project
	var facultyInclude = null;//shows detail about faculty members
	var center_id = null;
	var countryZoom = 1;
	var smallContinentZoom = 1;
	var largeContinentZoom = 1;
	var only_jhsph = 'yes';
	
/* this is the AJAX request. 
 * We can move this to a common lib soon.
 */
function createRequest() {
	var request = null;
	try {
		request = new XMLHttpRequest();
	} catch (trymicrosoft) {
		try {
			request = new ActiveXObject("Msxml2.XMLHTTP");
		} catch (othermicrosoft) {
			try {
				request = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (failed) {
				request = null;
			}
		}
	}
	if (request == null) {
		alert ("Error creating request object");
	} else {
		return request;
	}
}


/*
 * We kick off each new app with this function
 * to declare all includes we intend to use.
 */
	function setCFVars(pages) {
		if(pages) {
			for (key in pages) {
				eval(key+"='"+pages[key]+"'");
			}
		}
	}
	
	function setZoom(thisZoom) {
		if(thisZoom) {
			zoom = thisZoom;
		} else {
			zoom = 4;
			alert("We guessed at the zoom level");
		}
		return zoom;
	}

/* 
 * Here's where we use AJAX
 * to send requests our JSon component.
 * 
 * We can give it a country ID
 * or it will return each country
 * in a packet.
 * 
 * The query can have as many vars
 * as we need - in JSon format.
 */
	function startRequest(url,query) {
		var myURL = null;
		urlQuery = "?";
		if(query) {
			for (key in query) {
				if(key) {
					myName = key;
					myValue = query[key];
					urlQuery += myName + "=" + myValue + "&";
				}
			}
		}
		if(!url) {
			url = "";
			alert("we've lost our URL somewhere");
			exit;
		}
		myURL = url + urlQuery;
		JSONRequest = createRequest();
		JSONRequest.open("GET", myURL, true);
		JSONRequest.onreadystatechange = putOnPage;
		JSONRequest.send(null);
  	}

/*
 * This function allows us to use checkboxes
 * to add or remove points by country.
 * 
 * To see it in use, visit http://commprojects.jhsph.edu/urbanhealth/
 */
	function checkFunction (url,country_code,formField) {
		if(formField.checked == true) {
			startRequest(url,{'country_code':country_code,'center_id':center_id,'only_jhsph':only_jhsph});
/*			alert("checked = " + formField.checked); */
		} else {
			unplotPoints(country_code); 
/*			alert("checked = " + formField.checked); */
		}
	}


/*
 * Here is where we deconstruct 
 * the JSon data. We assign values 
 * to each of our javascript vars.
 * 
 * Two loops here. One through the
 * countries and one through the 
 * cities for each country...
 */
	function putOnPage() {
		if(JSONRequest.readyState == 4) { 



/* 
 * m is the internal counter, 
 * counter is the global counter
 * 
 * on function start, 
 * counter sets m's value
 * 
 * on document load,
 * counter is null 
 */
			m = 0;//function counter
			if(counter!=null) {
				m = m + counter;
			} else {
				counter = 0;
			}
			var myCountries = eval("(" + JSONRequest.responseText + ")");
			for(i=0; i <= myCountries.countries.length; i++) {
				if(myCountries.countries[i]) {
					countriesList.push(myCountries.countries[i]);
					for(n=0; n<= myCountries.countries[i].cities.length; n++) {
						if(myCountries.countries[i].cities[n]) {
							var pointCoords = null;

/*
 * address is the geocoding location
 */
							address = myCountries.countries[i].cities[n].city_name + ", ";
							if(myCountries.countries[i].cities[n].state_code != "") {
								address += myCountries.countries[i].cities[n].state_code + ", ";
							}
							address += myCountries.countries[i].country_name;
						
/*
 * We found tha Google geocoding failed on some of our cities
 * so we map countries if that happens.
 */
							mapCountry = "";
							if(myCountries.countries[i].cities[n].state_code != "") {
								mapCountry += myCountries.countries[i].cities[n].state_code + ", ";
							}
							mapCountry += myCountries.countries[i].country_name;
						
/*
 * title is the tooltip for each point
 */
							tt_title = myCountries.countries[i].cities[n].city_name + ", ";
							if(myCountries.countries[i].cities[n].state_code != "") {
								tt_title += myCountries.countries[i].cities[n].state_code + ", ";
							}
							tt_title += myCountries.countries[i].country_name;

/*
 * if we have coords for a city, we use those
 * rather than geocoding
 */
							if((myCountries.countries[i].cities[n].longitude!="") && (myCountries.countries[i].cities[n].latitude!="")) {
								currLatitude = myCountries.countries[i].cities[n].latitude;
								currLongitude = myCountries.countries[i].cities[n].longitude;
							}

/*
 * vars set
 */
							state_code = myCountries.countries[i].cities[n].state_code;
							country_code = myCountries.countries[i].country_code;
							city_id = myCountries.countries[i].cities[n].city_id;
							country_name = myCountries.countries[i].country_name;

/*
 * check for coords
 */
							if(currLatitude == null || currLongitude == null) {
								plotPoint(address,tt_title,country_code,city_id,m,country_name,center_id,only_jhsph);
							} else {
								plotCodedPoint(currLatitude,currLongitude,tt_title,country_code,city_id,counter,country_name,center_id,only_jhsph);
							}

/*
 * step up counter
 */
							m++;
							counter = m;
						}
					}
				}
			}
		}
	}
	
/* 
 * Primary map function - loads on 
 * pageload and creates the map 
 * and geocoder objects
 */
    function load(longitude,latitude,zoom) {
      if (GBrowserIsCompatible()) {
        map = new GMap2(document.getElementById("map"));
        map.setCenter(new GLatLng(latitude,longitude), zoom, G_HYBRID_MAP);
        geocoder = new GClientGeocoder();
      }
    }

/*
 * We use this function to plot the points 
 * with coords on the map. It also pushes
 * the city_id and marker into the 
 * array we are holding on to, which contains
 * all our points.
 * 
 * it also calls clickHandler to display our includes. 
 * we call them here because the click event is part 
 * of the marker attributes.
 */
 
 	function plotCodedPoint(currLatitude,currLongitude,tt_title,country_code,city_id,counter,country_name,center_id,only_jhsph) {
		if (currLatitude && currLongitude) {
			var currPoint = new GLatLng(currLatitude,currLongitude);
			myicon = createIcon();
			var marker = new GMarker(currPoint, {'icon': myicon, 'tt_title': tt_title});
			mapPoints[counter] = [];
			mapPoints[counter].push(country_code,city_id,only_jhsph,marker);
			map.addOverlay(marker);
			GEvent.addListener(marker, "click", function() {
				clickHandler(marker, {"country_code":country_code,"city_id":city_id,"state_code":state_code,"center_id":center_id,"only_jhsph":only_jhsph}, "click", countryInclude);
				//map.setCenter(currPoint,eval(countryZoom));
				showAddress('"'+country_name+'"',eval(countryZoom));

/*				if(textMessage != null) {
					marker.openInfoWindowHtml(textMessage);
				} else {
					marker.openInfoWindowHtml(tt_title + "<br/>" + address);
				} */
			});
			return marker;
		}
 	}
 	
/*
 * We use this function to geocode AND plot
 * the points on the map. It also pushes
 * the city_id and marker into the 
 * array we are holding on to, which contains
 * all our points.
 * 
 * it also calls clickHandler 
 * to display our includes. we call them here
 * because the click event is part of the marker
 * attributes.
 */
	function plotPoint(address,tt_title,country_code,city_id,counter,country_name,center_id,only_jhsph) {
		if (geocoder) {
			geocoder.getLatLng(
				address, function(point) {
				if (point) {
					myicon = createIcon();
					var marker = new GMarker(point, {'icon': myicon, 'tt_title': tt_title});
					mapPoints[counter] = [];
					mapPoints[counter].push(country_code,city_id,marker,only_jhsph);
					map.addOverlay(marker);
					GEvent.addListener(marker, "click", function() {
						clickHandler(marker, {"country_code":country_code,"city_id":city_id,"state_code":state_code,"center_id":center_id,"only_jhsph":only_jhsph}, "click", countryInclude);
						showAddress('"'+country_name+'"',eval(countryZoom));

/* 
 * We'd put our bubble content here if we wanted to
 */
						//if(textMessage != null) {
						//	marker.openInfoWindowHtml(textMessage);
						//} else {
						//	marker.openInfoWindowHtml(tt_title + "<br/>" + address);
						//} 
					});
					return marker;
				}
			}
			);
		}
	}

/*
 * Here's where we remove points from the map.
 * We're using a second array, which has the marker
 * in it, to keep track of all the current points 
 * on the map.
 * 
 * If a country_code is supplied, we only remove the
 * points who have that country_code as part of 
 * their subarray. If not, we remove all points using 
 * the mapPoints array.
 */	
	function unplotPoints(country_code) {
		for(x=0;x<=mapPoints.length;x++) {
			if(mapPoints[x]) {
				if(mapPoints[x][0]==country_code) {
					map.removeOverlay(mapPoints[x][2]);
				} else {
					if(country_code==null) {
						map.removeOverlay(mapPoints[x][2]);
						document.getElementById(mapPoints[x][0]).checked = false;
					}
				}
			}
		}
	}

 
/*
 * showAddress finds the address returned
 * from the search form.
 */
	function showAddress(address,zoom) {
		if (geocoder) {
			geocoder.getLatLng(
				address,
				function(point) {
					if (!point) {
						alert(address + " not found");
					} else {
						var myZoom = 15;
						if(zoom) {
						myZoom = zoom;
						map.setCenter(point,myZoom);
					}
				}
			}
			);
		}
	}
	
	function panToAddress(address,zoom) {
		if (geocoder) {
			geocoder.getLatLng(
				address,
				function(point) {
					if (!point) {
						alert(address + " not found");
					} else {
						var myZoom = 15;
						if(zoom) {
						myZoom = zoom;
						map.panTo(point);
						map.setZoom(myZoom);
					}
				}
			}
			);
		}		
	}

/*
 * Simple function to create icon object
 * 
 * There's the default if one is not supplied.
 */
	function createIcon(iconImage,iconShadow) {
		var icon = new GIcon();
		if(!iconImage) {
			icon.image = "/custom/mod_projects/_images/pinPoint.png";
		} else {
			icon.image = iconImage;
		}
		if(!iconShadow) {
			icon.shadow = "/custom/mod_projects/_images/mm_20_shadow.png";
		} else {
			icon.shadow = iconShadow;			
		}

		icon.iconSize = new GSize(12, 20);
		icon.shadowSize = new GSize(22, 20);
		icon.iconAnchor = new GPoint(6, 6);
		icon.infoWindowAnchor = new GPoint(5, 1);
		return icon;
	}
	
/*
 * This function is a carryover from Chris's v2 map. 
 * It creates the request for the details about
 * the selected service
 * 
 * Note: We'll eventually want to combine the following
 * four functions into one or two or a class, but for now
 * in the interest of saving time, we'll leave it this way
 * CS 7/20/2007
 * 
 * Modified 10/2007 to allow multiple query items 
 * and dynamic includes
 * CS 10/17/2007
 */
	function clickHandler(marker, query, mode, countryInclude){
		if(query) {
			urlQuery = "?";
			for (key in query) {
				if(key) {
					myName = key;
					myValue = query[key];
					if(myValue!="") {
						urlQuery += myName + "=" + myValue + "&";
					}
				}
			}
		}
		countryInclude = countryInclude + urlQuery;
		pointRequest = createRequest();
		pointRequest.open("GET", countryInclude, true);
		pointRequest.onreadystatechange = getInfo;
		pointRequest.send(null);
  	}

/*
 * This is the function that loads the 
 * listing into the itemContainer div
 */
	function getInfo() {
		clearItemInfo();//we clear this here because of a Safari rendering bug
		if(pointRequest.readyState == 4) {
			document.getElementById("itemContainer").innerHTML = pointRequest.responseText;
			
		}
	}

/*
 * This is the AJAX request for the 
 * individual projects
 */
	
	function projectHandler(projectInclude, query){
		projectInclude = projectInclude + "?";
		if(query) {
			for (key in query) {
				projectInclude += key + "=" + query[key] + "&";
			}
		}		
		projectRequest = createRequest();
		projectRequest.open("GET", projectInclude, true);
		projectRequest.onreadystatechange = getProjectInfo;
		projectRequest.send(null);
		if(textMessage) {
			return textMessage;
		}
  	}

/*
 * This is the function that loads the 
 * project data into the itemContainer
 */
	function getProjectInfo() {
		clearItemInfo();//we clear this here because of a Safari rendering bug
		if(projectRequest.readyState == 4) {
			document.getElementById("itemContainer").innerHTML = projectRequest.responseText;
		}
	}

/* 
 * Removes content from the itemContainer
 */
	function clearItemInfo() {
		document.getElementById("itemContainer").innerHTML = "";
	}


/* all of the map controls are in this function.
 * 
 * we will eventually replace this with a control class -
 * or at least a more useful function - but for now it works
 * and wastes about 40 lines.
 */	
	function loadControls(width,height,navwidth,navheight) {
/* Our zoom controls One for Zoom in, Zoom out, Global View, and Close up */
		var zin = new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(10,10));
		zin.apply(document.getElementById("zoomInControl"));
		document.getElementById("map").appendChild(document.getElementById("zoomInControl"));	
		document.getElementById("zoomInControl").style.visibility = "visible";

		var zout = new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(31,10));
		zout.apply(document.getElementById("zoomOutControl"));
		document.getElementById("map").appendChild(document.getElementById("zoomOutControl"));	
		document.getElementById("zoomOutControl").style.visibility = "visible";

		var zoomclose = new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(52,10));
		zoomclose.apply(document.getElementById("closeupControl"));
		document.getElementById("map").appendChild(document.getElementById("closeupControl"));	
		document.getElementById("closeupControl").style.visibility = "visible";

		var zoomglobal = new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(73,10));
		zoomglobal.apply(document.getElementById("globalControl"));
		document.getElementById("map").appendChild(document.getElementById("globalControl"));	
		document.getElementById("globalControl").style.visibility = "visible";

/* Our directional controls One for North, South, East and West */
		var northNav = new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(Math.round((width-navwidth)/2),0));
		northNav.apply(document.getElementById("northControl"));
		document.getElementById("map").appendChild(document.getElementById("northControl"));	
		document.getElementById("northControl").style.visibility = "visible";
		
		var westNav = new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(0,Math.round((height-navwidth)/2)));
		westNav.apply(document.getElementById("westControl"));
		document.getElementById("map").appendChild(document.getElementById("westControl"));	
		document.getElementById("westControl").style.visibility = "visible";
		
		var eastNav = new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(Math.round(width-navheight),Math.round((height-navwidth)/2)));
		eastNav.apply(document.getElementById("eastControl"));
		document.getElementById("map").appendChild(document.getElementById("eastControl"));	
		document.getElementById("eastControl").style.visibility = "visible";
		
		var southNav = new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(Math.round((width-navwidth)/2),Math.round(height-navheight)));
		southNav.apply(document.getElementById("southControl"));
		document.getElementById("map").appendChild(document.getElementById("southControl"));	
		document.getElementById("southControl").style.visibility = "visible";		
	}
	
/*
 * These functions are carryovers from past map versions.
 */

/*  
 * Reset map functions
 * 
 * Note: User resetCenter - more flexibility
 * the vars come from the application.
 * 
 */

//function resetMap()
//{
//	map.setCenter(new GLatLng(startLat, startLng));
//	map.setZoom(startZoom);
//
//}

function resetCenter(longitude, latitude, zoom)
{
	var center = new GLatLng(latitude, longitude);
	map.setCenter(center, zoom);
}

/* Redefining an existing function is bad pratice - especially if 
 * its does the same thing in a more limiting way the original function. 
 * Bad idea. Commented out. Good example of what NOT to do.
 * 
 * function zoomIn()
 * {
 * 	map.zoomIn();
 * }	
 * 
 * function zoomOut()
 * {
 * 	map.zoomOut();
 * }
 */


