
/**
 * project code name 'nepal': earthpoi.com v1.0
 * a free global public/private points of interest storage/sharing system
 * (c) 2006 by Bas van Gaalen & Ana Henneberke. all rights reserved.
 * $Id: main.v1.0.1.js 500 2006-10-16 18:32:46Z bas $
 */

// main application
var App = {

	aListeners: [],
	sStatus: null,
	oDeleteMarkerId: null,
	sButtonText: null,
	oButton: null,

	msgLoading: '<div class="loading"><img src="/media/wait.gif" alt="" width="18" height="18" />loading...</div>',
	msgMoving: '<div class="moving">Position me at the desired location and click <b>save</b> in the panel.</div>',

	init: function(sUrl, bInitMap, iPoiId) {
		Server.init(sUrl);
		if (bInitMap) {
			if (GBrowserIsCompatible()) {
				Map.init(iPoiId);
				if (!Auth.trySessionSignin()) {
					if (!Auth.tryCookieSignin()) {
						App.refreshHeader();
					}
				}
			} else {
				//location.href = '?pid=nofun';
				alert('incompatible browser!');
			}
		}
		if (!iPoiId) Panel.open();
	},

	shutdown: function() {
		GUnload();
		App.aListeners.each(function(l) {
			GEvent.removeListener(l);
		});
	},

	getStatus: function() {
		return (this.sStatus != null) ? this.sStatus : 'idle';
	},

	setStatus: function(sStatus) {
		if (!sStatus) sStatus = null;
		this.sStatus = sStatus;
	},

	isStatus: function(sStatus) {
		if (!sStatus) sStatus = 'idle';
		return sStatus == this.getStatus();
	},

	getHtml: function(sTpl, sElm, onCompleteFunc, sExtraPars) {
		if (!onCompleteFunc) onCompleteFunc = null;
		if (!sExtraPars) sExtraPars = '';
		Server.requestAndUpdate(sElm, 'a=ght&f=html&t=' + sTpl + '&' + sExtraPars, onCompleteFunc);
	},

	getNavigation: function() {
		App.getHtml('navigation', 'header', function(oXhr, oJson) {
			Tabs.init('home');
		}, 'u=' + User.getUid());
	},

	refreshHeader: function() {
		App.getNavigation();
		Map.get().removeControl(Map.oAddControl);
		Map.get().removeControl(Map.oGLargeMapControl);
		if (User.getUid()) {
			Map.oAddControl = new MapAddControl();
			Map.get().addControl(Map.oAddControl, new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(7, 7)));
			var oPos = new GSize(7, 91);
		} else {
			var oPos = new GSize(7, 7);
		}
		Map.oGLargeMapControl = new GLargeMapControl();
		Map.get().addControl(Map.oGLargeMapControl, new GControlPosition(G_ANCHOR_TOP_LEFT, oPos));
	},

	setLocation: function(sLocation) {
		document.locsearch.mapsearch.value = sLocation;
		Map.geocode(sLocation);
	},

	displayMessage: function(msg) {
		Element.show('msg');
		$('msg').innerHTML = msg;
	},

	displayError: function(msg) {
		Element.show('page_error_msg');
		$('page_error_msg').innerHTML = msg;
	},

	openAbout: function() {
		Win.open('about', 600, 400);
	},

	closeAbout: function() {
		Win.close();
	},

	openPrivacy: function() {
		Win.open('privacy', 600, 400);
	},

	closePrivacy: function() {
		Win.close();
	},

	openContact: function() {
		Win.open('contact', 380, 180);
	},

	closeContact: function() {
		Win.close();
	},

	disableButton: function(oBut) {
		App.oButton = oBut;
		App.sButtonText = oBut.value;
		oBut.blur();
		oBut.disabled = true;
		oBut.value = 'please wait...';
	},

	enableButton: function() {
		if (App.oButton) {
			App.oButton.disabled = false;
			App.oButton.value = App.sButtonText;
		}
	}

};

// add control handling
var MapAddControl = function() {};

