/**
 *                O$$$7$
 *          $7$$$$$$$$$
 *        $$$$$
 *       $$$
 *       $$8                                                7$$$$$8
 *       $$$        D$7$$$$$                                7    7$$$$N
 *       7$$        $    Z$$ Z                                       $$7
 *        $$              $ D$8                           O$$$$$7D   $$D
 *        $$$            $$ 7$$                 $  $   O7$ $$N  77$$$$$
 *        $$$        Z$$$$  $$  N       7$$  $ $    $$$N  7 7       $$$
 *         7$$$$$$$$$$$    7$$$$$$$$$$O7   8$$$$   7 O     $DO       $O
 *                         7$7      7$$ 77$   $      $N  7  7 D$$D  7$
 *                         $7         $$$8  8Z        8N   $
 *                        $$          $$$               7$
 *                        $$         8$$
 *                         7$$       $$7
 *                               O$$$$
 * 
 * Play Anywhere, Anytime. Gbanga is the mixed-reality mobile game where
 * you must take-over as many real-world bars to become the supreme Mafioso!
 *
 * Copyright (c) 2007-2010 Gbanga, Millform AG. All rights reserved.
 *
 * @author Matthias
 * @version 1
 * @platform Desktop IE/Opera/Firefox/Safari
 *
 * Disclaimer and licenses:
 * 
 * - ASCII art above was generated with glassgiant.com
 * - The Gbanga website uses OpenLayers, the Free Maps for the Web JavaScript Library, http://openlayers.org, http://svn.openlayers.org/trunk/openlayers/license.txt
 * - The Gbanga website uses jQuery: The Write Less, Do More, JavaScript Library, http://jquery.com, http://github.com/jquery/jquery/blob/master/MIT-LICENSE.txt
 * 
 */

j = jQuery.noConflict();

// initialize global root variable G for Gbanga
if (!window.G) {
	G = {};
}

G.isInitializing = true;

G.resizing = function() {
	var s = j("#sidebar");
	var f = j("#footer");
	var c = j("#closer");
	var h = f.offset().top - s.offset().top;
	if (h === 0) {
		s.height('auto');
	} else {
		s.height(h);
	}
	c.height(j(window).height() - c.offset().top);
	//G.checkOverflowInSidebar();	
};

G.initSidebar = function() {
	// measure platform-dependent scroll bar width
	var w1 = j('#sidebar')[0].clientWidth;
	j('#sidebar').css('overflow-y', 'scroll');
	var w2 = j('#sidebar')[0].clientWidth;
	var delta = w1 - w2;
	
	// resize styles for this scroll bar
	j('#closer').each(function(i, e) {
		j(e).css('right',
				(parseInt(j(e).css('right').replace('px', ''), 10) + delta) + 'px');
	});
	j('#sidebar').each(function(i, e) {
		// TRICK/BUG: WebKit (Chrome & Safari) substract the width of a scrollbar
		//            from the style-attribute 'width', so it needs to be added again (x2)
		j(e).css('width',
				(parseInt(j(e).css('width').replace('px', ''), 10) + delta * (j.browser.webkit ? 2 : 1) ) + 'px');
	});
	j('.column').each(function(i, e) {
		j(e).css('width',
				(parseInt(j(e).css('width').replace('px', ''), 10) - delta / 3 * 2) + 'px');
	});	
	j('#footer').each(function(i, e) {
		j(e).css('width',
				(parseInt(j(e).css('width').replace('px', ''), 10) + delta) + 'px');
	});
	j('#map').each(function(i, e) {
		j(e).css('right',
				(parseInt(j(e).css('right').replace('px', ''), 10) + delta) + 'px');
	});
};

G.defaultize = function(elements) {
	
	elements.unbind('focus').focus(function(event) {
		var t = j(this);
		var v = t.val();
		t.removeClass('defaulttext');
		if (v === t.attr('defaulttext') || v === '') {
			t.val('');
		}
	});
	var refreshStyle = function(event) {
		var t = j(this);
		var v = t.val();
		if (v === t.attr('defaulttext' || v === '') || t.val() === '') {
			t.addClass('defaulttext');
			t.val(t.attr('defaulttext'));
		} else {
			t.removeClass('defaulttext');
		}
	};
	
	elements.unbind('blur').blur(refreshStyle);
	elements.unbind('change').change(refreshStyle);
	
	elements.each(function(i, e) {
		var t = j(e);
		var v = t.val();
		if (v === t.attr('defaulttext' || v === '') || t.val() === '') {
			t.addClass('defaulttext');
			t.val(t.attr('defaulttext'));
		} else {
			t.removeClass('defaulttext');
		}
	});

};

G.initLinks = function() {
	// Set up handlers for the UI:
	
	G.defaultize(j('.defaulttext'));
	
	j('#closer').unbind('click').click(function(event) {
		event.preventDefault();
		
		if (j('#closer').hasClass('open')) {
			G.collapseSidebar();
		} else {
			G.restoreSidebar();
		}
	});
	
	j('#searchinput').unbind('keypress').keypress(function(event) {
		if (event.keyCode === 13) {
			event.preventDefault();
			//GbangaAPI.findOnMap(j("#search").val(),
			//	// success
			//	function(resp) {
			//		alert(resp);
			//	},
			//	// failure
			//	function() {
			//		
			//	}
			//	// omit complete event
			//);
			G.showPlayer(j("#searchinput").val());
		}
	});
	
	j('#logo').unbind('click').click(function(event) {
		event.preventDefault();
		G.History.home();	
	});
	
	j('#homeLink').unbind('click').click(function(event) {
		event.preventDefault();
		G.History.back();	
	});
		
	j('[href|=faq], [href=help], .faq').unbind('click').click(function(event) {
		event.preventDefault();
		G.showSidepanel("faq", undefined, this.hash);
	});
	
	j('[href=contact]').unbind('click').click(function(event) {
		event.preventDefault();
		G.showSidepanel("contact");
	});
	
	j('[href=games]').unbind('click').click(function(event) {
		event.preventDefault();
		G.showTotal("games", "games.php", "About our games", { width: Math.min(j(window).width() - 20, Math.max(j(window).width() * 0.7, 700)) } );
	});
	
	j('[href=company]').unbind('click').click(function(event) {
		event.preventDefault();
		G.showTotal("company", "company.php", "About the company Gbanga", { width: Math.min(j(window).width() - 20, Math.max(j(window).width() * 0.7, 700)) } );
	});
	
	j('[href=solutions]').unbind('click').click(function(event) {
		event.preventDefault();
		G.showTotal("solutions", "solutions.php", "Business solutions provided by Gbanga", { width: Math.min(j(window).width() - 20, Math.max(j(window).width() * 0.7, 700)) } );
	});
	
	j('[href=terms]').unbind('click').click(function(event) {
		event.preventDefault();
		G.showSidepanel("terms");
	});
	
	j('[href=status]').unbind('click').click(function(event) {
		event.preventDefault();
		G.showSidepanel("status", "status/?embedded");
	});
	
	j("#yourposition").html(G.params._region);
	
	j('.player').unbind('click').click(function(event) {
		event.preventDefault();
		var playername = j(this).attr('href');
		playername = playername.substring(playername.lastIndexOf("/") + 1);
		G.showPlayer(playername);
	});

	j('.cell').unbind('click').click(function(event) {
		event.preventDefault();
		var cellname = j(this).attr('href');
		cellname = cellname.substring(cellname.lastIndexOf("/") + 1);
		G.showCell(cellname);
	});
	
	var regFun = function(event) {
		event.preventDefault();
		G.checkIfUsernameTaken("#username", "#submit", "#usernameTaken");		
		G.checkPassword("#password", "#verify", "#submit", "#passwordsMatching");
		G.check("#cellphone", /^\s*(0{2}|\+)\d[\d\s]*$/, "#submit", "#cellphoneFormat", "Please provide the cell phone including the trailing country code such as +1 for the US or +41 for Switzerland.");
		G.check("#email", /^[_A-Za-z0-9\-\+]+(\.[_A-Za-z0-9\-\+]+)*@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)*(\.[A-Za-z]{2,6})$/, "#submit", "#emailFormat", "Please provide a valid email. This is used for password reminders, security information and thelike.");
		
		//j("#cellphone").blur( function() {
		//	if (j("#cellphone").val().replace('+', '00').trim().match("^0041")) {
		//		j.post("sclt.php", { m: j("#cellphone").val().replace('+', '00').trim() }, function(data) {
		//			j("#registeredatswisscomlabs").attr('checked', data === '1');
		//			if (data === '1') {
		//				j("#swisscomlabsStatus").removeClass('wrong ui-state-error');
		//				j("#swisscomlabsStatus").hide();
		//			} else {
		//				j("#swisscomlabsStatus").addClass('wrong ui-state-error');
		//				j("#swisscomlabsStatus").show();
		//			}
		//		});
		//	} else {
		//		j("#registeredatswisscomlabs").attr('checked', true);
		//		j("#swisscomlabsStatus").hide();
		//	}
		//});
		
		G.closeDialog("#login");
		G.closeDialog("#videoDialog");
		G.closeDialog("#signupError");
		G.closeDialog("#signupSuccess");
		
		if (j("#cellphone").val() === '') {
			j("#cellphone").val(G.params._predial);
		}
		G.dialog("#signup", "Registration", { width: 355 });
	};
	
	j('[href=register], [href=signup], [href=join], #gbangoos, #promo').unbind('click', regFun).click(regFun);
	
	j("[href=login]").unbind('click').click(function(event) {
		event.preventDefault();
		G.closeDialog("#signup");
		G.closeDialog("#videoDialog");
		G.closeDialog("#signupError");
		G.closeDialog("#signupSuccess");
		G.dialog("#login", "Sign in", { width: 355 });
	});
	
	j("#submit2").unbind('click').click(function(event) {
		event.preventDefault();
		G.closeDialog("#login");
		G.login(j('#username2').val(), j('#password2').val());
	});
	
	j("#welcome, .video, .plainenglishvideo, [href=plainenglish], [href=http://www.youtube.com/watch?v=d7UF3HMMeLw]").unbind('click').click(function(event) {
		event.preventDefault();
		G.dialog("#videoDialog", "Gbanga Famiglia in plain english", { width: 505 });
	});

	j("#welcome").unbind('mouseenter').mouseenter(function(event) {
		event.preventDefault();
		j(this).attr('src', 'img/hover_explanation.png');
	});
	
	j("#welcome").unbind('mouseleave').mouseleave(function(event) {
		event.preventDefault();
		j(this).attr('src', 'img/title.png');
	});
	
	j("#submit").unbind('click').click(function(event) {
		event.preventDefault();
		if (j(".wrong:visible").length > 0) {
			j(".wrong:visible").effect("shake", { times:3, distance:5, direction:"down" }, 100);
		// } else if (!j("#registeredatswisscomlabs").attr('checked')) {
			// j("#registeredatswisscomlabs").addClass("wrong");
			// j("#registeredatswisscomlabs").effect("shake", { times:3, distance:5, direction:"down" }, 100);
		} else if (j("#password").val().length === 0) {
			j("#password").addClass("wrong");
			// j("#password").effect("shake", { times:3, distance:5, direction:"down" }, 100);
		} else if (j("#verify").val().length === 0) {
			j("#verify").addClass("wrong");
			// j("#verify").effect("shake", { times:3, distance:5, direction:"down" }, 100);
		} else if (j("#cellphone").val().length === 0) {
			j("#cellphone").addClass("wrong");
			// j("#cellphone").effect("shake", { times:3, distance:5, direction:"down" }, 100);
		} else if (j("#email").val().length === 0) {
			j("#email").addClass("wrong");
			// j("#email").effect("shake", { times:3, distance:5, direction:"down" }, 100);
		} else if  (j("#model").val().length === 0) {
			j("#model").addClass("wrong");
			// j("#model").effect("shake", { times:3, distance:5, direction:"down" }, 100);
		} else {
			
			G.closeDialog("#signup");
			G.register(j("#username").val(),
					   j("#password").val(),
					   j("#cellphone").val(),
					   j("#email").val(),
					   j('#model')[0].options[j('#model')[0].selectedIndex].text, // j("#model").val(),
					   j("#language").val());
		}
	});
	
	j("#reminderSubmit").unbind('click').click(function(event) {
		event.preventDefault();
		G.closeDialog("#reminderForm");
		G.remindPassword(j("#reminderDestination").val());
	});
	
	j("[href=?remind]").unbind('click').click(function(event) {
		event.preventDefault();
		G.closeDialog("#signup");
		G.dialog("#reminderForm", "Request a reminder message");
	});

};

