function createIcons()
{
	icon00 = new GIcon();
	icon00.image = "http://schoolperformancemaps.com/images/00.png";
	icon00.shadow = "http://schoolperformancemaps.com/images/shadow.png";
	icon00.iconSize = new GSize(12, 20);
	icon00.shadowSize = new GSize(22, 20);
	icon00.iconAnchor = new GPoint(6, 20);
	icon00.infoWindowAnchor = new GPoint(5, 1);
	
	icon01 = new GIcon();
	icon01.image = "http://schoolperformancemaps.com/images/01.png";
	icon01.shadow = "http://schoolperformancemaps.com/images/shadow.png";
	icon01.iconSize = new GSize(12, 20);
	icon01.shadowSize = new GSize(22, 20);
	icon01.iconAnchor = new GPoint(6, 20);
	icon01.infoWindowAnchor = new GPoint(5, 1);
	
	icon02 = new GIcon();
	icon02.image = "http://schoolperformancemaps.com/images/02.png";
	icon02.shadow = "http://schoolperformancemaps.com/images/shadow.png";
	icon02.iconSize = new GSize(12, 20);
	icon02.shadowSize = new GSize(22, 20);
	icon02.iconAnchor = new GPoint(6, 20);
	icon02.infoWindowAnchor = new GPoint(5, 1);
	
	icon03 = new GIcon();
	icon03.image = "http://schoolperformancemaps.com/images/03.png";
	icon03.shadow = "http://schoolperformancemaps.com/images/shadow.png";
	icon03.iconSize = new GSize(12, 20);
	icon03.shadowSize = new GSize(22, 20);
	icon03.iconAnchor = new GPoint(6, 20);
	icon03.infoWindowAnchor = new GPoint(5, 1);
	
	icon04 = new GIcon();
	icon04.image = "http://schoolperformancemaps.com/images/04.png";
	icon04.shadow = "http://schoolperformancemaps.com/images/shadow.png";
	icon04.iconSize = new GSize(12, 20);
	icon04.shadowSize = new GSize(22, 20);
	icon04.iconAnchor = new GPoint(6, 20);
	icon04.infoWindowAnchor = new GPoint(5, 1);
	
	icon05 = new GIcon();
	icon05.image = "http://schoolperformancemaps.com/images/05.png";
	icon05.shadow = "http://schoolperformancemaps.com/images/shadow.png";
	icon05.iconSize = new GSize(12, 20);
	icon05.shadowSize = new GSize(22, 20);
	icon05.iconAnchor = new GPoint(6, 20);
	icon05.infoWindowAnchor = new GPoint(5, 1);
	
	icon06 = new GIcon();
	icon06.image = "http://schoolperformancemaps.com/images/06.png";
	icon06.shadow = "http://schoolperformancemaps.com/images/shadow.png";
	icon06.iconSize = new GSize(12, 20);
	icon06.shadowSize = new GSize(22, 20);
	icon06.iconAnchor = new GPoint(6, 20);
	icon06.infoWindowAnchor = new GPoint(5, 1);
	
	icon07 = new GIcon();
	icon07.image = "http://schoolperformancemaps.com/images/07.png";
	icon07.shadow = "http://schoolperformancemaps.com/images/shadow.png";
	icon07.iconSize = new GSize(12, 20);
	icon07.shadowSize = new GSize(22, 20);
	icon07.iconAnchor = new GPoint(6, 20);
	icon07.infoWindowAnchor = new GPoint(5, 1);
	
	icon08 = new GIcon();
	icon08.image = "http://schoolperformancemaps.com/images/08.png";
	icon08.shadow = "http://schoolperformancemaps.com/images/shadow.png";
	icon08.iconSize = new GSize(12, 20);
	icon08.shadowSize = new GSize(22, 20);
	icon08.iconAnchor = new GPoint(6, 20);
	icon08.infoWindowAnchor = new GPoint(5, 1);
	
	icon09 = new GIcon();
	icon09.image = "http://schoolperformancemaps.com/images/09.png";
	icon09.shadow = "http://schoolperformancemaps.com/images/shadow.png";
	icon09.iconSize = new GSize(12, 20);
	icon09.shadowSize = new GSize(22, 20);
	icon09.iconAnchor = new GPoint(6, 20);
	icon09.infoWindowAnchor = new GPoint(5, 1);
	
	icon10 = new GIcon();
	icon10.image = "http://schoolperformancemaps.com/images/10.png";
	icon10.shadow = "http://schoolperformancemaps.com/images/shadow.png";
	icon10.iconSize = new GSize(12, 20);
	icon10.shadowSize = new GSize(22, 20);
	icon10.iconAnchor = new GPoint(6, 20);
	icon10.infoWindowAnchor = new GPoint(5, 1);
	
}