// google map handling
var Map = {

	oMap: null,
	oGeoCode: null,
	oPBounds: null,
	oAddControl: null,
	oGLargeMapControl: null,
	bLoading: null,
	sFormText: null,

	init: function(iPoiId) {
		this.bLoading = false;
		this.sFormText = document.locsearch.mapsearch.value;
		this.initAddControl();
		var eMap = $('map');
		var oMap = new GMap2(eMap);
		oMap.setCenter(new GLatLng(40, 60), 2, G_NORMAL_MAP);
		oMap.enableContinuousZoom();
		oMap.enableDoubleClickZoom();
		oMap.addControl(new GMapTypeControl());
		oMap.addControl(new GScaleControl());
		App.aListeners.push(GEvent.addDomListener(eMap, 'DOMMouseScroll', this.wheelZoom));
		App.aListeners.push(GEvent.addDomListener(eMap, 'mousewheel', this.wheelZoom));
		App.aListeners.push(GEvent.addListener(oMap, 'dragend', this.loadArea));
		App.aListeners.push(GEvent.addListener(oMap, 'zoomend', this.loadArea));
		App.aListeners.push(GEvent.addDomListener(document.locsearch.mapsearch, 'click', function() {
			if (this.value == Map.sFormText) {
				this.value = '';
			}
		}));
		App.aListeners.push(GEvent.addDomListener(document.locsearch.mapsearch, 'blur', function() {
			if (this.value == '') {
				this.value = Map.sFormText;
			}
		}));
		this.oMap = oMap;
		this.oGeoCode = new GClientGeocoder();
		Markers.init(200, 200);
		if (iPoiId) {
			Poi.openView(iPoiId);
		} else {
			this.loadArea();
		}
	},

	get: function() {
		return this.oMap;
	},

	geocode: function(sSearch) {
		this.oGeoCode.getLatLng(sSearch, function(oPoint) {
			if (oPoint) { Map.get().setCenter(oPoint, 11); }});
	},

	wheelZoom: function(e) {
		if (e.cancelable) e.preventDefault(); 
		(e.detail || -e.wheelDelta) < 0 ? Map.get().zoomIn() : Map.get().zoomOut();
		return false;
	},

	loadArea: function() {
		if (!Map.bLoading) {
			Map.bLoading = 1;
			setTimeout(function() {Map.doLoadArea()}, 750);
		}
	},

	doLoadArea: function() {
		Map.bLoading = 0;
		with (Map.get()) {
			var gBounds = getBounds();
			if (Map.oPBounds && Map.oPBounds == gBounds) return true;
			Map.oPBounds = gBounds;
			var sPars = 'a=gpb&b=' + gBounds.getSouthWest().toUrlValue() + ',' +
				gBounds.getNorthEast().toUrlValue();
			Server.request(sPars, Map.parseObjectList);
		}
	},

	parseObjectList: function(oXhr, oJson) {
		oJson.each(function(o) {
			Markers.add(o);
		});
		Markers.updateView(this.get().getBounds());
	},

	update: function() {
		Markers.clear();
		Map.loadArea();
	},

	initAddControl: function() {
		MapAddControl.prototype = new GControl();
		MapAddControl.prototype.initialize = function(oMap) {
			var eContainer = document.createElement('div');
			var eAdd = document.createElement('div');
			Element.addClassName(eAdd, 'add_control_normal');
			eContainer.appendChild(eAdd);
			GEvent.addDomListener(eAdd, 'click', function() { Poi.openAdd(); });
			oMap.getContainer().appendChild(eContainer);
			return eContainer;
		}
		MapAddControl.prototype.getDefaultPosition = function() {
			return new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(7, 7));
		}
	}

}

