var reslist;
var resmap;
var AllSymbol = '00ALL';
var lang = 'Japanese';
var japaneseintro;
var englishintro;

function zoomToPoint(lat, lng) {
	var center = new GLatLng(lat, lng);
	drawmap(center, null, null, false);
}

function zoomToCity(lat, lng, city) {
	var center = new GLatLng(lat, lng);
	drawmap(center, city, null, false);
}

function zoomOut() {
	drawmap(null, null, null, false);
}

function popupResinfo(res) {
	var i;
	var s = '<div class="resinfo">';

	s += 'Zoom Level: '
 	s += ' <a class="clickable" onclick="zoomToPoint(' + res.latitude + ',' +
 		res.longitude + ')">street</a> / ';
 	s += ' <a class="clickable" onclick="zoomToCity(' + res.latitude + ',' +
 		res.longitude + ',\'' + res.city + '\')">city</a> / ';
	s += ' <a class="clickable" onclick="zoomOut()">full</a>';
	s += '<br /><br />';

	if (res.url)
		s += '<a href="' + res.url + '">';
	s += res.name;
	if (res.url)
		s += '</a>';
	s += '<br />';
	s += 'Genre: ' + res.genre ;
	if (res.subgenre)
		s += '(' + res.subgenre + ')';
	s += '<br />';
	s += 'Address: ' + res.address + ', ' + res.city + ', ' + res.state;
	if (res.zip)
		s += ' ' + res.zip;
	s += '<br />';
	s += 'Phone: ' + res.phone + '<br />';
	for (i = 0; res.photo[i]; i++) {
		if (i == 0)
			s += 'Photo: ';
		else
			s += ', ';
		s += '<a href="' + res.photo[i].url + '">';
		s += res.photo[i].date + '</a>';
	}
	if (i > 0)
		s += '<br />';
	if (res.thumbnail) {
		s += '<ul class="thumbnail">'
		for (i = 0; res.thumbnail[i]; i++) {
			s += '<li><a href="' + res.thumbnail[i].url + '">';
			s += '<img src="' + res.thumbnail[i].img +
				'" alt="" /></a></li>';
		}
		s += '</ul>'
	}
	if (i > 0)
		s += '<br />';
	if (res.comment)
		s += 'Comment: ' + res.comment + '<br />'; 

	s += '</div>';
	res.marker.openInfoWindowHtml(s);
}

function createMarker(res) {
	var loc = new GLatLng(res.latitude, res.longitude);
	var marker = new GMarker(loc);

	GEvent.addListener(marker, "click",
			   function() {
				   popupResinfo(res);
			   }
			);
	return marker;
}

function createMap() {
	if (!GBrowserIsCompatible())
		return;
	var mapelem = document.getElementById("map");
	if (mapelem) {
		resmap = new GMap2(mapelem);

		drawmap(null, null, null, false);

		resmap.addControl(new GLargeMapControl());
		resmap.addControl(new GMapTypeControl());

		for (var i = 0; reslist.restaurants.restaurant[i]; i++) {
			var marker = reslist.restaurants.restaurant[i].marker;
 			if (marker)
 				resmap.addOverlay(marker);
		}
	}
}

function redrawMap() {
	// set the map center to center of the markers, and choose
	// the largest zoom level that can contain all the makers.

	resmap.checkResize();
	var zoomLevel = resmap.getBoundsZoomLevel(reslist.bounds);
	resmap.setCenter(reslist.center, zoomLevel, G_NORMAL_MAP);
}

function drawmap(point, cityname, genrename, resetmarker) {
	// if a single point is given, just use it
	// else if city name is given, limit the city wide
	// otherwise, use the entire area
	var ne, sw, center;

	if (resetmarker)
		resmap.clearOverlays();

	if (point && !cityname) {
		ne = point;
		sw = point;
		center = point;
	} else {
		var maxlat = -90;
		var minlat = 90;
		var maxlng = -180;
		var minlng = 180;

		for (var i = 0; reslist.restaurants.restaurant[i]; i++) {
			var res = reslist.restaurants.restaurant[i];

			if (cityname &&
			    cityname != AllSymbol && cityname != res.city)
				continue;

			if (genrename &&
			    genrename != AllSymbol && genrename != res.genre)
				continue;

			if (resetmarker)
				resmap.addOverlay(res.marker);

			if (maxlat < res.latitude)
				maxlat = res.latitude;
			if (minlat > res.latitude)
				minlat = res.latitude;
			if (maxlng < res.longitude)
				maxlng = res.longitude;
			if (minlng > res.longitude)
				minlng = res.longitude;
		}

		ne = new GLatLng(maxlat, maxlng);
		sw = new GLatLng(minlat, minlng);

		if (point)
			center = point;
		else {
			// note: (lng1 + lng2) / 2 may not work due to overflow.
			center = new GLatLng(ne.lat() / 2.0 + sw.lat() / 2.0,
					     ne.lng() / 2.0 + sw.lng() / 2.0);
		}
	}

	reslist.bounds = new GLatLngBounds(ne, sw);
	reslist.center = center;

	redrawMap();
}