G.init = function() {
	
	if (G.params._country === 'US') {
		j(".appstore.button").hide();
	}
	
	G.initSidebar();
	
	G.resizing();
	
	j(window).resize(G.resizing);
	
	G.initLinks();
	
};

G.resumeOnLogin = function() {
	var n = G.Cookie.get('n', null);
	if (n !== null) {
		j('username2').val(n);
		var k = G.Cookie.get('k', null);
		if (k !== null) {
			G.resume(n, k, true);
			return true;
		}
	}
	return false;
};

G.initMap = function() {
    
	if (typeof(G.map) !== 'undefined') {
		return; // prevent doublicated initialization
	}
	
	var options = {
		controls: [
					new OpenLayers.Control.Navigation(),
					new OpenLayers.Control.PanZoomBar(),
					new OpenLayers.Control.Attribution(),
					new OpenLayers.Control.ScaleLine( { maxWidth: 162 } )
				   ],
		eventListeners: {
			"zoomend": G.onZoomEnd,
			"moveend": G.onMoveEnd,
			"movestart": G.onMoveStart
		},
		maxExtent: new OpenLayers.Bounds(-20037508,-20037508,20037508,20037508), 
		// maxExtent: new OpenLayers.Bounds(-20037508.3427892,-20037508.3427892,20037508.3427892,20037508.3427892),
		restrictedExtent: new OpenLayers.Bounds(-20037508.3427892,-20037508.3427892,20037508.3427892,20037508.3427892),
		numZoomLevels: 17, 
		maxResolution: 156543, 
		units:'m', 
		projection: new OpenLayers.Projection("EPSG:900913"),
		displayProjection: new OpenLayers.Projection("EPSG:4326")
	};
	
	G.map = new OpenLayers.Map('map', options);
	
	_backgroundLayer = new OpenLayers.Layer.TMS(
		"Gbanga background map", // thanks to OpenStreetMap and Mapnik
		"http://tile.gbanga.com/",
		{ numZoomLevels: 17,
		  displayOutsideMaxExtent: false,
		  type: 'png',
		  attribution: '&copy; Map data <a href="http://creativecommons.org/licenses/by-sa/2.0/" target="_blank">CC-By-Sa</a> 2010 <a href="http://www.openstreetmap.org/" target="_blank">OpenStreetMap</a> contributors',
		  getURL: function(bounds) {
				bounds = this.adjustBounds(bounds);
					var res = this.map.getResolution();
					var x = Math.round((bounds.left - this.maxExtent.left) / (res * this.tileSize.w));
					// Google-like tile schema http://trac.openlayers.org/wiki/UsingCustomTiles
					var y = Math.round((this.maxExtent.top - bounds.top) / (res * this.tileSize.h));
					var z = (this.serverResolutions !== 'undefined' && this.serverResolutions !== null) ? this.serverResolutions.indexOf(res) : this.map.getZoom();
					var limit = Math.pow(2, z);
					if (y < 0 || y >= limit) {
						return null;
					} else {
						var path = z + "/" + x + "/" + y + ".png";
						var url = this.url;
						// x = ((x % limit) + limit) % limit;
						if (url instanceof Array) {
							url = this.selectUrl(path, url);
						}
						return url + path;
					}
		 },
		 isBaseLayer:true,
		 buffer:1
		}
	);
	
	G.markers = new OpenLayers.Layer.Markers("Markers", {
		calculateInRange: function() { return true; }
	});
	
	OpenLayers.Util.onImageLoadError = function() {
		this.src = 'img/notgbanganized.png';
		// G.map.zoomTo(7);
	};
	
	//var symbolizer = OpenLayers.Util.applyDefaults(
	//	{ pointRadius: 20, fillOpacity: 1.0 },
	//	OpenLayers.Feature.Vector.style["default"]);
	
	var closeUpStyle = new OpenLayers.StyleMap( /* {"default": symbolizer} */ );
	// create a mapping between feature attribute and symbolizer
	var featureType = {
			1: { graphicWidth: 21, graphicHeight: 15, fillOpacity: 0.9, externalGraphic: "http://img." + document.location.host + "/${img}" } // CELL
			/*2: {fillColor: "red", strokeColor: "red", pointRadius: 30, externalGraphic: G.dynamicImageLocation + "${img}"}, // PLAYER
			3: {fillColor: "orange", strokeColor: "red", pointRadius: 20, externalGraphic: G.dynamicImageLocation + "${img}"}, // GBANGOO
			4: {fillColor: "yellow", strokeColor: "orange", pointRadius: 30, externalGraphic: G.dynamicImageLocation + "${img}"}, // QUEST
			5: {fillColor: "white", strokeColor: "lightgrey", pointRadius: 10}, // NEWS
			6: {fillColor: "lightgrey", strokeColor: "grey", externalGraphic: G.dynamicImageLocation + "${img}"}, // POINT_OF_INTEREST
			7: {fillColor: "grey", strokeColor: "black", pointRadius: 50}, // PHYSICAL_ADDRESS
			8: {fillColor: "grey", strokeColor: "black", pointRadius: 50}, // IP_ADDRESS
			9: {fillColor: "lightgrey", strokeColor: "grey", pointRadius: 5}, // TOWN
			209: { graphicWidth: 27, graphicHeight: 27, externalGraphic: G.dynamicImageLocation + '3038' } // ZOO KEEPER*/
	};

	// add rules to the default symbolizer that check for the "type"
	// attribute and apply the symbolizer defined in lookup
	closeUpStyle.addUniqueValueRules("default", "type", featureType);
	
	//G.closeUp = new OpenLayers.Layer.Vector("CloseUp", {
	//	attribution: 'game meta data by Gbanga',
	//	strategies: [ new OpenLayers.Strategy.BBOX() ],
	//	calculateInRange: function() { return true; },
	//	styleMap: closeUpStyle
	//});
	
//	OpenLayers.Protocol.GbangaHTTP = OpenLayers.Class(OpenLayers.Protocol.HTTP, {
//		url:"/api/",
//		params:{"m":"getMapTile"},
//		read: function(options) {
//			options = OpenLayers.Util.applyDefaults(options, this.options);
// 	        var resp = new OpenLayers.Protocol.Response({requestType: "read"});
// 	       
// 	        if(options.filter && options.filter instanceof OpenLayers.Filter.Spatial) {
// 	            if(options.filter.type == OpenLayers.Filter.Spatial.BBOX) {
//					var bbox = options.filter.value;
//					options.filter.value = bbox.clone().transform(G.map.displayProjection, G.map.getProjectionObject());
//					
// 	                options.params = OpenLayers.Util.extend(options.params, {
// 	                    bbox: options.filter.value.toArray()
// 	                });
// 	            }
// 	        }
// 	
// 	        resp.priv = OpenLayers.Request.GET({
// 	            url: options.url,
// 	            callback: this.createCallback(this.handleRead, resp, options),
// 	            params: options.params,
// 	            headers: options.headers
// 	        });       
// 	
// 	        return resp;
//		},
// 	    initialize: function(options) {
// 	        this.params = {};
// 	        this.headers = {};
// 	        OpenLayers.Protocol.prototype.initialize.apply(this, arguments);
// 	    },
//		format: new OpenLayers.Format.GeoJSON({
//			'internalProjection': G.map.getProjectionObject(), 
//			'externalProjection': G.map.displayProjection
//		}),
//		CLASS_NAME:"OpenLayers.Protocol.GbangaHTTP"
//	});

	
	// the Gbanga overlay layer with Gbanga world annotations
	G.closeUp = new OpenLayers.Layer.Vector("CloseUp", {
		attribution: 'game meta data by Gbanga',
//		strategies: [ new OpenLayers.Strategy.BBOX() ],
//		protocol: new OpenLayers.Protocol.GbangaHTTP({}),
		styleMap: closeUpStyle
	});
	
	//add the hover select control
	//var hoverSelect = new OpenLayers.Control.SelectFeature(G.closeUp, 
	//{clickout:true, hover:true, onSelect: tooltipSelect});
	//map.addControl(hoverSelect);
	//hoverSelect.activate();

	// G.closeUp.events.register("featureselected", G.closeUp, G.closeUpFeatureClicked);
	var control = new OpenLayers.Control.SelectFeature(G.closeUp, {
		onSelect: G.closeUpFeatureClicked,
		hover: false,
		clickout: false,
		stopDown: false,
		stopUp: false
	});
	G.map.addControl(control);
	control.activate();
	
	G.map.addLayers([_backgroundLayer, G.closeUp, G.markers]);
	
	G.geojsonReader = new OpenLayers.Format.GeoJSON({
		'internalProjection': G.map.getProjectionObject(), 
		'externalProjection': G.map.displayProjection
	});
	
	G.setMapCenter(new OpenLayers.LonLat(G.params._lon, G.params._lat), 11);
	
	var currentPosition = new OpenLayers.LonLat(G.params._lon, G.params._lat);
	
	G.markerHistory = [];
	var i, avatar, m;
	if (G.params._newbies) {
		for (i = 0; i < G.params._newbies.length; i++) {
			var newbie = G.params._newbies[i];
			var newbie_pos = new OpenLayers.LonLat(newbie.lon, newbie.lat);
			avatar = new OpenLayers.Icon(newbie.avatar, new OpenLayers.Size(18,18), new OpenLayers.Pixel(-9,-9), undefined);
			m = G.addMarkerToMap(newbie_pos, avatar, "Latest player " + newbie.username, "<p><a class=\"player\" target=\"_blank\" href=\"/who/" + newbie.username + "\"><img width=\"18\" height=\"18\" border=\"0\" src=\"" + newbie.avatar + "\"> " + newbie.username + "</a> just signed up to Gbanga near <em>" + newbie.near + "</em>. Check out <a class=\"player\" target=\"_blank\" href=\"/who/" + newbie.username + "\"> " + newbie.username + "</a>'s profile to make friends or become their Gbanga Famiglia archrival</p><hr><p>This map shows the participant's activity in Gbanga, a mixed-reality mobile game where you must take-over real-world bars to become the supreme Mafioso. <a href=\"register\">Register here</a> to join the fun and watch the <a target=\"_blank\" href=\"plainenglish\">video</a>!</p>", false);
			m.display(false);
			G.markerHistory[G.markerHistory.length] = m;
		}
	}
	if (G.params._shouts) {
		for (i = 0; i < G.params._shouts.length; i++) {
			var shout = G.params._shouts[i];
			var shout_pos = new OpenLayers.LonLat(shout.lon, shout.lat);
			avatar = new OpenLayers.Icon(shout.flag, new OpenLayers.Size(21,15), new OpenLayers.Pixel(-10,-8), undefined);
			m = G.addMarkerToMap(shout_pos, avatar, "<p>Shout at " + shout.cell, "<a class=\"player\" target=\"_blank\" href=\"/who/" + shout.username + "\"><img width=\"18\" height=\"18\" border=\"0\" src=\"" + shout.avatar + "\"> " + shout.username + "</a> just shouted in Cell <a href=\"/where/" + shout.cell + "\" class=\"cell\"><img width=\"21\" height=\"15\" border=\"0\" src=\"" + shout.flag + "\"> " + shout.cell + "</a> near <em>" + shout.near + "</em>: <em>&quot;" + shout.message + "&quot;</em>.</p><hr><p><em>A Gbanga Shout is like broadcasting a chat message to a remote location within the Gbanga world.</em></p><hr><p>This map shows the participant's activity in Gbanga, a mixed-reality mobile game where you must take-over real-world bars to become the supreme Mafioso. <a href=\"register\">Register here</a> to join the fun and watch the <a target=\"_blank\" href=\"plainenglish\">video</a>!</p>", false);
			m.display(false);
			G.markerHistory[G.markerHistory.length] = m;
		}
	}
	if (G.params._discoveries) {
		for (i = 0; i < G.params._discoveries.length; i++) {
			var disc = G.params._discoveries[i];
			var disc_pos = new OpenLayers.LonLat(disc.lon, disc.lat);
			avatar = new OpenLayers.Icon(disc.flag, new OpenLayers.Size(21,15), new OpenLayers.Pixel(-10,-8), undefined);
			m = G.addMarkerToMap(disc_pos, avatar, disc.cell + " discovered!", "<p><a class=\"player\" target=\"_blank\" href=\"/who/" + disc.username + "\"><img width=\"18\" height=\"18\" border=\"0\" src=\"" + disc.avatar + "\"> " + disc.username + "</a> just discovered <a href=\"/where/" + disc.cell + "\" class=\"cell\"><img width=\"21\" height=\"15\" border=\"0\" src=\"" + disc.flag + "\"> " + disc.cell + "</a> near <em>" + disc.near + "</em>.</p><hr><p><em>" + disc.username + " is the first to visit this location and score points!</em></p><hr><p>This map shows the participant's activity in Gbanga, a mixed-reality mobile game where you must take-over real-world bars to become the supreme Mafioso. <a href=\"register\">Register here</a> to join the fun and watch the <a target=\"_blank\" href=\"plainenglish\">video</a>!</p>", false);
			m.display(false);
			G.markerHistory[G.markerHistory.length] = m;
		}
	}
	
	// G.currentMarker = G.addMarkerToMap(currentPosition, null, G.params._region + ", " + G.params._country, "<a title=\"Register for Gbanga\" target=\"_blank\" href=\"register\">Start ruling your hood</a> " + G.params._region + " with the mobile game Gbanga", true);
	// G.markerHistory[G.markerHistory.length] = G.currentMarker;
	
	//j('#yourposition').click( function(event) {
	//	event.preventDefault();
	//	G.setMapCenter(currentPosition);
	//	G.currentMarker.events.triggerEvent("click");
	//});
	
	G.map.events.register("mousedown", G.map, function(event) { G.Marquee.stop(); } );
	G.closeUp.events.register("mousedown", G.closeUp, function(event) { G.Marquee.stop(); } );
	G.markers.events.register("mousedown", G.markers, function(event) { G.Marquee.stop(); } );
	
	/*j('.player').each(function(i,e) {
		j(e).click(function(event) {
			event.preventDefault();
		});
	});*/
	
	// Gbarnga secret labs
	G.markerLabs = G.addMarkerToMap(new OpenLayers.LonLat(-9.4630144681742, 7.0117538748366), "img/gbarnga.png", "Gbarnga, Liberia, Africa", "Very very very secret <a href=\"http://labs.gbanga.com/\" target=\"_blank\">Gbanga labs</a> facilities.", false);
	// Don Viktor
	// G.markerDonViktor = G.addMarkerToMap(new OpenLayers.LonLat(23.35977, 45.437605), "img/donviktor.png", "Transilvania, Romania", "<a href=\"/who/DonViktor\" class=\"player\" target=\"_blank\">Don Victor</a> is fed up with his life as a gangster. Check out his <a href=\"http://picasaweb.google.com/101770291314871913994/\" target=\"_blank\">travel photos</a>.", false);
	// Crispy Carl
	// G.markerCrispyCarl = G.addMarkerToMap(new OpenLayers.LonLat(135.206,34.690), "img/crispycarl.png", "K&#333;be, Japan", "<a href=\"/who/CrispyCarl\" class=\"player\" target=\"_blank\">Crispy Carl</a> is hungry...", false);
	// Alka-Pony
	// G.markerAlkaPony = G.addMarkerToMap(new OpenLayers.LonLat(27.080,69.895), "img/alkapony.png", "Utsjoki, Finland", "<a href=\"/who/AlkaPony\" class=\"player\" target=\"_blank\">Alka-Pony</a> is scared...", false);
	// Bone Cracker
	// G.markerBoneCracker = G.addMarkerToMap(new OpenLayers.LonLat(37.627, 55.7575), "img/nutcracker.png", "Moscow, Russia", "<a href=\"/who/BoneCracker\" class=\"player\" target=\"_blank\">Bone Cracker</a> is angry...", false);
	// Leonardo
	// G.markerLeonardo = G.addMarkerToMap(new OpenLayers.LonLat(-43.2066,-22.8975), "img/leonardo.png", "Rio De Janeiro, Brazil", "<a href=\"/who/Leonardo\" class=\"player\" target=\"_blank\">Leonardo</a> is intimidated...", false);
	// Valentino
	// G.markerValentino = G.addMarkerToMap(new OpenLayers.LonLat(-74.0047,40.7224), "img/valentino.png", "New York, US", "<a href=\"/who/Valentino\" class=\"player\" target=\"_blank\">Valentino</a> is observing...", false);
	
	G.Marquee.start();
	
};