// authentication
var Auth = {

	trySessionSignin: function() {
		if (!Cookie.get('sess')) {
			return false;
		}
		Server.request('a=tss', Auth.handleSessionSignin);
		return true;
	},

	handleSessionSignin: function(oXhr, oJson) {
		if (oJson.result == 1) {
			User.setUid(oJson.uid);
/*
			if (oJson.ct && oJson.cn) {
				App.setLocation(oJson.ct + ', ' + oJson.cn);
			}
*/
		} else {
			Auth.tryCookieSignin();
		}
		App.refreshHeader();
		
	},

	tryCookieSignin: function() {
		if (!Cookie.get('puid') && !Cookie.get('pass')) {
			return false;
		}
		Server.request('a=tcs', Auth.handleSignin);
		return true;
	},

	signout: function() {
		Server.request('a=sou', function() {
			Cookie.remove('puid', '/');
			Cookie.remove('pass', '/');
			Cookie.remove('sess', '/');
			User.setUid();
			App.refreshHeader();
			Map.get().closeInfoWindow();
			Tabs.openHome();
			Map.update();
		});
	},

	openSignin: function() {
		Win.open('signin', 500, 300, function() {
			Field.focus($('email'));
		});
	},

	closeSignin: function() {
		Win.close('signin');
	},

	submitSignin: function(oButton) {
		if ($F('email') == '') {
			Win.displayError('Don\'t forget to enter an email address!');
			Field.focus($('email'));
			return false;
		}
		if ($F('pass') == '') {
			Win.displayError('Don\'t forget to enter a password!');
			Field.focus($('pass'));
			return false;
		}
		var sResponse = ($F('pass') != '') ? sha2($F('ch') + sha2($F('pass'))) : '';
		App.disableButton(oButton);
		Server.request('a=siu&u=' + encodeURIComponent($F('email')) + '&r=' + sResponse + '&m=' + encodeURIComponent($F('rm')), Auth.handleSignin);
		return false;
	},

	handleSignin: function(oXhr, oJson) {
		if (oJson.result == 1) {
			Auth.closeSignin();
			User.setUid(oJson.uid);
/*
			if (oJson.ct && oJson.cn) {
				App.setLocation(oJson.ct + ', ' + oJson.cn);
			}
*/
			Map.update();
		} else {
			App.enableButton();
			Win.displayError(oJson.msg);
		}
		App.refreshHeader();
	},

	openSignup: function() {
		Win.open('signup', 450, 380, function() {
			Field.focus($('dname'));
		});
	},

	closeSignup: function() {
		Win.close('signup');
	},

	submitSignup: function(oButton) {		
		if ($F('dname') == '') {
			Win.displayError('Don\'t forget to enter a screen name!');
			Field.focus($('dname'));
			return false;
		}
		if ($F('email') == '') {
			Win.displayError('Don\'t forget to enter an email address!');
			Field.focus($('email'));
			return false;
		}
		if ($F('pass1') == '' || $F('pass2') == '') {
			Win.displayError('Don\'t forget to enter a password twice!');
			Field.focus($('pass1'));
			return false;
		}
		if ($F('pass1') != $F('pass2')) {
			Win.displayError('The passwords you entered do not match :(');
			Field.focus($('pass1'));
			return false;
		}
		App.disableButton(oButton);
		Server.request('a=suu&n=' + encodeURIComponent($F('dname')) + '&e=' + encodeURIComponent($F('email')) + '&p1=' + sha2($F('pass1')) + '&p2=' + sha2($F('pass2')) + '&pl=' + String($F('pass1')).length, Auth.handleSignup);
		return true;
	},

	handleSignup: function(oXhr, oJson) {
		if (oJson.result == 0) {
			App.enableButton();
			Win.displayError(oJson.msg);
		} else {
			Auth.closeSignup();
			Auth.openActivate();
		}
	},

	openActivate: function() {
		Win.open('activate', 450, 250, function() {
			Field.focus($('uid'));
		});
	},

	closeActivate: function() {
		Win.close('activate');
	},

	submitActivation: function(oButton) {
		if ($F('uid') == '') {
			Win.displayError('Don\'t forget to enter the activation code we sent to your email address!');
			Field.focus($('uid'));
			return false;
		}
		App.disableButton(oButton);
		Server.request('a=aua&c=' + encodeURIComponent($F('uid')), Auth.handleActivate);
	},

	handleActivate: function(oXhr, oJson) {
		if (oJson.result == 0) {
			App.enableButton();
			Win.displayError(oJson.msg);
		} else {
			Auth.closeActivate();
			User.setUid(oJson.uid);
			App.refreshHeader();
		}
	},

	openLostPass: function() {
		Win.open('lost_pass', 450, 150, function() {
			Field.focus($('email'));
		});
	},

	closeLostPass: function() {
		Win.close('lost_pass');
	},

	submitLostPass: function(oButton) {
		if ($F('email') == '') {
			Win.displayError('Don\'t forget to enter an email address!');
			Field.focus($('email'));
			return false;
		}
		App.disableButton(oButton);
		Server.request('a=lp&u=' + encodeURIComponent($F('email')), Auth.handleLostPass);
	},

	handleLostPass: function(oXhr, oJson) {
		if (oJson.result == 0) {
			App.enableButton();
			Win.displayError(oJson.msg);
		} else {
			Auth.closeLostPass();
			Auth.openLostPassReset();
		}
	},

	openLostPassReset: function() {
		Win.open('lost_pass_reset', 450, 250, function() {
			Field.focus($('code'));
		});
	},

	closeLostPassReset: function() {
		Win.close('lost_pass_reset');
	},

	submitLostPassReset: function(oButton) {
		if ($F('code') == '') {
			Win.displayError('Don\'t forget to enter the lost password code!');
			Field.focus($('code'));
			return false;
		}
		if ($F('pass1') == '' || $F('pass2') == '') {
			Win.displayError('Don\'t forget to enter a password twice!');
			Field.focus($('pass1'));
			return false;
		}
		if ($F('pass1') != $F('pass2')) {
			Win.displayError('The passwords you entered do not match :(');
			Field.focus($('pass1'));
			return false;
		}
		App.disableButton(oButton);
		Server.request('a=lpr&c=' + encodeURIComponent($F('code')) + '&p1=' + sha2($F('pass1')) + '&p2=' + sha2($F('pass2')) + '&pl=' + String($F('pass1')).length, Auth.handleLostPassReset);
		return true;
	},

	handleLostPassReset: function(oXhr, oJson) {
		if (oJson.result == 0) {
			App.enableButton();
			Win.displayError(oJson.msg);
		} else {
			Auth.closeLostPassReset();
			Win.open('lost_pass_okay', 350, 150);
		}
	},

	submitLostPassResetPage: function(oButton) {
		if ($F('code') == '') {
			App.displayError('Don\'t forget to enter the lost password code!');
			Field.focus($('code'));
			return false;
		}
		if ($F('pass1') == '' || $F('pass2') == '') {
			App.displayError('Don\'t forget to enter a password twice!');
			Field.focus($('pass1'));
			return false;
		}
		if ($F('pass1') != $F('pass2')) {
			App.displayError('The passwords you entered do not match :(');
			Field.focus($('pass1'));
			return false;
		}
		App.disableButton(oButton);
		Server.request('a=lpr&c=' + encodeURIComponent($F('code')) + '&p1=' + sha2($F('pass1')) + '&p2=' + sha2($F('pass2')) + '&pl=' + String($F('pass1')).length, Auth.handleLostPassResetFromForm);
		return true;
	},

	handleLostPassResetFromForm: function(oXhr, oJson) {
		if (oJson.result == 0) {
			App.enableButton();
			App.displayError(oJson.msg);
		} else {
			Win.open('lost_pass_okay_from_form', 350, 120);
		}
	},

	closeLostPassOkay: function() {
		Win.close('lost_pass_okay');
	}

};