function drawTableByFunc(compfunc) {
	reslist.compfunc = compfunc;
	drawTable();
}

function limitCity(cityname) {
	if (reslist.selectedcity == cityname)
		return;

	reslist.selectedcity = cityname;
	drawTable();
	if (resmap)
		drawmap(null, cityname, reslist.selectedgenre, true);
}

function limitGenre(genrename) {
	if (reslist.selectedgenre == genrename)
		return;

	reslist.selectedgenre = genrename;
	drawTable();
	if (resmap)
		drawmap(null, reslist.selectedcity, genrename, true);
}

// This is an explicit closure to retain a specific restaurant object on
// callback.
function makePopupCallback(res) {
	return (function() { popupResinfo(res); });
}

function drawTable() {
	var parent = document.getElementById(reslist.id);
	var tablenode = document.createElement("table");
	var tbodynode = document.createElement("tbody");
	var anode, divid, divnode, trnode, thnode, tdnode, textnode;

	divid = reslist.id + 'table';
	divnode = document.getElementById(divid);
	if (divnode)
		divnode.parentNode.removeChild(divnode);
	divnode = document.createElement("div");
	divnode.id = divid;
	parent.appendChild(divnode);
	reslist.restaurants.restaurant.sort(reslist.compfunc);

	// table header
	trnode = document.createElement("tr");

	// restaurant name
	thnode = document.createElement("th");
	anode = document.createElement("a");
	anode.onclick = function() {
		drawTableByFunc(compByName);
	};
	textnode = document.createTextNode("name");
	anode.appendChild(textnode);
	thnode.appendChild(anode);
	trnode.appendChild(thnode);
	// food genre
	thnode = document.createElement("th");
	anode = document.createElement("a");
	anode.onclick = function() {
		drawTableByFunc(compByGenre);
	};
	textnode = document.createTextNode("genre");
	anode.appendChild(textnode);
	thnode.appendChild(anode);
	trnode.appendChild(thnode);
	// city name
	thnode = document.createElement("th");
	anode = document.createElement("a");
	anode.onclick = function() {
		drawTableByFunc(compByCity);
	};
	textnode = document.createTextNode("city");
	anode.appendChild(textnode);
	thnode.appendChild(anode);
	trnode.appendChild(thnode);
	// number of photo pages
	thnode = document.createElement("th");
	anode = document.createElement("a");
	anode.onclick = function() {
		drawTableByFunc(compByRefs);
	};
	textnode = document.createTextNode("refs");
	anode.appendChild(textnode);
	thnode.appendChild(anode);
	trnode.appendChild(thnode);

	tbodynode.appendChild(trnode);

	// table content
	for (var i = 0; reslist.restaurants.restaurant[i]; i++) {
		var res = reslist.restaurants.restaurant[i];

		if (reslist.selectedcity != AllSymbol &&
		    reslist.selectedcity != res.city)
			continue;

		if (reslist.selectedgenre != AllSymbol &&
		    reslist.selectedgenre != res.genre)
			continue;

		trnode = document.createElement("tr"); // start row

		// restaurant name
		tdnode = document.createElement("td");
		anode = document.createElement("a");
		anode.className = 'clickable';
 		anode.onclick = makePopupCallback(res);
		textnode = document.createTextNode(res.name);
		anode.appendChild(textnode);
		tdnode.appendChild(anode);
		trnode.appendChild(tdnode);

		// food genre
		tdnode = document.createElement("td");
		textnode = document.createTextNode(res.genre);
		tdnode.appendChild(textnode);
		trnode.appendChild(tdnode);

		// city name
		tdnode = document.createElement("td");
		textnode = document.createTextNode(res.city);
		tdnode.appendChild(textnode);
		trnode.appendChild(tdnode);

		// number of photo pages
		tdnode = document.createElement("td");
		textnode = document.createTextNode(res.photo.length);
		tdnode.appendChild(textnode);
		trnode.appendChild(tdnode);

		tbodynode.appendChild(trnode); // close row
	}

	tablenode.appendChild(tbodynode); // close tbody
	divnode.appendChild(tablenode);	  // close table
}