G.Marquee = {
	
	AUTO_MOVE_INTERVAL: 12000, // in millis
	running: false, // is running?
	i: 0, // cursor
	processing: false,
	start: function() {
		if (!G.Marquee.running) {
			G.Marquee.running = true;
			G.Marquee.___runner();
			// window.setTimeout(G.Marquee.___runner, G.Marquee.AUTO_MOVE_INTERVAL);
		}
	},
	___runner: function() {
		if (G.Marquee.running && G.markerHistory.length > 0) {
			G.Marquee.processing = true;
			
			if (G.Marquee.i > -1 && G.Marquee.i < G.markerHistory.length) {
				G.markerHistory[G.Marquee.i].display(false);
			}
			// increment cursor
			G.Marquee.i++;
			G.Marquee.i %= G.markerHistory.length;
			
			G.markerHistory[G.Marquee.i].events.triggerEvent("click");
			G.markerHistory[G.Marquee.i].display(true);
			
			window.setTimeout(G.Marquee.___runner, G.Marquee.AUTO_MOVE_INTERVAL);
			
			G.Marquee.processing = false;
			
		}
	},
	stop: function() {
		if (!G.Marquee.processing) {
			// debugger;
			G.Marquee.running = false;
		}
		// G.Marquee.processing = false;
	},
	hide: function() {
		if (!G.Marquee.processing && G.markerHistory && G.markerHistory.length >= G.Marquee.i) {
			G.markerHistory[G.Marquee.i].display(false);
			if (G.markerHistory[G.Marquee.i]._popup && G.markerHistory[G.Marquee.i]._popup !== null) {
				var tmp = G.markerHistory[G.Marquee.i]._popup;
				G.markerHistory[G.Marquee.i]._popup = null;
				tmp.hide();
				tmp.destroy();
			}
		}
	}

};