// user
var User = {

	iUid: null,

	getUid: function() {
		return this.iUid;
	},

	setUid: function(iUid) {
		if (!iUid) iUid = null;
		this.iUid = iUid;
	},

	openView: function(iUid) {
		Win.open('view_user', 450, 0, null, 'u=' + iUid);
	},

	closeView: function() {
		Win.close();
	},

	openEdit: function(iUid) {	
		Win.open('edit_user', 450, 0, function() {
			Field.focus($('dname'));
		}, 'u=' + iUid);
	},

	submitEdit: function(oButton) {
		if ($F('dname') == '') {
			Win.displayError('Don\'t forget to enter a screen name!');
			Field.focus($('dname'));
			return false;
		}
		App.disableButton(oButton);		
		Server.request('a=eeu&u=' + User.getUid() + '&n=' +  encodeURIComponent($F('dname')) + '&c=' + encodeURIComponent($F('country')) + '&ci=' + encodeURIComponent($F('city')) + '&g=' + $F('genders') + '&bd=' + $F('bdate_day') + '&bm=' + $F('bdate_month') + '&by=' + $F('bdate_year') + '&d=' + encodeURIComponent($F('desc')), User.handleEdit);
	},

	handleEdit: function(oXhr, oJson) {
		if (oJson.result == 1) {
			Win.close();
			Win.open('tip', 450, 0, null, 'm=3');
			App.getNavigation();
		} else {
			App.enableButton();
			Win.displayError(oJson.msg);
		}
	},

	closeEdit: function() {
		Win.close();
	},
	
	openSettings: function(iUid) {
		Win.open('settings', 450, 0, null, 'u=' + iUid);
	},

	closeSettings: function() {
		Win.close('settings');
	},

	openEmailSettings: function(iUid) {
		Win.open('email_settings', 450, 0, function() {
			Field.focus($('email'));
		}, 'u=' + iUid);
	},

	submitEmailSettings: function(oButton) {
		if ($F('email') == '') {
			Win.displayError('Don\'t forget to enter an email address!');
			Field.focus($('email'));
			return false;
		}
		if ($F('pass') == '') {
			Win.displayError('Don\'t forget to enter a password!');
			Field.focus($('pass'));
			return false;
		}
		App.disableButton(oButton);
		Server.request('a=ce&u=' + User.getUid() + '&e=' + encodeURIComponent($F('email')) + '&p=' + sha2($F('pass')), User.handleEmailSettings);
	},

	handleEmailSettings: function(oXhr, oJson) {
		if (oJson.result == 1) {
			Win.close();
			Win.open('tip', 450, 150, null, 'm=2');
		} else {
			App.enableButton();
			Win.displayError(oJson.msg);
		}
	},

	closeEmailSettings: function() {
		Win.close('email_settings');
	},

	openPasswordSettings: function(iUid) {
		Win.open('password_settings', 450, 0, function() {
			Field.focus($('opass'));
		}, 'u=' + iUid);
	},

	submitPasswordSettings: function(oButton) {
		if ($F('opass') == '') {
			Win.displayError('Don\'t forget to enter your old password!');
			Field.focus($('opass'));
			return false;
		}
		if ($F('pass1') == '' || $F('pass2') == '') {
			Win.displayError('Don\'t forget to enter a password twice!');
			Field.focus($('pass1'));
			return false;
		}
		if ($F('pass1') != $F('pass2')) {
			Win.displayError('The passwords you entered do not match :(');
			Field.focus($('pass1'));
			return false;
		}
		App.disableButton(oButton);
		Server.request('a=cp&u=' + User.getUid() + '&op=' +  sha2($F('opass')) + '&p1=' + sha2($F('pass1')) + '&p2=' + sha2($F('pass2')) + '&pl=' + String($F('pass1')).length, User.handlePasswordSettings);
		return false;
	},

	handlePasswordSettings: function(oXhr, oJson) {
		if (oJson.result == 1) {
			// TODO: normal message here also
			// Win.openClient('this is my title', 'successfully did something intereting!', 300, 100);
			// Win.displayError('Your password was successfully changed.');
			Win.close();
			Win.open('tip', 450, 0, null, 'm=1');
		} else {
			App.enableButton();
			Win.displayError(oJson.msg);
		}
	},

	closePasswordSettings: function() {
		Win.close('password_settings');
	}

};