function getHeight()
{
	var y = 600;
	if (self.innerHeight) // all except Explorer
	{
		y = self.innerHeight;
	}
	else if (document.documentElement && document.documentElement.clientHeight)
		// Explorer 6 Strict Mode
	{
		y = document.documentElement.clientHeight;
	}
	else if (document.body) // other Explorers
	{
		y = document.body.clientHeight;
	}
	return y;
}

function getWidth()
{
	var x = 700;
	if (self.innerWidth) // all except Explorer
	{
		x = self.innerWidth;
	}
	else if (document.documentElement && document.documentElement.clientWidth)
		// Explorer 6 Strict Mode
	{
		x = document.documentElement.clientWidth;
	}
	else if (document.body) // other Explorers
	{
		x = document.body.clientWidth;
	}
	return x;
}

function checkHeight()
{
	var newHeight = getHeight() - 191;
	document.getElementById("map").style.height = newHeight + "px";
	var newHeight2 = newHeight - 24;
	document.getElementById("about").style.height = newHeight2 + "px";
	document.getElementById("contact").style.height = newHeight2 + "px";
	
	var newWidth = getWidth() - 196;
	document.getElementById("about").style.width = newWidth + "px";
	document.getElementById("contact").style.width = newWidth + "px";
}

function resetMap()
{
	// redraw map in most browsers, reload page in Safari
	if (document.getElementById("maplink"))
	{
		document.getElementById("maplink").innerHTML = "";
	}
	/* if (navigator.userAgent.indexOf("Safari") == -1)
	{ */
		mapState();
	/* }
	else
	{
		window.location.reload(true);
	} */
	return;
}

function preUpdate()
{
	if (document.getElementById("maplink"))
	{
		document.getElementById("maplink").innerHTML = "";
	}
	document.getElementById("info").innerHTML = "<strong>Updating map -- please wait...</strong>";
	document.getElementById("progress").innerHTML = "Checking database...";
	// if (navigator.userAgent.indexOf("Safari") == -1)
	// {
		window.setTimeout("updateMarkers();", 200);
	// }
	// else
	// {
	// 	updateMarkers();
	// }
}