G.closeUpFeatureClicked = function(feature) {
	// alert(feature);
	// G.test = feature;
	if (feature && feature.fid) {
		var fid = feature.fid;
		var cellname = fid.substring(5);
		G.showCell(cellname);
	}
};

G.onMoveStart = function(event) {
	G.Marquee.stop();
};

G.onMoveEnd = function(event) {
	if (G.map.zoom === 16) {
		var ext = G.getMapExtent();
		G.getMapTile(ext.top, ext.left, ext.bottom, ext.right);
		G.closeUp.setVisibility(true);
	} else {
		G.closeUp.setVisibility(false);
	}
};

G.onZoomEnd = function(event) {
	if (G.markerLabs) {
		G.markerLabs.display(G.map.getZoom() > 12);
	}
	G.Marquee.stop();
};

G.addMarkerToMap = function(position, icon, title, description, showPopup, showMultiple) {
	
	if (icon === null|| icon === 'undefined') {
		var i = Math.floor(Math.random() * 3) + 1;
		icon = new OpenLayers.Icon("img/spot_small" + i + ".png", new OpenLayers.Size(25,16), new OpenLayers.Pixel(0,0), undefined);
	} else if (typeof(icon) === 'string') {
		icon = new OpenLayers.Icon(icon, new OpenLayers.Size(48,48), new OpenLayers.Pixel(-24,-24), undefined);
	}
	
	var marker = new OpenLayers.Marker(position.clone().transform(G.map.displayProjection, G.map.getProjectionObject()), icon);
	
	G.markers.addMarker(marker);
	
	if (description) {
		marker.events.register("click", marker, function () {
			G.showPopup(marker, "<h1>" + title + "</h1><p>" + description + "</p>", showMultiple, true);
		} );
	}
	
	if (showPopup === true) {
		G.showPopup(marker, "<h1>" + title + "</h1><p>" + description + "</p>", showMultiple, true);
	}
	
	return marker;
};

G.showPopup = function(marker, text, showMultiple, pan) {

	if (!showMultiple) {
		G.closeAllPopups();
	}
	
	var popup = new OpenLayers.Popup.AnchoredBubble(
		"popup",
		marker.lonlat,
		null,
		text,
		marker.icon,
		true,
		undefined);
	
	marker._popup = popup;
	
	popup.minSize = new OpenLayers.Size(G.map.size.w / 2.5, 0.0);
	popup.maxSize = new OpenLayers.Size(G.map.size.w / 2.2, G.map.size.h / 2.2);
	popup.panMapIfOutOfView = true;
	popup.autoSize = true;
	G.map.addPopup(popup);
	popup.updateSize();
	if (pan) {
		G.map.panTo(marker.lonlat);
	} else {
		G.map.setCenter(marker.lonlat, G.map.zoom);
	}
	G.initLinks();
	
};

G.closeAllPopups = function() {
	var popups = G.map.popups;
	if (popups && popups.length > 0) {
		j(popups).each(function(i, p) {
			G.map.removePopup(p);
			p.destroy();
		});
	}
};

G.removeMarkerFromMap = function(marker) {
	G.markers.removeMarker(marker);
	if (marker._popup && typeof(marker._popup) !== 'undefined') {
		G.map.removePopup(marker._popup);
	}
};

G.getMapCenter = function() {
	return G.map.getCenter().clone().transform(map.getProjectionObject(), G.map.displayProjection);
};

G.setMapCenter = function(center, zoom) {
	if (zoom && typeof(zoom) !== 'undefined') {
		zoom = parseInt(zoom, 10);
		var numzoom = G.map.getNumZoomLevels();
		if (zoom >= numzoom) {
			zoom = numzoom - 1;
		}
	} else {
		zoom = G.map.zoom;
	}
	G.map.setCenter(center.clone().transform(G.map.displayProjection, G.map.getProjectionObject()), zoom); 
};

G.setMapExtent = function(extent) {
	G.map.zoomToExtent(extent.clone().transform(G.map.displayProjection, G.map.getProjectionObject()));
};

G.getMapExtent = function() {
	return G.map.getExtent().clone().transform(G.map.getProjectionObject(), G.map.displayProjection);
};

G.getMapZoom = function() {
	return G.map.getZoom();
};

G.hideAllPanels = function() {
	j("#home").hide();
	// j("#column1").children().each(function(i,e) { j(e).hide() });
	// j("#column2").children().each(function(i,e) { j(e).hide() });
	// j("#column1, #column2").show();
	var items = j("#sidebar > :visible");
	if (items.length > 1) {
		items.last().hide();
	}
};

G.hidePanelsFiltered = function(filter) {
	j("#column1").children().filter(filter).each(function(i,e) { j(e).hide(); });
	j("#column2").children().filter(filter).each(function(i,e) { j(e).hide(); });
};