function compByName(x, y) {
	if (x.name > y.name)
		return 1;
	else if (x.name < y.name)
		return -1;
	else if (x.phone > y.phone) // XXX: last resort
		return 1;
	else if (x.phone < y.phone)
		return -1;
	return (compByCity(x, y));
}

function compByCity(x, y) {
	if (x.city > y.city)
		return 1;
	else if (x.city < y.city)
		return -1;
	return (compByName(x, y));
}

function compByGenre(x, y) {
	if (x.genre > y.genre)
		return 1;
	else if (x.genre < y.genre)
		return -1;
	return (compByCity(x, y));
}

function compByRefs(x, y) {	// ascending order
	if (x.photo.length > y.photo.length)
		return -1;
	else if (x.photo.length < y.photo.length)
		return 1;
	return (compByCity(x, y));
}

function drawMenu(list) {
	var i = 0;
	var tmparray = new Array(list.length);
	var key;

	for (key in list)
		tmparray[i++] = key;
	tmparray.sort();

	for (i = 0; i < tmparray.length; i++) {
		key = tmparray[i];
		document.write('<option value="' + key + '"');
		if (key == AllSymbol) {
			document.write(' selected="selected"');
			document.write('>All');
		} else
			document.write('>' + key);
		document.write(' (' + list[key] + ')</option>');
	}
}

function toggleLang() {
	var langswnode = document.getElementById("langswitch");

	if (lang == 'Japanese')
		lang = 'English';
	else
		lang = 'Japanese';
	if (langswnode.hasChildNodes()) {
		// XXX: assuming there's at most one child
		langswnode.removeChild(langswnode.firstChild);
	}
	updatelang(langswnode);
	updateintro();
}

function updatelang(node) {
	var text = (lang == 'Japanese') ? '[English]' : '[Japanese]';
	var textnode = document.createTextNode(text);
	node.appendChild(textnode);
}

function updateintro() {
	var intronode = document.getElementById("intro");
	var textnode = document.createTextNode((lang == 'Japanese') ?
					       japaneseintro : englishintro);

	if (intronode.hasChildNodes()) {
		// XXX: assuming there's at most one child
		intronode.removeChild(intronode.firstChild);
	}
	intronode.appendChild(textnode);
}

function showlist(id) {
	var xml = new JKL.ParseXML("res.xml");
	var citylist = [];
	var genrelist = [];

	var langswnode = document.getElementById("langswitch");
	updatelang(langswnode);
	
	xml.setOutputArrayElements(["restaurant", "photo", "thumbnail"]);
	reslist = xml.parse();

	japaneseintro = reslist.restaurants.japaneseintro;
	englishintro = reslist.restaurants.englishintro;
	updateintro();

	for (var i = 0; reslist.restaurants.restaurant[i]; i++) {
		var res = reslist.restaurants.restaurant[i];

		//XXX: assume there's no name of AllSymbol in the list
		citylist[AllSymbol] = citylist[AllSymbol] ?
			citylist[AllSymbol] + 1 : 1;
		citylist[res.city] = citylist[res.city] ?
			citylist[res.city] + 1 : 1;
		genrelist[AllSymbol] = genrelist[AllSymbol] ?
			genrelist[AllSymbol] + 1 : 1;
		genrelist[res.genre] = genrelist[res.genre] ?
			genrelist[res.genre] + 1 : 1;

		if (res.latitude && res.longitude) {
			var marker = createMarker(res);
			res.marker = marker;
		}
	}

	// Create a pull down menu for cities
	document.write('<div class="linemenu">');
	document.write('Limit city: <select name="city"' +
		       ' onchange=limitCity(this.options[this.selectedIndex].value)>');
	drawMenu(citylist);
	document.write('</select>');
	document.write('</div>');

	// Create a pull down menu for genres
	document.write('<div class="linemenu">');
	document.write('Limit genre: <select name="genre"' +
		       ' onchange=limitGenre(this.options[this.selectedIndex].value)>');
	drawMenu(genrelist);
	document.write('</select>');
	document.write('</div>');

	reslist.id = id;
	reslist.compfunc = compByCity;
	reslist.selectedcity = AllSymbol;
	reslist.selectedgenre = AllSymbol;
	drawTable();
}