function updateMarkers()
{
	// timeLog = "start update markers: " + ((new Date())/1000);

	// hide the about and contact info
	document.getElementById("contact").style.display = "none";
	document.getElementById("about").style.display = "none";

	var bounds = map.getBounds();
	
	// state-specific function
	var schTypeCode = getSchoolTypeCode();
	
	// if schooltypes change, get rid of all markers
	if (schTypeCode != oldSchTypeCode)
	{
		map.clearOverlays();
		markers = [];
	}
	/*
	else if (!bounds.equals(oldBounds))
	// if bounds change, kill markers outside outerBounds
	{
			var osw = new GLatLng(
				(bounds.getSouthWest().lat() - (bounds.getCenter().lat() - bounds.getSouthWest().lat())),
				(bounds.getSouthWest().lng() - (bounds.getCenter().lng() - bounds.getSouthWest().lng()))
				);
			var one = new GLatLng(
				(bounds.getNorthEast().lat() + (bounds.getNorthEast().lat() - bounds.getCenter().lat())),
				(bounds.getNorthEast().lng() + (bounds.getNorthEast().lng() - bounds.getCenter().lng()))
				);
			outerBounds = bounds;
			outerBounds.extend(osw);
			outerBounds.extend(one);
			for (theMarker in markers)
			{
				if (!outerBounds.contains(theMarker.getPoint()))
				{
					map.removeOverlay(theMarker);
					delete markers[theMarker];
				}
			}
	}
	*/
	
	// see if we should map if there is a change in bounds or school types selected
	if (!bounds.equals(oldBounds) || schTypeCode != oldSchTypeCode)
	{
		
		oldSchTypeCode = schTypeCode;
		oldBounds = bounds;
		
		/* if (bounds.minX != oldBounds.minX || bounds.minY != oldBounds.minY || bounds.maxX != oldBounds.maxX || bounds.maxY != oldBounds.maxY)
		{
			oldBounds.minX = bounds.minX;
			oldBounds.minY = bounds.minY;
			oldBounds.maxX = bounds.maxX;
			oldBounds.maxY = bounds.maxY;
		} */
		
		if (map.getZoom() >= minPlotZoom && schTypeCode != "0")
		// only map schools if we are zoomed in sufficiently and school type(s) are selected
		{			
			var requestUrl = "getschoolinfo.php?limit=" + markerLimit + "&minlon=" + bounds.getSouthWest().lng() + "&maxlon=" + bounds.getNorthEast().lng() + "&minlat=" + bounds.getSouthWest().lat() + "&maxlat=" + bounds.getNorthEast().lat() + "&schtypecode=" + schTypeCode;
			var request = GXmlHttp.create();
			request.open("GET", requestUrl, true);
			request.onreadystatechange = function() {
				if (request.readyState == 4) {
					var xmlDoc = request.responseXML;
					scount = xmlDoc.documentElement.getElementsByTagName("schoolcount")[0].firstChild.data;
					
					var tcArray = xmlDoc.documentElement.getElementsByTagName("topcity");
					if (tcArray.length && tcArray[0].firstChild)
					{
						topCity = tcArray[0].firstChild.data;
					}
					else
					{
					topCity = "";
					}

					schools = xmlDoc.documentElement.getElementsByTagName("schoolinfo");
					schoolsAA = new Object();
					for (i = 0; i < schools.length; i++)
					{
						schoolsAA['cds' + schools[i].getElementsByTagName("cds_code")[0].firstChild.data] = -1;
					}
					
					if (scount > markerLimit)
					{
						document.getElementById("progress").innerHTML = "Mapping " + markerLimit + " schools of " + scount + " found...";
					}
					else if (scount == 1)
					{
						document.getElementById("progress").innerHTML = "Mapping 1 school...";
					}
					else
					{
						document.getElementById("progress").innerHTML = "Mapping " + scount + " schools...";
					}
					
					updateAds();
										
					// async call to actually change markers, so progress info can show first
					// timeLog += "\ncalling setTimeout: " + ((new Date())/1000);
					
					// if (navigator.userAgent.indexOf("Safari") == -1)
					// {
						window.setTimeout("mapSchools();", 200);
					// }
					// else
					// {
					// 	mapSchools();
					// }
	
				}
			}
			request.send(null);
			
			// set up hash if maplink exists
			if (document.getElementById("maplink"))
			{
				// alert(map.getCenter().lat() + "%2C" + map.getCenter().lng() + "%2C" + map.getZoom() + "%2C" + schTypeCode.replace(/\,/g, "%2C"));
				document.getElementById("maplink").innerHTML = '<a href="#' + (Math.round(1000000 * map.getCenter().lat())/1000000) + '%2C' + (Math.round(1000000 * map.getCenter().lng())/1000000) + '%2C' + map.getZoom() + '%2C' + schTypeCode.replace(/\,/g, '%2C') + '">Link to this map</a>';
			}
		}
		else
		{
			document.getElementById("progress").innerHTML = "";
			resetText();
		}
	}
	else
	{
		document.getElementById("progress").innerHTML = "";
		resetText();
	}	
}


function mapSchools()
{
	// v2 experiment -- blocking all code that reuses markers
	
	for (j = 0; j < scount && j < markerLimit; j++)
	{
		// loop through results to map
		if (!markers["school"+schools[j].getElementsByTagName("cds_code")[0].firstChild.data])
		{
			markers["school"+schools[j].getElementsByTagName("cds_code")[0].firstChild.data] = createSchoolMarker(new GLatLng(parseFloat(schools[j].getElementsByTagName("lat")[0].firstChild.data), parseFloat(schools[j].getElementsByTagName("lon")[0].firstChild.data)), schools[j].getElementsByTagName("cds_code")[0].firstChild.data, schools[j].getElementsByTagName("nces")[0].firstChild.data, schools[j].getElementsByTagName("district")[0].firstChild.data, schools[j].getElementsByTagName("school")[0].firstChild.data, schools[j].getElementsByTagName("rankinfo")[0].firstChild.data, schools[j].getElementsByTagName("avg_rank")[0].firstChild.data);
			
			map.addOverlay(markers["school"+schools[j].getElementsByTagName("cds_code")[0].firstChild.data]);
		}
	}
	
	if (document.getElementById("progress").innerHTML != "") document.getElementById("progress").innerHTML += " done";
	resetText();

}