G.showTotal = function(elementName, optionalFilename, title, additionalParams) {
	var titleBefore = document.title;
	document.title = title;
	G.History.add("Popup " + elementName, G.showTotal, elementName, optionalFilename, title, additionalParams);
	G.collapseSidebar();
	j("#" + elementName).html('<div class="loader"><img src="img/loader.gif" height="32" width="32" border="0" alt="Loading..."></div>');
	if (optionalFilename !== undefined) {
		j("#" + elementName).load(optionalFilename, G.initLinks);
	} else {
		j("#" + elementName).load(elementName + ".part", G.initLinks);
	}
	var w = j(window).width() * 0.7;
	var h = j(window).height() * 0.7;
	additionalParams = j.extend( { width:w, height:h, close: function(event, ui) { j("#" + elementName).dialog("destroy"); document.title = titleBefore; G.restoreSidebar(); } }, additionalParams );
	G.dialog("#" + elementName, title, additionalParams);
};

G.showSidepanel = function(elementName, optionalFilename, hash) {
	G.History.add("Sidepanel " + elementName, G.showSidepanel, elementName, optionalFilename, hash);
	//if (j("#" + elementName + ":visible").length === 0 || typeof(optionalFilename) !== 'undefined') {
	//	G.hideAllPanels();
	//	j("#" + elementName).html('<div class="loader"><img src="img/loader.gif" height="32" width="32" border="0" alt="Loading..."></div>');
	//	if (optionalFilename !== undefined) {
	//		j("#" + elementName).load(optionalFilename, G.initLinks);
	//	} else {
	//		j("#" + elementName).load(elementName + ".part", G.initLinks);
	//	}
	//	j("#" + elementName).show();
	//}
	// if (typeof(optionalFilename) !== 'undefined') {
		G.hideAllPanels();
		G.closeDialog();
		j("#sidecontent").html('<div class="loader"><img src="img/loader.gif" height="32" width="32" border="0" alt="Loading..."></div>');
		
		var after_fun = function() {
			G.initLinks();
			if (hash && typeof(hash) !== 'undefined' && hash.length > 1) {
				var q = j("[name~=" + hash.substring(1) + "]");
				q.addClass('highlight');
				j("#sidebar").scrollTop(q.offset().top - 100);
				if (elementName === 'faq') {
					var b = j("#toPreviousScreen");
					b.unbind('click').click(function(event) {
						event.preventDefault();
						j("#homeLink").click();
					});
					q.append(b);
				}
			}
		}
		
		if (optionalFilename !== undefined) {
			j("#sidecontent").load(optionalFilename, after_fun);
		} else {
			j("#sidecontent").load(elementName + ".part", after_fun);
		}
		j("#sidecontent").show();
	// }
	G.restoreSidebar();
};

G.showCell = function(screenname) {
	G.History.add("Cell " + screenname, G.showCell, screenname);
	// alert(username);
	if (screenname.indexOf('/') > -1) {
		screenname = screenname.substring(screenname.lastIndexOf('/') + 1);
	}
	// if (j("#player:visible").length === 0) {
	G.hideAllPanels();
	G.closeDialog();
	j("#entity").html('<div class="loader"><img src="img/loader.gif" height="32" width="32" border="0" alt="Loading..."></div>');
	j("#entity").load("cell.php?cellname=" + screenname, function() {
		G.Marquee.stop();
		G.currentCellProfile = screenname;
		G.initLinks();
	});
	j("#entity").show();
	// }
	G.restoreSidebar();
};

G.currentSidebar = null;
G.lastSidebar = null;

G.showPlayer = function(username) {
	G.History.add("Player " + username, G.showPlayer, username);
	// alert(username);
	if (username.indexOf("mailto:") === 0) {
		window.location = username;
	} else {
		if (username.indexOf('/') > -1) {
			username = username.substring(username.lastIndexOf('/') + 1);
		}
		// if (j("#player:visible").length === 0) {
		G.closeDialog();
		G.hideAllPanels();
		j("#entity").html('<div class="loader"><img src="img/loader.gif" height="32" width="32" border="0" alt="Loading..."></div>');
		j("#entity").load("player.php?username=" + username, function() {
			j("#searchinput").val("").change();
			G.Marquee.stop();
			G.currentPlayerProfile = username;
			G.initLinks();
			// check if logged in
			if (G.session && G.session.player) {
				// check if self
				if (G.session.player.name === username) {
					var pa = j("#playeravatar");
					var img = pa.attr('src');
					pa.attr('src', 'img/editavataroverlay.png');
					pa.attr('hiddenurl', img);
					pa.css('background', 'url(' + img + ') transparent no-repeat center center');
					pa.css('cursor', 'pointer');
					pa.unbind('click').click(function(event) {
						event.preventDefault();
						j("#avatarUploadP0").val(G.session.key);
						
						j("#cancelUpload").unbind('click').click(function(event) {
							event.preventDefault();
							G.closeDialog('#upload');
						});
						j("#avatarUploadP1").unbind('change').change(function(event) {
							j("#submitAvatarUpload").show();
						});
						
						j("#avatarUploadIFrame").unbind('load').load(function(event) {
							window.setTimeout(function() {
								var pa = j("#playeravatar");
								var img = pa.attr('hiddenurl');
								pa.css('background', 'url(' + img + '?' + (new Date().getTime()) + ') transparent no-repeat center center');
								window.setTimeout(function() {
									var pa = j("#playeravatar");
									var img = pa.attr('hiddenurl');
									pa.css('background', 'url(' + img + '?' + (new Date().getTime()) + ') transparent no-repeat center center');
								}, 1000);
							}, 1000);
						});
						
						j("#submitAvatarUpload").unbind('click').click(function(event) {
							event.preventDefault();
							j("#avatarUpload").submit();
							G.closeDialog('#upload');
							G.dialog('#uploadProgressFeedback', 'Upload in progress...');
							j("#playeravatar").css('background', 'transparent');
						});	
						G.dialog('#upload', "Change your profile picture");
					});
					
					j('input#statusedit').val(j("p#status").text());
					j('input#statusedit').change();
					j('input#cellphone').val(G.session.player.cellPhone);
					j('input#cellphone').change();
					j('input#email').val(G.session.player.email);
					j('input#email').change();
					j('input#twitter').val(G.session.player.twitter);
					j('input#twitter').change();
					j('input#everybodyCanSeeMyPosition').attr('checked', G.session.everybodyCanSeeMyPosition && G.session.friendsCanSeeMyPosition);
					j('input#friendsCanSeeMyPosition').attr('checked', G.session.friendsCanSeeMyPosition && !G.session.everybodyCanSeeMyPosition);
					j('input#nobodyCanSeeMyPosition').attr('checked', !G.session.everybodyCanSeeMyPosition && !G.session.friendsCanSeeMyPosition);
					
					j('input#notifyBySMS').attr('checked', G.session.notifyBySMS);
					j('input#notifyByEmail').attr('checked', G.session.notifyByEmail);
					j('input#model').val(G.session.player.device);
					j('input#model').change();
					
					var f = function(event) {
						var s = j('input#statusedit').val();
						if (s !== G.session.player.status) {
							j("input#statusedit").attr("disabled", true); 
							j('span#status').html("<em>Status is updated...</em>");
							G.updateStatus(G.session.key, s);
						}
					};
					j('input#statusedit').unbind('blur').blur(f);
					j('input#statusedit').unbind('keyup').keyup(function(event) {
						if (event.keyCode === 13) {
							f(event);
						}
					});
					
					var f2 = function(event) {
						if (!/^\s*(0{2}|\+)\d[\d\s]*$/.test(j('#cellphone').val()) || j('#cellphone').val() === j('#cellphone').attr('defaulttext')) {
							j('#cellphone').val(G.session.player.cellPhone);
						}								
						if (!/^[_a-z0-9\-]+(\.[_a-z0-9\-]+)*@[a-z0-9\-]+(\.[a-z0-9\-]+)*(\.[a-z]{2,6})$/.test(j('#email').val()) || j('#email').val() === j('#email').attr('defaulttext')) {
							j('#email').val(G.session.player.email);
						}
						if (j('#twitter').val() === j('#twitter').attr('defaulttext')) {
							// empty is okay
							// j('#twitter').val(G.session.player.twitter);
						}
						
						var processing = false;
						
						if (j('#cellphone').val() !== G.session.player.cellPhone || j('#email').val() !== G.session.player.email || j('#twitter').val() !== G.session.player.twitter) {
							
							processing = true;
						
							G.updateProfile(G.session.key,
											j('#cellphone').val(),
											j('#email').val(),
											j('#twitter').val(),
											G.session.player.twitterPassword,
											G.session.player.facebook);
						}
						
						if (j('input#everybodyCanSeeMyPosition').attr('checked') !== G.session.everybodyCanSeeMyPosition || j('input#friendsCanSeeMyPosition').attr('checked') !== (G.session.friendsCanSeeMyPosition && !G.session.everybodyCanSeeMyPosition) || j('input#nobodyCanSeeMyPosition').attr('checked') !== (!G.session.everybodyCanSeeMyPosition && !G.session.friendsCanSeeMyPosition) || j('input#notifyBySMS').attr('checked') !==  G.session.notifyBySMS || j('input#notifyByEmail').attr('checked') !== G.session.notifyByEmail) {
							
							processing = true;
							
							G.changeSettings(G.session.key,
											 j('input#friendsCanSeeMyPosition').attr('checked'),
											 j('input#everybodyCanSeeMyPosition').attr('checked'),
											 j('input#notifyBySMS').attr('checked'),
											 j('input#notifyByEmail').attr('checked'));
							
						}
						
						if (processing) {
							j('input#changeProfile').hide();
							j('#processingProfile').show();
						}
						
					};
					
					j('input#changeProfile').unbind('click').click(f2);
					
					j("#profile").show();
					
					//
					//var ps = j("span#status");
					//
					//var statusField = j(document.createElement("input"));
					//statusField.attr('type', 'text');
					//statusField.attr('defaulttext', 'your current status');
					//G.defaultize(statusField);
					//statusField.val(ps.text());
					//ps.after(statusField);
					//ps.remove();
					//statusField.attr('id', 'status');

					//
					//var cellphoneField = j(document.createElement("input"));
					//cellphoneField.attr('type', 'text');
					//cellphoneField.attr('defaulttext', 'your phone number');
					//G.defaultize(cellphoneField);
					//cellphoneField.val(G.session.player.cellPhone);
					//cellphoneField.attr('id', 'cellphone');
					//statusField.after(cellphoneField);
					//var f2 = function(event) {
					//	 TODO
					//};
					//cellphoneField.unbind('change');
					//cellphoneField.change(f2);
					//
					//var emailField = j(document.createElement("input"));
					//emailField.attr('type', 'text');
					//emailField.attr('defaulttext', 'your email address');
					//G.defaultize(emailField);
					//if (G.session.player.email !== '') {
					//	emailField.val(G.session.player.email);
					//}
					//emailField.attr('id', 'email');
					//cellphoneField.after(emailField);
					//emailField.unbind('change');
					//emailField.change(f2);
					//
					//var twitterField = j(document.createElement("input"));
					//twitterField.attr('type', 'text');
					//twitterField.attr('defaulttext', 'your Twitter name');
					//G.defaultize(twitterField);
					//if (G.session.player.twitter !== '') {
					//	twitterField.val(G.session.player.twitter);
					//}
					//twitterField.attr('id', 'twitter');
					//emailField.after(twitterField);
					//twitterField.unbind('change');
					//twitterField.change(f2);
					
				// other player, but active session
				} else {
					
					j("#addAsFriend").show();
					var isFriend = false;
					j.each(G.session.friends, function(index, value) {
						if (value.name.toLowerCase() === G.currentPlayerProfile.toLowerCase()) {
							isFriend = true;
						}
					});
					var pendingFriend = false;
					if (typeof(G.pendingFriends) === 'undefined') {
						G.pendingFriends = [];
					}
					j.each(G.pendingFriends, function(index, value) {
						if (value.toLowerCase() === G.currentPlayerProfile.toLowerCase()) {
							pendingFriend = true;
						}
					});
					if (isFriend) {
						j("#addAsFriend").html("<em>Is your friend</em>");
					} else if (pendingFriend) {
						j("#addAsFriend").html("<em>Pending friends request</em>");
					} else {
						j("#addAsFriend").children(":first").unbind('click');
						j("#addAsFriend").children(":first").bind('click', function(event) {
							event.preventDefault();
							G.offerFriendship(G.session.key, G.currentPlayerProfile, "Hello");
							j("#addAsFriend").html("<em>Pending friends request</em>");
							G.pendingFriends[G.pendingFriends.length] = G.currentPlayerProfile;
						});
					}
				}
			}
		});
		j("#entity").show();
		G.lastSidebar = G.currentSidebar;
		G.currentSidebar = { player: username };
		// }
		G.restoreSidebar();
	}
};