// poi handling
var Poi = {

	iEditMarkerId: null,
	oEditGoogleMarker: null,
	oAddGoogleMarker: null,
	oMapChangedEvent: null,
	oMapZoomEvent: null,
	sEditMapType: null,
	iEditZoom: null,

	openAdd: function() {
		if (App.isStatus('idle')) {
			Tabs.select('manage');
			App.setStatus('add');

			Panel.open('create_poi', function() {

				var sText = App.msgMoving;
				var oMapCenter = Map.get().getBounds().getCenter();

				Poi.oAddGoogleMarker = new GMarker(new GLatLng(oMapCenter.lat(), oMapCenter.lng()), {draggable: true});
				Map.get().addOverlay(Poi.oAddGoogleMarker);
				Poi.oAddGoogleMarker.openInfoWindowHtml(sText, {maxWidth: 250});
				GEvent.addListener(Poi.oAddGoogleMarker, "dragstart", function() {
					Map.get().closeInfoWindow();
				});
				GEvent.addListener(Poi.oAddGoogleMarker, "dragend", function() {
					this.openInfoWindowHtml(sText, {maxWidth: 250});
				});		

				Poi.sEditMapType = Map.get().getCurrentMapType().getUrlArg();
				$('fmaptype').innerHTML = Map.get().getCurrentMapType().getName();
				Poi.oMapChangedEvent = GEvent.addListener(Map.get(), 'maptypechanged', function(){
					var oMapType = Map.get().getCurrentMapType();
					Poi.sEditMapType = oMapType.getUrlArg();
					$('fmaptype').innerHTML = oMapType.getName();
				}); 

				Poi.iEditZoom = Map.get().getZoom();
				$('fzoomlevel').innerHTML = Poi.iEditZoom;
				Poi.oMapZoomEvent = GEvent.addListener(Map.get(), 'zoomend', function(iOld, iNew){
					Poi.iEditZoom = iNew;
					$('fzoomlevel').innerHTML = iNew;
				});

				var oPoint = Poi.oAddGoogleMarker.getPoint();
				var fLat = oPoint.lat();
				var fLng = oPoint.lng();
				$('flocation').innerHTML = Utils.formatCoord(fLat, fLng);
				GEvent.addListener(Poi.oAddGoogleMarker, "drag", function() {
					var oPoint = this.getPoint();
					var fLat = oPoint.lat();
					var fLng = oPoint.lng();
					$('flocation').innerHTML = Utils.formatCoord(fLat, fLng);
				});

			}, 'u=' + User.getUid() + '&z=' + Map.get().getZoom() + '&m=' + Map.get().getCurrentMapType().getUrlArg());

		}
	},

	closeAdd: function() {
		GEvent.removeListener(Poi.oMapChangedEvent);
		GEvent.removeListener(Poi.oMapZoomEvent);
		GEvent.clearInstanceListeners(Poi.oAddGoogleMarker);
		Map.get().closeInfoWindow();
		Map.get().removeOverlay(Poi.oAddGoogleMarker);
		App.setStatus();
		Panel.close();
	},

	submitAdd: function(oButton) {
		if ($F('name') == '') {
			Panel.displayError('Don\'t forget to enter a name!');
			Field.focus($('name'));
			return false;
		}
		var oLatLng = this.oAddGoogleMarker.getPoint();
		var fLat = oLatLng.lat();
		var fLong = oLatLng.lng();
		var sPublic = $F('public') ? 'public' : 'private';
		App.disableButton(oButton);
		Server.request('a=cnp&u=' + User.getUid() + '&c=' + $F('category') + '&n=' + encodeURIComponent($F('name')) + '&d=' + encodeURIComponent($F('desc')) + '&t=' + encodeURIComponent($F('tags')) + '&la=' + fLat + '&lo=' + fLong + '&p=' + sPublic + '&z=' + Poi.iEditZoom + '&m=' + Poi.sEditMapType,  Poi.handleAdd);
	},

	handleAdd: function(oXhr, oJson) {
		if (oJson.result == 1) {
			App.setStatus();
			Panel.close();
			Map.get().setCenter(Poi.oAddGoogleMarker.getPoint());
			GEvent.removeListener(Poi.oMapChangedEvent);
			GEvent.removeListener(Poi.oMapZoomEvent);
			GEvent.clearInstanceListeners(Poi.oAddGoogleMarker);
			Map.get().closeInfoWindow();
			Map.get().removeOverlay(Poi.oAddGoogleMarker);
			Map.loadArea();
		} else {
			App.enableButton();
			Panel.displayError(oJson.msg);
		}
	},

	openView: function(iPoiId) {
		if (!Panel.exists()) return false;
		var oMarker = Markers.getById(iPoiId);
		if (!oMarker) {
			Server.request('a=gpd&p=' + iPoiId, function(oXhr, oJson) {
				Markers.add(oJson);
				Poi.openView(iPoiId);
			});
		}
		Panel.open('view_poi', function() {
			var oInfoWindow = Map.get().getInfoWindow();
			//alert(oInfoWindow.isHidden());
			if (oInfoWindow.isHidden()) {
				oMarker.oGMarker.openInfoWindowHtml(App.msgLoading);
				Server.request('a=ght&f=html&t=google_info_window&u=' + User.getUid() + '&p=' + iPoiId, function(oXhr) {
					oMarker.oGMarker.openInfoWindowHtml(oXhr.responseText, {maxWidth: 450});
				});
			}
			Markers.zoom(iPoiId, false);
		}, 'u=' + User.getUid() + '&p=' + iPoiId);
	},

	closeView: function() {
		(Tabs.getSelected() == 'home') ? Tabs.openHome() : Panel.close();
	},

	openEdit: function(iMarkerId) {
		if (App.isStatus('idle')) {
			Tabs.select('manage');
			App.setStatus('edit');
			Map.get().closeInfoWindow();

			sParms = 'u=' + User.getUid() + '&p=' + iMarkerId +
				'&z=' + Map.get().getZoom() + '&m=' + Map.get().getCurrentMapType().getUrlArg()
			Panel.open('edit_poi', function() {
				Poi.iEditMarkerId = iMarkerId;
				var sText = App.msgMoving;
				Poi.oEditGoogleMarker = Markers.getById(iMarkerId).oGMarker;
				Map.get().setCenter(Poi.oEditGoogleMarker.getPoint());
				GEvent.clearInstanceListeners(Poi.oEditGoogleMarker);
				Poi.oEditGoogleMarker.enableDragging();
				Poi.oEditGoogleMarker.openInfoWindowHtml(sText, {maxWidth: 250});
				GEvent.addListener(Poi.oEditGoogleMarker, "dragstart", function() {
					Map.get().closeInfoWindow();
				});
				GEvent.addListener(Poi.oEditGoogleMarker, "dragend", function() {
					this.openInfoWindowHtml(sText, {maxWidth: 250});
				});

				Poi.sEditMapType = Map.get().getCurrentMapType().getUrlArg();
				Poi.oMapChangedEvent = GEvent.addListener(Map.get(), 'maptypechanged', function(){
					var oMapType = Map.get().getCurrentMapType();
					Poi.sEditMapType = oMapType.getUrlArg();
					$('fmaptype').innerHTML = oMapType.getName();
				}); 

				Poi.iEditZoom = Map.get().getZoom();
				Poi.oMapZoomEvent = GEvent.addListener(Map.get(), 'zoomend', function(iOld, iNew){
					Poi.iEditZoom = iNew;
					$('fzoomlevel').innerHTML = iNew;
				});

				GEvent.addListener(Poi.oEditGoogleMarker, "drag", function() {
					var oPoint = this.getPoint();
					var fLat = oPoint.lat();
					var fLng = oPoint.lng();
					$('flocation').innerHTML = Utils.formatCoord(fLat, fLng);
				});

			}, sParms);
		}
	},

	submitEdit: function(oButton) {
		if ($F('name') == '') {
			Panel.displayError('Don\'t forget to enter a name!');
			Field.focus($('name'));
			return false;
		}
		var oLatLng = this.oEditGoogleMarker.getPoint();
		var fLat = oLatLng.lat();
		var fLong = oLatLng.lng();
		var sPublic = $F('public') ? 'public' : 'private';
		App.disableButton(oButton);
		Server.request('a=eep&i=' + this.iEditMarkerId + '&u=' + User.getUid() + '&c=' + $F('category') + '&n=' + encodeURIComponent($F('name')) + '&d=' + encodeURIComponent($F('desc')) + '&t=' + encodeURIComponent($F('tags')) + '&la=' + fLat + '&lo=' + fLong + '&p=' + sPublic + '&z=' + Poi.iEditZoom + '&m=' + Poi.sEditMapType, Poi.handleEdit);
	},

	handleEdit: function(oXhr, oJson) {
		if (oJson.result == 1) {
			App.setStatus();
			Panel.close();
			GEvent.removeListener(Poi.oMapChangedEvent);
			GEvent.removeListener(Poi.oMapZoomEvent);

			GEvent.clearInstanceListeners(Poi.oEditGoogleMarker);
			Poi.oEditGoogleMarker.disableDragging();
			var oMarker = Markers.getById(Poi.iEditMarkerId);
			Map.get().setCenter(oMarker.oGMarker.getPoint());
			Markers.removeById(Poi.iEditMarkerId);
			Map.loadArea();
		} else {
			App.enableButton();
			Panel.displayError(oJson.msg);
		}
	},

	closeEdit: function() {
		App.setStatus();
		Panel.close();
		GEvent.removeListener(Poi.oMapChangedEvent);
		GEvent.removeListener(Poi.oMapZoomEvent);

		GEvent.clearInstanceListeners(Poi.oEditGoogleMarker);
		Poi.oEditGoogleMarker.disableDragging();
		var oMarker = Markers.getById(Poi.iEditMarkerId);
		Markers.removeById(Poi.iEditMarkerId);
		Markers.add(oMarker);
		Map.get().setCenter(oMarker.oGMarker.getPoint());
	},

	openDelete: function(iPoiId) {
		App.oDeleteMarkerId = iPoiId;
		Win.open('delete_poi', 450, 250);
	},

	closeDelete: function() {
		App.oDeleteMarkerId = null;
		Win.close('delete_poi');
	},

	submitDelete: function(oButton) {
		App.disableButton(oButton);
		Server.request('a=dp&u=' + User.getUid() + '&p=' + App.oDeleteMarkerId, function() {
			Markers.removeById(App.oDeleteMarkerId);
			Poi.closeDelete();
			Panel.close();
		});
	},
	
	submitAddComment: function(oButton, iPoiId) {
		App.disableButton(oButton);
		Server.request('a=cpc&u=' + User.getUid() + '&p=' + iPoiId + '&c=' + encodeURIComponent($F('comment')), Poi.handleAddComment);
	},
	
	handleAddComment: function(oXhr, oJson) {
		if (oJson.result == 1) {
			
		} else {
			Panel.displayError(oJson.msg);
		}		
		App.enableButton();
	}

}