function resetText()
{
	if (map.getZoom() < minPlotZoom)
	{
		document.getElementById("info").innerHTML = "Click the map to zoom in to an area and map nearby schools.";
	}
	else
	{
		document.getElementById("info").innerHTML = "Click and drag inside the map to recenter.";
		if (document.getElementById("checkboxes"))
		{
			// alert("reset hash");
			var newhash = map.getCenterLatLng().y + "," + map.getCenterLatLng().x + "," + map.getZoom();
			// alert(document.getElementById("checkboxes").elements.length);
			for (var box = 0; box < document.getElementById("checkboxes").elements.length; box++)
			{
				// alert(document.getElementById("checkboxes").elements[box].checked);
				if (document.getElementById("checkboxes").elements[box].checked == true)
				{
					newhash += ("," + document.getElementById("checkboxes").elements[box].id);
				}
			}
			// location.hash = encode64(newhash);
			document.getElementById("maplink").innerHTML = '<a href="#' + encode64(newhash) + '">Link to this map</a>';
		}
	}
	if (oldSchTypeCode == "0") document.getElementById("info").innerHTML += "<br /><strong>Select at least one school type</strong> at the top.";	
	
}

function about()
{
	document.getElementById("about").style.display = "block";
	document.getElementById("contact").style.display = "none";
}

function closeAbout()
{
	document.getElementById("about").style.display = "none";
}

function contact()
{
	document.getElementById("contact").style.display = "block";
	document.getElementById("about").style.display = "none";
}

function closeContact()
{
	document.getElementById("contact").style.display = "none";
}

function ahah(url,target)
{
   // native XMLHttpRequest object
   document.getElementById(target).innerHTML = '...';
   if (window.XMLHttpRequest) {
       req = new XMLHttpRequest();
       req.onreadystatechange = function() {ahahDone(target);};
       req.open("GET", url, true);
       req.send(null);
   // IE/Windows ActiveX version
   } else if (window.ActiveXObject) {
       req = new ActiveXObject("Microsoft.XMLHTTP");
       if (req) {
           req.onreadystatechange = function() {ahahDone(target);};
           req.open("GET", url, true);
           req.send();
       }
   }
}

function ahahDone(target)
{
   // only if req is "loaded"
   if (req.readyState == 4) {
       // only if "OK"
       if (req.status == 200 || req.status == 304) {
           results = req.responseText;
           document.getElementById(target).innerHTML = results;
       } else {
           document.getElementById(target).innerHTML="ahah error:\n" +
               req.statusText;
       }
   }
}

function encode64(input) {
  var output = "";
  var chr1, chr2, chr3 = "";
  var enc1, enc2, enc3, enc4 = "";
  var i = 0;
  var keyStr = "ABCDEFGHIJKLMNOP" +
			"QRSTUVWXYZabcdef" +
			"ghijklmnopqrstuv" +
			"wxyz0123456789+/" +
			"=";


  do {
	 chr1 = input.charCodeAt(i++);
	 chr2 = input.charCodeAt(i++);
	 chr3 = input.charCodeAt(i++);

	 enc1 = chr1 >> 2;
	 enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
	 enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
	 enc4 = chr3 & 63;

	 if (isNaN(chr2)) {
		enc3 = enc4 = 64;
	 } else if (isNaN(chr3)) {
		enc4 = 64;
	 }

	 output = output + 
		keyStr.charAt(enc1) + 
		keyStr.charAt(enc2) + 
		keyStr.charAt(enc3) + 
		keyStr.charAt(enc4);
	 chr1 = chr2 = chr3 = "";
	 enc1 = enc2 = enc3 = enc4 = "";
  } while (i < input.length);

  return output;
}

function decode64(input) {
  var output = "";
  var chr1, chr2, chr3 = "";
  var enc1, enc2, enc3, enc4 = "";
  var i = 0;
  var keyStr = "ABCDEFGHIJKLMNOP" +
			"QRSTUVWXYZabcdef" +
			"ghijklmnopqrstuv" +
			"wxyz0123456789+/" +
			"=";

  // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
  var base64test = /[^A-Za-z0-9\+\/\=]/g;
  if (base64test.exec(input)) {
	 alert("There were invalid base64 characters in the input text.\n" +
		   "Valid base64 characters are A-Z, a-z, 0-9, '+', '/', and '='\n" +
		   "Expect errors in decoding.");
  }
  input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

  do {
	 enc1 = keyStr.indexOf(input.charAt(i++));
	 enc2 = keyStr.indexOf(input.charAt(i++));
	 enc3 = keyStr.indexOf(input.charAt(i++));
	 enc4 = keyStr.indexOf(input.charAt(i++));

	 chr1 = (enc1 << 2) | (enc2 >> 4);
	 chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
	 chr3 = ((enc3 & 3) << 6) | enc4;

	 output = output + String.fromCharCode(chr1);

	 if (enc3 != 64) {
		output = output + String.fromCharCode(chr2);
	 }
	 if (enc4 != 64) {
		output = output + String.fromCharCode(chr3);
	 }

	 chr1 = chr2 = chr3 = "";
	 enc1 = enc2 = enc3 = enc4 = "";

  } while (i < input.length);

  return output;
}