G.collapseSidebar = function() {
	var c = j('#closer');
	// c.html("&laquo;");
	c.removeClass('open');
	c.addClass('closed');
	j('#map').addClass('closed');
	if (G.map) {
		G.map.updateSize();
	}
	j('#sidebar').hide('slow');
	j('#footer').hide('slow');
};

G.restoreSidebar = function() {
	G.closeDialog();
	var c = j('#closer');
	j('#sidebar').show('slow');
	j('#footer').show('slow', function() {
		c.addClass('open');
		j('#map').removeClass('closed');
		if (G.map) {
			G.map.updateSize();
		}
		c.removeClass('closed');
		// c.html("&raquo;");
		j('#sidebar').css('overflow-y', 'scroll');
	});
};

G.lastDialog = null;

G.dialog = function(content, title, additionalParams) {
	if (G.lastDialog !== null) {
		G.lastDialog.dialog("close");
		G.lastDialog = null;
	}
	j(content).dialog( j.extend( { modal:true, draggable:false, resizable:false, title:title }, additionalParams ) );
	G.lastDialog = j(content).dialog('open');
};

G.closeDialog = function(content) {
	if (content) {
		j(content).dialog("close");
	} else if (G.lastDialog) {
		G.lastDialog.dialog("close");
		G.lastDialog = null;
	}
};

G.checkPassword = function(passwordInput, verifyInput, submitButton, warningDiv) {
	var pi = j(passwordInput);
	var vi = j(verifyInput);
	var sb = j(submitButton);
	var wd = j(warningDiv);
	var f = function() {
		if (vi.val() !== pi.val()) {
			// sb.disabled = true;
			wd.html("Passwords do not match");
			if (vi.val().length > 0) {
				wd.parent().show();
				
			}
			pi.addClass("wrong");
			vi.addClass("wrong");
		} else {
			pi.removeClass("wrong");
			vi.removeClass("wrong");
			wd.parent().hide();
			wd.html("");
		}
	};
	pi.unbind('blur').blur(function() {
		if (vi.val() !== '') {
			f();
		}
	});
	vi.unbind('blur').blur(f);
};

G.check = function(inputField, pattern, submitButton, warningDiv, warningMessage) {
	var i = j(inputField);
	var sb = j(submitButton);
	var wd = j(warningDiv);

	i.unbind('change').change(function() {
		if (!pattern.test(i.val())) {
			// sb.disabled = true;
			wd.html(warningMessage);
			wd.parent().show();
			i.addClass("wrong");
		} else {
			i.removeClass("wrong");
			wd.parent().hide();
			wd.html("");
		}
	});
};

G.removeDummyItemOnSelect = function(prefix) {
	var dummy = j("#" + prefix + "DummyItem");
	dummy.remove();
	dummy = null;
};

G.checkIfUsernameTaken = function(inputField, submitButton, warningDiv) {
	j(inputField).unbind('change').change(function() {
		if (/^[a-zA-Z][a-zA-Z._]{0,19}$/.test(j(inputField).val())) {
			j.ajax({
				url: '/api/',
				data: {
					m:'isAvailable',
					p0: j(inputField).val()
				},
				type: 'POST',
				success: function(data) {
						// three cases:
						if (data) { // 1. true - "it is available"
							j(warningDiv).parent().hide();
							j(inputField).removeClass('wrong');
						} else { // 2. false - "it is taken"
							j(warningDiv).parent().show();
							j(warningDiv).html("This username is already taken.");
							j(inputField).addClass('wrong');
						}
					}
			});
		} else {
			j(warningDiv).parent().show();
			j(warningDiv).html("Usernames are between 1 and 20 characters long and do not contain numbers. Only dots and underscores are allowed as special chars.");
			j(inputField).addClass('wrong');
		}
	});
};

G.remindPassword = function(destination) {
	j.ajax({
		url: '/api/',
		data: {
			m: 'remindPassword',
			p0: destination
		},
		type: 'POST',
		success: function(data) {
			j("#reminderFeedback").html("Password reminder will be sent to " + destination + " (in the case a user exists with this email/cell phone). With it you can log in to Gbanga on your mobile.");
			G.dialog("#reminderFeedback", "Reminder sent");
		},
		error: function(req, textStatus, errorThrown) {
			j("#reminderFeedback").html(req.statusText);
			G.dialog("#reminderFeedback", "Reminding password failed");
		}
	});
};

G.updateStatus = function(key, status) {
	if ( status !== G.session.player.status ) {
		j.ajax({
			url: '/api/',
			data: {
				m: 'updateStatus',
				p0: key,
				p1: status
			},
			type: 'POST',
			success: function(data) {
				if (typeof(data.cellPhone) !== 'undefined') {
					G.session.player = data;
				}
				if (G.session.player.name === G.currentPlayerProfile) {
					j('span#status').text(data.status); 
				}
				j("input#statusedit").removeAttr("disabled"); 
			},
			error: function(req, textStatus, errorThrown) {
				if (req.status === 403) {
					G.resume();
				}
				j("input#statusedit").removeAttr("disabled"); 
			}
		});
	}
};