// marker handling
var Markers = {

	iMaxLength: 200,
	iMaxViewing: 50,
	aMarkers: null,

	init: function(iMaxLength, iMaxViewing) {
		this.iMaxLength = iMaxLength;
		this.iMaxViewing = iMaxViewing;
		this.aMarkers = [];
		this.aMarkerIds = [];
	},

	getLength: function() {
		return Markers.aMarkers.length;
	},

	getById: function(iMarkerId) {
		var iMarkersIdx = 0;
		var iLen = this.getLength();
		while (iMarkersIdx < iLen) {
			if (this.aMarkers[iMarkersIdx].poi == iMarkerId) break;
			iMarkersIdx++;
		}
		return (iMarkersIdx < iLen) ? this.aMarkers[iMarkersIdx] : null;
	},

	getByIndex: function(iMarkerIndex) {
		return Markers.aMarkers[iMarkerIndex];
	},

	isBuffered: function(poi) {
		return this.aMarkerIds[poi];
	},

	add: function(oMarker) {
		if (!this.isBuffered(oMarker.poi)) {
			var oGMarker = Markers.create(oMarker.poi, oMarker.lat, oMarker.lng);
			Map.get().addOverlay(oGMarker);
			oMarker.oGMarker = oGMarker;
			this.aMarkers.push(oMarker);
			this.aMarkerIds[oMarker.poi] = true;
			return oMarker;
		}
	},

	create: function(iPoiId, fLat, fLong) {
		var oGMarker = new GMarker(new GLatLng(fLat, fLong), {draggable: true});
		oGMarker.disableDragging();
		GEvent.addListener(oGMarker, 'click', function() {
			if (iPoiId > 0) {
				// TODO: add content caching...
				this.openInfoWindowHtml(App.msgLoading);
				Server.request('a=ght&f=html&t=google_info_window&u=' + User.getUid() + '&p=' + iPoiId, function(oXhr) {
					oGMarker.openInfoWindowHtml(oXhr.responseText, {maxWidth: 450});
				});
			}
		});
		return oGMarker;
	},

	removeByIndex: function(iMarkersIdx) {
		var oMarker = this.getByIndex(iMarkersIdx);
		this.aMarkers.splice(iMarkersIdx, 1);
		delete this.aMarkerIds[oMarker.poi];
		Map.get().removeOverlay(oMarker.oGMarker);
	},

	removeById: function(iMarkerId) {
		var iMarkersIdx = 0;
		var iLen = this.getLength();
		while (iMarkersIdx < iLen) {
			if (this.aMarkers[iMarkersIdx].poi == iMarkerId) break;
			iMarkersIdx++;
		}
		var oMarker = this.aMarkers[iMarkersIdx];
		this.aMarkers.splice(iMarkersIdx, 1);
		delete this.aMarkerIds[oMarker.poi];
		Map.get().removeOverlay(oMarker.oGMarker);
		Map.get().closeInfoWindow();
	},

	clear: function() {
		Map.get().closeInfoWindow();
		while (Markers.getLength() > 0) {
			Markers.removeByIndex(0);
		}
	},

	updateView: function(oBounds) {
		var i = 0;
		var iDiff = this.getLength() - this.iMaxLength;
		while (iDiff > 0) {
			if (!oBounds.contains(this.aMarkers[i++].oGMarker.getPoint())) {
				this.removeByIndex(i);
				iDiff--;
			}
		}
	},

	aMapTypes: {
		'm': G_NORMAL_MAP,
		'k': G_SATELLITE_MAP,
		'h': G_HYBRID_MAP
	},

	zoom: function(iPoiId, bOpenInfoWindow) {
		var oMarker = Markers.getById(iPoiId);
		if (oMarker) {
			Map.get().setCenter(new GLatLng(oMarker.lat, oMarker.lng), oMarker.zml, Markers.aMapTypes[oMarker.mpt]);
			if (bOpenInfoWindow != false) {
				oMarker.oGMarker.openInfoWindowHtml(App.msgLoading);
				Server.request('a=ght&f=html&t=google_info_window&u=' + User.getUid() + '&p=' + iPoiId, function(oXhr) {
					oMarker.oGMarker.openInfoWindowHtml(oXhr.responseText, {maxWidth: 450});
				});
			}
		} else {
			Server.request('a=gpd&p=' + iPoiId, function(oXhr, oJson) {
				Markers.add(oJson);
				Markers.zoom(iPoiId, bOpenInfoWindow);
			});
		}
	},

	details: function(iPoiId) {
		//Map.get().closeInfoWindow();
		Poi.openView(iPoiId);
		//Markers.zoom(iPoiId, true);
	}

};