G.updateProfile = function(key, cellphone, email, twitterFeed, twitterPassword, facebookId) {
	j('#changedProfileResponse').hide();
	j.ajax({
		url: '/api/',
		data: {
			m: 'updateProfile',
			p0: key,
			p1: cellphone,
			p2: email,
			p3: twitterFeed,
			p4: twitterPassword,
			p5: facebookId
		},
		type: 'POST',
		success: function(data) {
			if (typeof(data.cellPhone) !== 'undefined') {
				G.session.player = data;
			}
			j('input#changeProfile').show();
			var response = j('#changedProfileResponse');
			response.html('Profile successfully updated!');
			response.attr('class', 'success');
			response.show();
			j('#processingProfile').hide();
		},
		error: function(req, textStatus, errorThrown) {
			if (req.status === 403) {
				G.resume();
			}
			j('input#changeProfile').show();
			var response = j('#changedProfileResponse');
			response.html('Profile update failed: ' + req.statusText);
			response.attr('class', 'error');
			response.show();
			j('#processingProfile').hide();
		}
	});
};

G.resume = function(username, key, startSession) {
	if (typeof(username) === 'undefined') {
		username = G.session.player.name;
	}
	if (typeof(key) === 'undefined') {
		key = G.session.key;
	}
	j.ajax({
		url: '/api/',
		data: {
			m: 'resume',
			p0: username,
			p1: key
		},
		type: 'POST',
		success: function(data) {
			if (startSession) {
				G.startSession(data);
			} else {
				G.session = data;
			}
		},
		error: function(req, textStatus, errorThrown) {
			// if (req.status === 403) {
				j("[href=login]").first().trigger('click');
			// }
		}
	});
};

G.changeSettings = function(key, friendCanSeeMyPosition, everybodyCanSeeMyPosition, notifyBySMS, notifyByEmail) {
	j('#changedProfileResponse').hide();
	j.ajax({
		url: '/api/',
		data: {
			m: 'changeSettings',
			p0: key,
			p1: friendCanSeeMyPosition,
			p2: everybodyCanSeeMyPosition,
			p3: notifyBySMS,
			p4: notifyByEmail
		},
		type: 'POST',
		success: function(data) {
			if (typeof(data.cellPhone) !== 'undefined') {
				G.session.player = data;
			}
			j('input#changeProfile').show();
			var response = j('#changedProfileResponse');
			response.html('Profile successfully updated!');
			response.attr('class', 'success');
			response.show();			
			j('#processingProfile').hide();			
		},
		error: function(req, textStatus, errorThrown) {
			if (req.status === 403) {
				G.resume();
			}
			j('input#changeProfile').show();
			var response = j('#changedProfileResponse');
			response.html('Profile update failed: ' + req.statusText);
			response.attr('class', 'error');
			response.show();			
			j('#processingProfile').hide();
		}
	});
};

G.getFriends = function(key) {
	j.ajax({
		url: '/api/',
		data: {
			m:'getFriends',
			p0:key
		},
		type: 'POST',
		success: function(data) {
			G.session.friends = data;
		},
		error: function(req, textStatus, errorThrown) {
			if (req.status === 403) {
				G.resume();
			} else {
				G.session.friends = null;
			}
		}
	});
};

G.offerFriendship = function(key, player, introduction) {
	j.ajax({
		url: '/api/',
		data: {
			m:'offerFriendship',
			p0:key,
			p1:player,
			p2:introduction
		},
		type: 'POST',
		success: function(data) {
			// G.session.friends = data;
			// TODO
		},
		error: function(req, textStatus, errorThrown) {
			// G.session.friends = null;
			// TODO
		}
	});
};

G.logout = function(key) {
	j.ajax({
		url: '/api/',
		data: {
			m:'logout',
			p0:key
		},
		type: 'POST',
		success: function(data) {
			location.reload();
			G.Cookie.erase('n');
			G.Cookie.erase('k');
		},
		error: function(req, textStatus, errorThrown) {
			location.reload();
			G.Cookie.erase('n');
			G.Cookie.erase('k');
		}
	});
};

G.startSession = function(data) {
	G.session = data;
	G.Cookie.set('n', G.session.player.name);
	G.Cookie.set('k', G.session.key, 0.1);
	
	var editProfileButton;
	var loginButton = j('[href=login]');
	loginButton.hide();
	if (j('#editMyProfile').length === 0) {
		editProfileButton = j(document.createElement('a'));
		editProfileButton.attr('id', 'editMyProfile');
		editProfileButton.attr('target', '_blank');
		editProfileButton.addClass('player');
		editProfileButton.unbind('click');
		editProfileButton.html("Edit my profile");
		loginButton.after(editProfileButton);
	}
	
	editProfileButton = j('#editMyProfile');
	editProfileButton.attr('href', '/who/' + G.session.player.name);
	editProfileButton.unbind('click').click(function(event) {
		event.preventDefault();
		G.showPlayer(G.session.player.name);
	});
	
	editProfileButton.show();
	
	var logoutButton = j('#right [href=register]');
	logoutButton.attr('href', '#');
	logoutButton.unbind('click').click(function(event) {
		event.preventDefault();
		G.logout(G.session.key);
	});
	logoutButton.html("Log out");
	
	G.showPlayer(data.player.name);
	G.getFriends(data.key);
};

G.getMapTile = function(top, left, bottom, right) {
	j.ajax({
		url: '/api/',
		data: {
			m:'getMapTile',
			p0:top,
			p1:left,
			p2:bottom,
			p3:right
		},
		type: 'POST',
		success: function(data) {
			G.closeUp.setVisibility(false);
			G.closeUp.destroyFeatures();
			G.currentMapTileFeatures = data;
			if (G.map.zoom === 16) {
				var features = G.geojsonReader.read(data);
				G.closeUp.addFeatures(features);
				G.closeUp.setVisibility(true);
			}
		},
		error: function(req, textStatus, errorThrown) {
			G.currentMapTileFeatures = errorThrown;
			G.closeUp.setVisibility(false);
		}
	});
};

G.login = function(username, password) {
	j("[href=login]").hide();
	j.ajax({
		url: '/api/',
		data: {
			m:'login',
			p0:username,
			p1:password
		},
		type: 'POST',
		success: function(data) {
			G.startSession(data);
		},
		error: function(req, textStatus, errorThrown) {
			if (req.status === 403) {
				j("#signupErrorStatus").html("Wrong username or password! Please check again or request a password reminder.");
			} else {
				j("#signupErrorStatus").html(req.statusText);
			}
			G.dialog("#signupError", "Login failed");
			j("#loginErrorBack").show();
			j("#signupErrorBack").hide();
			j("[href=login]").show();
		}
	});
};

G.register = function(username, password, cellphone, email, model, language) {
	
	var platformId = 11;
	var tested = false;
	var experimental = false;
	var category = 0;
	try {
		var code = j('#model').val();
		platformId = parseInt(code.substring(0, code.indexOf(',')), 10);
		code = code.substring(code.indexOf(',') + 1);
		tested = ('1' === code.substring(0, code.indexOf(',')));
		code = code.substring(code.indexOf(',') + 1);
		experimental = ('1' === code.substring(0, code.indexOf(',')));
		category = parseInt(code.substring(code.indexOf(',') + 1), 10);
	} catch (e) {}
	
	j.ajax({
		url: '/api/',
		data: {
			m:'register',
			p0:username,
			p1:password,
			p2:cellphone,
			p3:email,
			p4:model,
			p5:language,
			p6:"website:" + G.params._remoteAddr + ", " + G.params._city + ", " + G.params._country + ", (" + G.params._lat + "," + G.params._lon + ")"
		},
		type: 'POST',
		success: function(data) {
			// check platform id
			if (platformId === 3 || platformId === 4 || platformId === 5 || platformId === 7 || platformId === 8) {
				// it's J2ME
				j("#signupSuccessProceeding").html("An SMS with the download instructions for the mobile app has been sent to your phone...");
				G.dialog("#signupSuccess", "Successfully registered");
				G.requestDownloadSMS(username, password, false);
			} else if (platformId === 2) {
				// it's an iPhone
				j("#signupSuccessProceeding").html("You can now download and install the latest iPhone App by visiting <a href=\"http://gbanga.com/iphone\" target=\"_blank\" title=\"Download iPhone app\">http://gbanga.com/iphone</a>.");
				G.dialog("#signupSuccess", "Successfully registered");
			} else {
				// it's android or non-supported
				j("#signupSuccessProceeding").html("Sorry, but your phone is not supported yet.<br><br>Each time this message appears, Chrissie and Robin go on alert! We will let you know, as soon as Gbanga is ready for your device.<br><br>If you think this is wrong, please send us an email to <a href=\"mailto:support@gbanga.com\" title=\"Tell us why you think your device is supported!\">support@gbanga.com</a>.");
				G.dialog("#signupSuccess", "You're registered, but...");
			}
			
		},
		error: function(req, textStatus, errorThrown) {
			j("#signupErrorStatus").html(req.statusText);
			G.dialog("#signupError", "Registration failed");
			j("#loginErrorBack").hide();
			j("#signupErrorBack").show();
		}
	});
};

G.requestDownloadSMS = function(username, password, showDialogOnSuccess) {
	j("[href=requestDownloadSMS]").click( function(event) {
		event.preventDefault();
		G.requestDownloadSMS(username, password, true);
	});	
	j.ajax({
		url: '/api/',
		data: {
			m:'requestDownloadSMS',
			p0:username,
			p1:password
		},
		type: 'POST',
		success: function(data) {
			if (data && !data.success) {
				j("#smsDeliveryErrorStatus").html(data.description);
				G.dialog("#smsDeliveryError", "Delivering SMS failed");
			}
			if (data && data.success) {
				G.dialog("#smsDeliverySuccess", "SMS successfully delivered");
			}
		},
		error: function(req, textStatus, errorThrown) {
			if (req.status === 403) {
				j("#smsDeliveryErrorStatus").html("The username and/or password were wrong!");
			} else if (req.data && !req.data.success) {
				j("#smsDeliveryErrorStatus").html(req.data.description);
			} else {
				j("#smsDeliveryErrorStatus").html(req.statusText);
			}
			G.dialog("#smsDeliveryError", "Delivering SMS failed");
		}
	});
};

G.evaluateQueryString = function() {
	var pairs = G.params._queryString.split("&");
	if (pairs.length > 0) {
		pairs[0] = pairs[0].split("=");
		switch (pairs[0][0].toLowerCase()) {
			//case "plainenglish":
			//	j("#video").trigger("click");
			//	return true;
			case "who":
				if (pairs[0].length === 2) {
					G.showPlayer(pairs[0][1]);
					return true;
				}
				break;
			case "where":
				if (pairs[0].length === 2) {
					G.showCell(pairs[0][1]);
					return true;
				}
				break;
			default:
				// best effort: try to find a link with the given "?query"
				var o = j("[href=" + G.params._queryString.toLowerCase() + "]:visible");
				if (o.length > 0) {
					o.first().trigger("click");
					return true;
				} else {
					o = j("[href=?" + G.params._queryString.toLowerCase() + "]:visible");
					if (o.length > 0) {
						o.first().trigger("click");
						return true;
					}
				}
		}
	}
	return false;
};

G.hasStyleChangedForScrollbar = false;

	
	//j('#sidebar > *:visible').each(function(i, e) {
	//	k = j(e);
	//	if (k.height() + k.position().top > sidebarH) {
	//		scroll = true;
	//	}
	//});
	

		//j('#map').each(function(i, e) {
		//	j(e).css('right',
		//			(parseInt(j(e).css('right').replace('px', '')) + delta) + 'px');
		//});
		//j('#sidebar').each(function(i, e) {
		//	j(e).css('width',
		//			(parseInt(j(e).css('width').replace('px', '')) + delta) + 'px');
		//});
		//j('#closer').each(function(i, e) {
		//	j(e).css('right',
		//			(parseInt(j(e).css('right').replace('px', '')) + delta) + 'px');
		//});
		////j('#header').each(function(i, e) {
		////	j(e).css('width',
		////			(parseInt(j(e).css('width').replace('px', '')) + delta) + 'px');
		////});
		//j('#footer').each(function(i, e) {
		//	j(e).css('width',
		//			(parseInt(j(e).css('width').replace('px', '')) + delta) + 'px');
		//});
		////j('#modes').each(function(i, e) {
		////	j(e).css('right',
		////			(parseInt(j(e).css('right').replace('px', '')) + delta) + 'px');
		////});


/**
  * Handy cookie tool.
  * 
  * Taken from http://www.quirksmode.org/js/cookies.html#script
  */
G.Cookie = {
	/**
	 * When calling createCookie() you have to give it three bits of information:
	 * 
	 *  - the name and
	 *  - value of the cookie and
	 *  - the number of hours it is to remain active.
	 *
	 */
	set: function(name, value, hours) {
		var expires;
		if (hours) {
			var date = new Date();
			date.setTime(date.getTime() + (hours * 3600000));
			expires = "; expires=" + date.toGMTString();
		} else {
			expires = "";
		}
		document.cookie = name + "=" + value + expires + "; path=/";
	},
	
	/**
	 * To read out a cookie, call this function and pass the name of the cookie.
	 */
	get: function(name, defaultValue) {
		var nameEQ = name + "=";
		var ca = document.cookie.split(';');
		for(var i=0; i < ca.length; i++) {
			var c = ca[i];
			while (c.charAt(0) == ' ') {
				c = c.substring(1, c.length);
			}
			if (c.indexOf(nameEQ) === 0) {
				return c.substring(nameEQ.length, c.length);
			}
		}
		if (typeof(defaultValue) == 'undefined') {
			return undefined;
		} else {
			return defaultValue;
		}
	},
	
	/**
	 * Pass the name of the cookie to be erased
	 */
	erase: function(name) {
		this.set(name,"",-1);
	}
	
};

G.History = {

	_backButton: j('#homeLink'),
	_history: [],
	_forward: null,
	
	add: function(label, func) {
		var args = [];
		for (var i = 2; i < arguments.length; i++) {
			args.push(arguments[i]);
		}
		this._history.push({
			label: label,
			func: func,
			args: args
		});
		
		this._backButton.html("<strong>&lt;</strong> Go back");
		this._backButton.attr("title", "Go back to " + this.getCurrentLabel());
	},
	
	back: function() {
		this._forward = this._history.pop();
		
		if (this._history.length > 0) {
			var current = this._history.pop();
			var args = current.args;
			current.func(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10]);
			this._backButton.html("<strong>&lt;</strong> Go back");
			this._backButton.attr("title", "Go back to " + this.getCurrentLabel());

		} else {
			this.home();
		}
		
	},
	
	getCurrentLabel: function() {
		if (this._history.length > 1) {
			return this._history[this._history.length - 2].label;
		} else {
			return "Home";
		}
	},
	
	home: function() {
		while (this._history.length > 0) {
			this._forward = this._history.pop();
		}
		
		this._backButton.html(this.getCurrentLabel());
		
		G.closeDialog();
		G.hideAllPanels();
		j("#home").show();
		G.restoreSidebar();
		G.Marquee.start();
	}
	
};

G.resetIndividualMarkers = function() {
	
	// reset player territory
	if (G.markerPocket && G.markerPocket !== null && G.markerPocket.length) {
		var i;
		for (i = 0; i < G.markerPocket.length; i++) {
			try {
				var tmp = G.markerPocket[i];
				G.removeMarkerFromMap(tmp);
				tmp.destroy();
			} catch (e) {
				// alert(e);
			}
		}
	}
	G.markerPocket = [];
	
	// reset cell position
	if (G.currentCell && G.currentCell !== null) {
		var tmp2 = G.currentCell;
		G.currentCell = null;
		try {
			tmp2.display(false);
			G.removeMarkerFromMap(tmp2);
			tmp2.destroy();
		} catch (e2) {
			// alert(e2);
		}
	}
	
	G.Marquee.hide();
	
};

G.shout = function(cellname, message) {
	if ( G.session && G.session.key && G.session.key !== null && message.length > 0) {
		j.ajax({
			url: '/api/',
			data: {
				m: 'shout',
				p0: G.session.key,
				p1: cellname,
				p2: message
			},
			type: 'POST',
			success: function(data) {
				if (G.currentCellProfile === data.target.name) {
					j("#shouts").prepend(
						'<li>Player <a href="/who/' + G.session.player.name + '" class="player"><img src="http://img.' + document.location.host + '/' + G.session.player.image + '" alt="Player ' + G.session.player.name + '"height="18" width="18"> ' + G.session.player.name + '</a> shouted <em>&quot;' + data.content + '&quot;</em>.</li>'
					);
				}
				j("#shoutedit").val('');
				j("#shouting").show();
			},
			error: function(req, textStatus, errorThrown) {
				if (req.status === 403) {
					G.resume();
				}
				j("#shouting").show();
			}
		});
	}
};

G.quicksortDOMList = function(ul) {
	var sorted = G.qsortDOMLi(j(ul).children());
	j(sorted).each(function(i,e) {
		j(ul).prepend(e);
	});
};

G.qsortDOMLi = function(a) {
    if (a.length === 0) {
		return [];
	}
 
    var left = [];
    var right = [];
	var _pivot = j(a[0]);
    var pivot = _pivot.attr('order');
    for (var i = 1; i < a.length; i++) {
        // if (a[i] < pivot)
		if (j(a[i]).attr('order') < pivot) {
            left.push(a[i]);
		} else {
            right.push(a[i]);
		}
    }
 
    return G.qsortDOMLi(left).concat(_pivot[0], G.qsortDOMLi(right));
};


// from http://en.wikibooks.org/wiki/Algorithm_implementation/Sorting/Quicksort#JavaScript
//G.qsort = function(a) {
//    if (a.length == 0) return new Array();
// 
//    var left = new Array();
//    var right = new Array();
//    var pivot = a[0];
//    for (var i = 1; i < a.length; i++) {
//        if (a[i] < pivot)
//            left.push(a[i]);
//        else
//            right.push(a[i]);
//    }
// 
//    return qsort(left).concat(pivot, qsort(right));
//};

G.init();