// panel handling
var Panel = {

	open: function(sTpl, onCompleteFunc, sPars, iWidth) {
		if (!iWidth) iWidth = 350;
		$('panel').style.display = 'block';
		$('panel').style.width = iWidth + 'px';
		$('map').style.marginLeft = (iWidth + 20) + 'px';
		Map.get().checkResize();
		if (sTpl) {
			$('panel').innerHTML = App.msgLoading;
			App.getHtml(sTpl, 'panel', onCompleteFunc, sPars);
		}
	},

	close: function() {
		$('panel').style.display = 'none';
		$('map').style.marginLeft = '10px';
		Map.get().checkResize();
	},

	exists: function() {
		return $('panel');
	},

	displayError: function(msg) {
		Element.show('panel_error_msg');
		$('panel_error_msg').innerHTML = msg;
	}

};

var Tabs = {

	sSelectedTab: null,
	aTabs: null,

	init: function(sTab) {
		this.sSelectedTab = sTab;
		Tabs.aTabs = {
			'home': Tabs.openHome,
			'manage': Panel.close
		};
	},

	select: function(sTabId) {		
		Element.removeClassName($('tab_' + Tabs.sSelectedTab), 'selected');		
		Element.addClassName($('tab_' + sTabId), 'selected');
		Tabs.sSelectedTab = sTabId;
		Tabs.aTabs[sTabId]();
		$('tab_' + sTabId).blur();
	},

	deSelect: function(sTabId) {
		Element.removeClassName($('tab_' + Tabs.sSelectedTab), 'selected');
		if (Tabs.sSelectedTab == sTabId) Tabs.sSelectedTab = null;
	},

	getSelected: function() {
		return Tabs.sSelectedTab;
	} ,

	openHome: function() {
		Tabs.cancelState();
		Panel.open('panel_home');
	},

	cancelState: function() {
		switch (App.getStatus()) {
			case 'add':
				Poi.closeAdd();
				break;
			case 'edit':
				Poi.closeEdit();
				break;
		}
	}

};
