/* ------------------------------------ *
 * Global Variables
 * ------------------------------------ */

// this is now defined in wrurl and included with PHP code
// var __wrurl = 'http://wr.wizi.com';

var __timerid = 0;
var __eventids = [];
var __eventargs = [];

var __forcenewtoken = false;

/* ------------------------------------ *
 * Ping WR and get replies
 * ------------------------------------ */

function startping() {
	__timerid = window.setInterval('ping()', 5000);
}

function stopping() {
	window.clearInterval(__timerid);
}

function ping() {
	$.getJSON(__wrurl + '/wr/02/_?op=ping&id=0&jscb=?', function(data) {
		processasyncevents(data);
	});
}

/* ------------------------------------ *
 * Process Asynchronous API Events
 * ------------------------------------ */

function processasyncevents(data) {
	for(i = 0; i < data.length; i ++) {
		if(data[i]['ev'] == 'sent') {
			handlemessagesent(data[i]);
		}
		else if(data[i]['ev'] == 'paydone') {
			handlepaydone(data[i]);
		}
		else if(data[i]['ev'] == 'setopt') {
			handlesetopt(data[i]);
		}
		else if(data[i]['ev'] == 'newtok') {
			handlenewtoken(data[i]);
		}
		else if(data[i]['ev'] == 'upd') {
			handleupdate(data[i]);
		}

		if(data[i]['ref']) {
			var id = parseInt(data[i]['ref']);

			if(id == 0) {
				continue;
			}

			switch(__eventids[id]) {
				case 'load':
					handleloadlocation(data[i], __eventargs[id]);
					break;

				case 'send':
					handlemessagesent(data[i]);
					break;

				case 'user':
					handleloaduser(data[i]);
					break;

				case 'iploc':
					handleiplocation(data[i], __eventargs[id]);
					break;

				case 'signin':
					handlesignin(data[i]);
					break;
				
				default:
					debug('API error!');
					break;
			}
		}
	}
}

function handleloaduser(data) {
	// the WR session may expire while the cookie with the username is still present in the client's browser
	// if the returned user tag doesn't have 'lastuse' present then the session is anonymous
	if(data['lastuse']) {
		debug('User session is valid.');

		$('#tokenurl :input[name = "tokenurl"]').val(__wrurl + '/' + data['url']);
		$('a[href = "/move/avatartopin"], a[href = "/move/pintoavatar"]').show();

		if(gettokeninurl() == null && data['avatar']) {
			if(data['avatar'].indexOf('#') == 0) {
				$('#token-icon').attr('src', '/avatars/' + data['avatar'].replace('#', '') + '.png');
			}
			else {
				$('#token-icon').attr('src', data['avatar']);
			}
		}

		window.spin.hide();
		setsmstoken(data['url']);

		// set the location of my pin with data from user tag and display it if there is no token present in the url
		setpinlocation({ data: data, action: 'me', show: gettokeninurl() == null });

		// hide sign in button and display full navigation bar
		$('#header .topnav .logged-out').fadeOut(100, function() {
			$('#header .topnav .logged-in').css('display', $('body').hasClass('ie7') ? 'inline' : 'inline-block').fadeIn(100, null);
		});

		// hide why join webpart and display user profile information
		$('#sidebar .why-join').slideUp(200, function() {
			$('#profile').slideDown(200, null);
		});

		// get ip location to set the country and country code fields
		getiplocation(false);

		if(gettokeninurl() != null) {
			processtokeninurl(gettokeninurl());
		}

		// set slider visibility value
		$('#profile #visibility-amount').val(getvisibilitylabel($('#profile #visibility-slider').slider('value')));
	}
	else {
		debug('User session is no longer valid.');

		// clear cookie with username since the session is no longer valid
		$.cookie.clear('wrusr', { domain: '.wizi.com' });
				
		processtokeninurl(gettokeninurl());
	}
}

function handlenewtoken(data) {
	debug('New token: ' + data['url']);

	$('#tokenurl :input[name = "tokenurl"]').val(__wrurl + '/' + data['url']);
	window.token = data['url'];

	$('#token-icon').attr('src', '/images/pin-red.png');

	setsmstoken(data['url']);
}

function handleiplocation(data, args) {
	debug('IP location: ' + data['ip']);

	// set country code from country location
	if(data['c'] && data['c'] != 'xx') {
		debug('Place CN: ' + data['placecn']);
		debug('Country: ' + data['c']);
		setcountrycode(data['c']);	
	}

	if(args.setcenter) {
		// set map center to returned location
		if(data['lat'] && data['lon']) {
			debug('IP location [lat: ' + data['lat'] + ', lon: ' + data['lon'] + ']');
			window.gmap.setCenter(new GLatLng(data['lat'], data['lon']), 5);
		}
		else {
			window.gmap.setCenter(new GLatLng(0.0, -30.0), 1);
		}
	}
}

function handleloadlocation(data, args) {
	switch(data['err']) {
		case 'NA':
			openmapalert('The requested location was not found.');
			return;
					
		case 'NP':
			openmapalert('The requested location has expired.');
			return;

		default:
			$('#tokenurl :input[name = "tokenurl"]').val(__wrurl + '/' + data['url']);
			setsmstoken(data['url']);

			if(data['avatar']) {
				if(data['avatar'].indexOf('#') == 0) {
					$('#token-icon').attr('src', '/avatars/' + data['avatar'].replace('#', '') + '.png');
				}
				else {
					$('#token-icon').attr('src', data['avatar']);
				}
			}


			if($.cookie.get('wrusr') != null) {
				// hide why join webpart and display user profile information
				$('#sidebar .why-join').slideUp(200, function() {
					$('#profile').slideDown(200, null);
				});
			}
			
			setpinlocation({ data: data, action: args.action, show: args.show });
			return;
	}
}

function handlesignin(data) {
	if(data['err'] == 'OK') {
		debug('Good, sign in OK!');

		var usr = $('#header :input[name = "signinwiziname"]').val().toLowerCase();
		$.cookie.set('wrusr', usr, { seconds: 365 * 24 * 3600, domain: '.wizi.com' });

		$('a[href = "/move/avatartopin"], a[href = "/move/pintoavatar"]').show();

		// close the sign in form
		$('#header a.sign-in').removeClass('sign-in-open');
		$('#header .sign-in-form').css('left', '-3000px');

		// replace sign in menu with full featured navigation menu
		$('#header .topnav .logged-out').fadeOut(500, function() {
			$('#header .topnav .logged-in').css('display', $('body').hasClass('ie7') ? 'inline' : 'inline-block').fadeIn(500, null);
		});

		$('#must-signin').css('display', 'none');

		if(window.gmap.getCenter().lat() == 0.0 && window.gmap.getCenter().lng() == -30.0) {
			debug('Map not moved...');

			window.spin.hide();
			window.gmap.closeInfoWindow();

			// display user's location / avatar
			loadlocation({ token: usr, action: 'me', show: true });
		}
		else {
			debug('Map moved!!');
			loadlocation({ token: usr, action: 'me', show: false });
		}
	}
	else if(data['err'] == 'NA') {
		// display errors
		$('#header .sign-in-form .signin-error').text('Invalid wizi name or password');

		// hide loader
		$('#header .sign-in-form .loader-signin').css('display', 'none');
		$('#header :button[name = "cancelsignin"]').show();
	}
}

function handlesetopt(data) {
	debug('Set Options');

	if(data['wrurl']) {
		debug('New WR url: ' + data['wrurl']);
		__wrurl = data['wrurl'];
	}
}

function handlemessagesent(data) {
	debug('SMS message sent!');

	if(data['err']) {
		$('#smsoptions .sms-result').css('display', getinline())
			.addClass('sms-error').text('Failed to send SMS.');
	}
	else {
		$('#smsoptions .sms-result').css('display', getinline())
			.removeClass('sms-error').text('Location successfully sent. It may take a few minutes to arrive');
	}

	// hide the progress indicator
	$('#smsoptions .sms-progress').css('display', 'none');
	$('#smsoptions :button[name = "sendsms"]').removeAttr('disabled');
}

function handlepaydone(data) {
	debug('Payment Done!');

	$('#buy-options').slideUp(500, function() {
		$(this).css('top', '-500px');
		$('#send-form').slideDown(750, null);
	});
}

function handleupdate(data) {
	if(data['saldo']) {
		debug('Saldo changed: ' + data['saldo']);
		$('#profile #sms-credit span').text(data['saldo']);

		if(parseInt(data['saldo']) < 1) {
			$('#smsoptions :button[name = "sendsms"]').attr('disabled', 'disabled');
	
			$('#buy-options')
				.find('.buy-msg').css('display', 'none').end()
				.find('.msg-out-of-credit').css('display', 'block').end()
				.show().animate({ top: '400px' }, 1000 /* 2000 */, function() {
				$(this).animate({ top: '375px' }, 250);
			});
		}
		else {
			$('#smsoptions :button[name = "sendsms"]').removeAttr('disabled');
			
			$('#buy-options').slideUp(500, function() {
				$(this).css('top', '-500px');
			});		
		}
	}
}

function getinline() {
	return $('body').hasClass('ff2') ? 'inline' : 'inline-block';
}

/* ------------------------------------ *
 * Country Codes
 * ------------------------------------ */

function addcountrycodes() {
	var list = $('#sendoptions .sms-country');

	if(list.find('option').length == 0) {
		$('<option />').attr('value', '').text('Select the country').appendTo(list);

		$.each(countrycodes, function(index, country) {
			$('<option />').attr('value', country[2]).text(country[0]).appendTo(list);
		});
	}

	list.change(function() {
		$('#sendoptions .sms-country-code').text($(this).val() == '' ? '' : '+' + $(this).val());
		$('#smsoptions .sms-result').css('display', 'none').removeClass('sms-error').text('');
	});
}

function setcountrycode(country) {
	var regex = new RegExp('^' + country + ' \/', 'i');
	var country = $.grep(countrycodes, function(value, index) {
		return regex.test(value[1])
	});

	if(country.length != 0) {
		$('#sendoptions .sms-country').val(country[0][2]);
		$('#sendoptions .sms-country-code').text('+' + country[0][2]);	
	}
}

/* ------------------------------------ *
 * Global Methods & Handlers
 * ------------------------------------ */

function setglobalstate() {
	debug('Cookie [wrusr]: ' + $.cookie.get('wrusr'));
	debug('Classes: ' + $('body').attr('class'));

	// show the geolocation button if the browser supports geolocation
	if(navigator.geolocation) {
		$('#actions .find-me').css('display', 'inline-block');
	}
	else {
		debug('No geolocation support!');
	}

	// TODO: refactor to a new function
	$('#profile #visibility-slider').slider({ range: 'min', value: 13802, min: 0, max: 38573, slide: function(event, ui) {
			$('#profile #visibility-amount').val(getvisibilitylabel(ui.value));
		}, stop: function(event, ui) {
			$('#profile .profile-visibility-progress').css('display', 'inline');

			var visibility = 3600 * Math.round(Math.pow(10, ui.value / 10000.0));
			var value = Math.round(visibility + new Date().getTime() / 1000.0);

			if(ui.value == 0) {
				value = 0;
			}

			var priv = value == 0 ? 'invis' : 'pub';

			$.getJSON(__wrurl + '/wr/02/' + $.cookie.get('wrusr') + '?op=upd&id=0&priv=' + priv + '&pubexpiry=' + value + '&jscb=?', function(data) {
				$('#profile .profile-visibility-progress').css('display', 'none');
				processasyncevents(data);
			});
		}
	});

	debug('Token: ' + gettokeninurl());

	// check if the user is signed in and confirm that the session is valid
	if($.cookie.get('wrusr') == null) {
		processtokeninurl(gettokeninurl());
	}
	else {
		$.getJSON(__wrurl + '/wr/02/' + $.cookie.get('wrusr') + '?id=' + getid('user') + '&jscb=?', function(data) {
			processasyncevents(data);
		});
	}
}

function processtokeninurl(token) {
	if(token == null) {
		// get ip location to set the pin location and set the country and country code fields
		getiplocation(true);
		createtoken();		
	}
	else {
		$('a[href = "/move/pintoplace"]').show();

		window.spin.hide();
		loadlocation({ token: token, action: 'marker', show: true });
	}
}

// add classes to the body tag for specific browsers / platforms
function addbodyclasses() {
	if(navigator.userAgent && navigator.userAgent.indexOf('Firefox/2.0') != -1) {
		$('body').addClass('ff2');
	}
	if(navigator.userAgent && navigator.userAgent.indexOf('AppleWebKit') != -1) {
		$('body').addClass('safari');
	}
	if(navigator.userAgent && navigator.userAgent.indexOf('MSIE') != -1) {
		$('body').addClass('ie');
	}
	if(navigator.userAgent && navigator.userAgent.indexOf('MSIE 6') != -1) {
		$('body').addClass('ie6');
	}
	if(navigator.userAgent && navigator.userAgent.indexOf('MSIE 7') != -1) {
		$('body').addClass('ie7');
	}
	if(navigator.userAgent && navigator.userAgent.indexOf('MSIE 8') != -1) {
		$('body').addClass('ie7');
	}
	if(navigator.platform && navigator.platform.indexOf('Mac') != -1) {
		$('body').addClass('mac');
	}
}

function getvisibilitylabel(value) {
	var visibility = Math.round(Math.pow(10, value / 10000.0));

	if(visibility == 1) {
		visibility = 'invisible'
	}
	else if(visibility <= 24) {
		visibility = visibility + ' hours';
	}
	else {
		visibility = Math.round(visibility / 24) + ' days';
	}

	return visibility;
}

/* event handlers */

function attachevents() {
	$('#balloon-content a.balloon-photo').lightbox({ navigation: { preload: false } });

	$('#balloon-content a.balloon-close').click(function() {
		$('#balloon').hide();
		return false;
	});

	$('#balloon-content .balloon-zoom a').click(function() {
		if($(this).text() == '-') {
			window.gmap.zoomOut();
		}
		if($(this).text() == '+') {
			window.gmap.zoomIn();
		}
		return false;
	});

	$('a[href = "/move/avatartopin"]').click(function() {
		window.gme.setLatLng(window.gmap.getCenter());

		window.spin.hide();
		window.gme.show();

		updatetoken(true); // me
		return false;
	});
	$('a[href = "/move/pintoavatar"]').click(function() {	
		window.gmap.setCenter(window.gme.getLatLng());
		window.spin.show();

		updatetoken(false); // not me
		return false;
	});
	$('a[href = "/move/pintoplace"]').click(function() {
		window.gmap.setCenter(window.gmarker.getLatLng());
		window.spin.show();

		updatetoken(false); // not me
		return false;
	});

	$('a[href = "/buy/close"]').click(function() {
		$('#buy-options').slideUp(500, function() {
			$(this).css('top', '-500px');
		});
		
		return false;
	});

	$('a[href = "/buy/open"]').click(function() {
		var credit = $('#profile #sms-credit span').text();
		$('#profile #sms-credit span').text('-500');

		$('#tokenurl :button[name = "sendtoken"]').click();

		$('#profile #sms-credit span').text(credit);
		return false;		
	});

	$('#buy-options input[type = "image"]').click(function() {
		$('#buy-options input[name = "custom"]').each(function() {
			$(this).val($.cookie.get('wrusr')); // set paypal custom field to current username
		});	
	});

	$('#map-alert a').click(function() {
		$(this).parent().fadeOut(500, function() {
			$(this).css('top', '-500px');
		});

		return false;
	});

	// header events
	$('#header a.sign-in, #must-signin a[href = "/send/signin"]').click(function() {
		if($(this).hasClass('sign-in-open')) { // sign in form open -> close it
			cancelsignin();
		}
		else {
			canceljoin();
			window.scrollTo(0, 0);
		
			// set sign in button color to match sign in form
			$(this).addClass('sign-in-open');
			$('#header .sign-in-form .signin-error').text('');

			// reset all form fields
			$('#header .sign-in-form :text[name = "signinwiziname"]').val('');
			$('#header .sign-in-form :password[name = "signinpwd"]').val('');

			$('#header .sign-in-form .signin-wiziname-error').css('display', 'none');
			$('#header .sign-in-form .signin-pwd-error').css('display', 'none');

			// hide loader
			$('#header .sign-in-form .loader-signin').css('display', 'none');
			$('#header :button[name = "cancelsignin"]').show();

			// open sign in form
			$('#header .sign-in-form').css('top', '-500px').css('left', ($('#header a.sign-in').offset().left - 128) + 'px').animate({ top: '50px' }, 500, function() {
				$(this).animate({ top: '40px' }, 100, null);
			});
			$('#header :input[name = "signinwiziname"]').focus();
		}

		return false;
	});
	
	$('#header a.sign-out').click(function() {
		$(this).blur();
		$('#send-form').slideUp(750, null); // close sms form on logout
		$('#account-popup .account-cancel').click();

		// show sign out progress
		$('#header .sign-out-feedback').css('left', ($(this).offset().left - 81) + 'px');
		$('#header .logged-in .loader-signout').css('display', 'inline');

		return signout();
	});
	
	// account events
	$('#account-popup :text[name = "accountemail"]').change(function() {
		$('#account-popup .account-email-error').css('display', 'none');
	});	
	
	$('#header ul.logged-in a[href = "/account"]').click(function() {
		$('#header #account-popup').css('top', '-300px').css('display', 'block').css('left', ($(this).offset().left - 500) + 'px').animate({ top: '50px' }, 500, function() {
			$(this).animate({ top: '40px' }, 100, null);
		});

		return false;
	});
	$('#account-popup .account-cancel').click(function() {
		$('#header #account-popup').animate({ top: '-300px' }, 500, function() {
			$('#account-popup :password').each(function() {
				$(this).val('');
			});

			$('#account-popup .account-email-error, #account-popup .account-email-success').css('display', 'none');
			$('#account-popup .account-pwd-error, #account-popup .account-pwd-success').css('display', 'none');

			$(this).css('display', 'none');
		});

		return false;
	});
	$('#account-popup a[href = "/account/save"]').click(function() {
		return savenewemail(this);
	});
	$('#account-popup a[href = "/account/change"]').click(function() {
		return changepassword(this);
	});


	// action events
	$('#actions a.find-me').click(function() {
		return findme();
	});
	
	// sign in events
	$('#header input[name = "signinpwd"]').keydown(function(event) {
		if(event.keyCode == 13) {
			$(this).blur();
			signin();
		}
	});

	$('#header :button[name = "signin"]').click(function() {
		signin();
	});

	$('#header :button[name = "cancelsignin"]').click(function() {
		cancelsignin();
	});	

	// join events
	$('#sidebar a.join-wizi').click(function() {
		cancelsignin();
	
		// reset form state
		$('#join form .text-field').val('');
		$('#join form input[name = "canceljoin"]').css('display', 'inline');

		$('#join form span:not(.wizi-domain)').text('');
		$('#join form img').css('display', 'none');


		$('#sidebar .why-join').slideUp(500, function() {
			$('#join').slideDown(500, null);
		});

		return false;
	});

	$('#join :button[name = "canceljoin"]').click(function() {
		canceljoin();
	});	

	$('#join :input[name = "name"]').blur(function() {
		if($(this).val() == '') {
			$('#join .nameverify-message').css('color', '#c20f24').text('Mandatory field');
		}
		else {
			$('#join .nameverify-message').text('');
		}
	});

	$('#join :input[name = "pwd"]').blur(function() {
		if($(this).val() == '') {
			$('#join .wizipwd-message').css('color', '#c20f24').text('Mandatory field');
		}
		else {
			$('#join .wizipwd-message').text('');
		}
	});

	$('#join :input[name = "email"]').blur(function() {
		if($(this).val() == '') {
			$('#join .emailverify-message').css('color', '#c20f24').text('Mandatory field');
		}
		else if(!/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test($(this).val())) {
			$('#join .emailverify-message').css('color', '#c20f24').text('Invalid email');
		}
		else {
			$('#join .emailverify-message').text('');
		}
	});

	$('#join :input[name = "wiziname"]').blur(function() {
		checkwiziname(this);
	});

	$('#join :input[name = "pwdverify"]').blur(function() {
		checkpassword(this);
	});

	$('#join :button[name = "joinwizi"]').click(function() {
		joinwizi();
	});

	// send events
	$('#smsoptions .sms-from').blur(function() {
		if($(this).val().length == 0) {
			$(this).addClass('sms-grey').val('your name');
		}
	});

	$('#smsoptions .sms-from').keyup(function() {
		setremainingsmschars();
	});

	$('#smsoptions .sms-message').keyup(function() {
		setremainingsmschars();
	});

	$('#tokenurl :text[name = "tokenurl"]').keydown(function(event) {
		if(event.keyCode == '8' || event.keyCode == '46') {
			return false;
		}
	});

	$('#tokenurl :text[name = "tokenurl"]').keypress(function(event) {
		if(event.keyCode != '') {
			return false;
		}
	});

	$('body').delegate('#tokenurl :button[name = "sendtoken"], .ginfo .send-sms', 'click', function() {
		if($(this).is('a')) {
			window.scrollTo(0, $('#gmap').offset().top);
		}

		$('#sendoptions').css('display', 'block');

		if($.cookie.get('wrusr') == null) {
			$('#must-signin').slideDown(750, null);	
		}
		else {
			$('#must-signin').css('display', 'none');	
			var credit = parseInt($('#profile #sms-credit span').text()); // TODO: refactor this

			if(credit < 1) {
				debug('Credit is less than 1!');

				$('#buy-options')
					.find('.buy-msg').css('display', 'none').end()
					.find('.msg-no-credit').css('display', 'block').end()
					.show().animate({ top: '400px' }, 1000 /* 2000 */, function() {
					$(this).animate({ top: '375px' }, 250);
				});
			}
			else {
				$('#send-form').slideDown(750, null);	
			}
		}
		
		return false;
	});

	$('#smsoptions a.sms-close').click(function() {
		$('#sendoptions').slideUp(750, null);
		return false;
	});

	$('#smsoptions .sms-from').focus(function() {
		if($(this).hasClass('sms-grey')) {
			$(this).removeClass('sms-grey').val('');
		}
	});

	$('#smsoptions .sms-cell-phone').focus(function() {
		if($(this).hasClass('sms-grey')) {
			$(this).removeClass('sms-grey').val('');
		}
	});

	$('#smsoptions :button[name = "sendsms"]').click(function() {
		sendsms();
		__forcenewtoken = true;
	});

	// social networks
	$('body').delegate('#social-networks a, .ginfo ul a[target = "_blank"]', 'click', function(){
		var url = Url.encode($('#tokenurl :input[name = "tokenurl"]').val());
		__forcenewtoken = true;
		
		switch($(this).attr('class').replace('send-', '')) {
			case 'twitter':
				$(this).attr('href', 'http://twitter.com/home?status=' + Url.encode($('#smsoptions .sms-message').val()));
				break;

			case 'facebook':
				$(this).attr('href', 'http://www.facebook.com/sharer.php?u=' + url + '&t=' + url);
				break;
	
			case 'orkut':
				$(this).attr('href', 'http://promote.orkut.com/preview?nt=orkut.com&du=' + url + '&tt=' + url);
				break;
		}
	});

	// profile events
	$('#profile .avatar-icon a.change-avatar').click(function() {
		var $changer = $('#profile .avatar-changer-popup');
		var $avatar = $('#profile .avatar-container');

		var top = $avatar.offset().top;

		$changer.css('top', top + 'px').css('left', ($avatar.offset().left - 14) + 'px');
		$changer.width(4).height($avatar.height() + 10).css('display', 'block');

		$changer.animate({ opacity: 1.0 }, 100, function() {
			$(this).animate({ left: ($(this).offset().left - 460) + 'px', width: '424px' }, 1000, function() {
				top -= 40;

				$(this).animate({ height: '118px', top: (top + 'px') }, 500, function() {
					$(this).find('ul').fadeIn(500, null);
				});
			});
		});

		return false;
	});
	$('#profile .avatar-changer-popup ul li img[src *= "/avatars/"]').click(function() {
		changeavatar(this);
	});
	$('#profile a.cancel-avatar').click(function() {
		$('#profile .avatar-changer-popup').fadeOut(1000, null).css('opacity', '0.0').find('ul').css('display', 'none');
		return false;
	});

	$('#profile .profile-cn a.change-cn').click(function() {
		$(this).animate({ opacity: 0.0 }, 100, function() {
			$('#profile .cn-edit-controls').slideDown(500, function() {
				$(this).css('display', 'block');
			});
		});
		return false;
	});
	$('#profile .cn-edit-controls a.save-cn').click(function() {
		$(this).blur();
		return changecommonname();
	});
	$('#profile .cn-edit-controls a.cancel-cn').click(function() {
		$('#profile .cn-edit-controls').slideUp(500, function() {
			$('#profile .profile-cn a.change-cn').animate({ opacity: 1.0 }, 100, null);
		});
		return false;
	});

	$('#profile .status-message a.change-status').click(function() {
		$(this).animate({ opacity: 0.0 }, 100, function() {
			$('#profile .info-edit-controls').slideDown(750, function() {
				$(this).css('display', 'block');
			});
		});

		return false;
	});
	$('#profile .info-edit-controls a.save-info').click(function() {
		$(this).blur();
		return changestatusmessage();
	});
	$('#profile .info-edit-controls a.cancel-info').click(function() {
		$('#profile .info-edit-controls').slideUp(500, function() {
			$('#profile .status-message a.change-status').animate({ opacity: 1.0 }, 100, null);
		});
		return false;
	});

	// street search
	$('#street-search input').keydown(function(event) {
		if(event.keyCode == 13) {
			$('#street-search a').click();
		}
	}).focus(function() {
		if($(this).val() == 'Address') {
			$(this).val('').removeClass('address-grey');
		}
	}).blur(function() {
		if($(this).val() == '') {
			$(this).val('Address').addClass('address-grey');
		}
	});

	$('#street-results .search-close').click(function() {
		$('#street-results').slideUp(500, null);
		return false;
	});

	$('#street-search a').click(function() {
		var geocoder = new GClientGeocoder();
		$('#street-search img.progress').css('display', 'inline-block');

		geocoder.getLocations($('#street-search :text').val(), function(result) {
			$('#street-search img.progress').css('display', 'none');
			
			if(result.Status.code != G_GEO_SUCCESS) {
				$('#street-results').slideUp(500, null);
				openmapalert('Your search returned no results.');
			}
			else if(result.Placemark.length == 1) {
				$('#street-results').slideUp(500, null);
				window.gmap.setCenter(new GLatLng(result.Placemark[0].Point.coordinates[1], result.Placemark[0].Point.coordinates[0]), 13);
				window.spin.show();

				openballoon({ cn: result.Placemark[0].address });
				updatetoken(false); // not me
			}
			else {
				$('#street-results li').remove();

				$.each(result.Placemark, function(index, placemark) {
					$('<li />').text(placemark.address).data('data', placemark).appendTo('#street-results ul');
				});

				$('#street-results').slideDown(500, null);
			}
		});

		return false;
	});

	$('#street-results').delegate('li', 'click', function() {
		window.gmap.setCenter(new GLatLng($(this).data('data').Point.coordinates[1], $(this).data('data').Point.coordinates[0]), 13);
		window.spin.show();
		
		openballoon({ cn: $(this).data('data').address });
		updatetoken(false); // not me
	});
	$('#street-results').delegate('li', 'mouseover', function() {
		$(this).css('background-color', '#cce2ef');
	});
	$('#street-results').delegate('li', 'mouseout', function() {
		$(this).css('background-color', 'transparent');
	});
}

function canceljoin() {
	$('#join form span:not(.wizi-domain)').text('');

	$('#join').slideUp(500, function() {
		$('#sidebar .why-join').slideDown(500, null);
	});
}

function cancelsignin() {
	$('#header a.sign-in').removeClass('sign-in-open');
	$('#header .sign-in-form').css('left', '-3000px');
}

/* ------------------------------------ *
 * Account Methods & Handlers
 * ------------------------------------ */

function savenewemail(t) {
	$('#account-popup .account-email-error').css('display', 'none');
	$('#account-popup .account-email-success').css('display', 'none');

	var email = $('#account-popup :text[name = "accountemail"]').val();

	if(email == '') {
		$('#account-popup .account-email-error').css('display', 'inline-block').text('Mandatory field');
		return false;
	}

	if(!/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(email)) {
		$('#account-popup .account-email-error').css('display', 'inline-block').text('Invalid email');
		return false;
	}

	$(t).css('display', 'none');
	$('#account-popup #name-email img').css('display', 'inline');

	$.getJSON(__wrurl + '/wr/02/' + $.cookie.get('wrusr') + '?op=upd&email=' + Url.encode(email) + '&jscb=?', function(data) {
		$('#account-popup #name-email img').css('display', 'none').next().css('display', 'inline-block');
		$('#account-popup .account-email-success').css('display', 'inline-block');
		
		processasyncevents();
	});

	return false;
}

function changepassword(t) {
	$('#account-popup .account-pwd-error').css('display', 'none');
	$('#account-popup .account-pwd-success').css('display', 'none');

	var pwd = $('#account-popup :password[name = "accountpwd"]').val();

	if(pwd == '') {
		$('#account-popup .account-pwd-error').css('display', 'inline-block').text('Invalid password');
		return false;
	}

	if(pwd != $('#account-popup :password[name = "accountpwdverify"]').val()) {
		$('#account-popup .account-pwd-error').css('display', 'inline-block').text('Passwords don\'t match');
		return false;
	}

	$(t).css('display', 'none');
	$('#account-popup #account-pwd img').css('display', 'inline');

	$.getJSON(__wrurl + '/wr/02/' + $.cookie.get('wrusr') + '?op=upd&ancred=pw:' + Url.encode(pwd) + '&jscb=?', function(data) {
		var ok = false;

		for(i = 0; i < data.length; i ++) {
			if(data[i]['err'] == 'OK') {
				ok = true;
				break;
			}
		}

		$('#account-popup #account-pwd img').css('display', 'none').next().css('display', 'inline-block');

		if(ok) {
			$('#account-popup .account-pwd-success').css('display', 'inline-block').text('Password changed');
		}
		else {
			$('#account-popup .account-pwd-error').css('display', 'inline-block').text('Error changing password');
		}
	});

	return false;
}

/* ------------------------------------ *
 * SMS Methods & Handlers
 * ------------------------------------ */

function sendsms() {
	var credit = parseInt($('#profile #sms-credit span').text()); // TODO: refactor this

	if(credit < 1) {
		debug('Credit is less than 1!');

		$('#buy-options')
			.find('.buy-msg').css('display', 'none').end()
			.find('.msg-no-credit').css('display', 'block').end()
			.show().animate({ top: '400px' }, 1000 /* 2000 */, function() {
			$(this).animate({ top: '375px' }, 250);
		});
	}

	// clear error messages
	$('#smsoptions .sms-result').css('display', 'none').removeClass('sms-error').text('');

	// abort if message is too long, error is already present
	if(getremainingsmschars() < 0) {
		return;
	}

	// check the from field is not empty and not the default value
	if($('#sendoptions .sms-from').val().length == 0 || $('#sendoptions .sms-from').val() == 'your name') {
		$('#smsoptions .sms-result').css('display', $('body').hasClass('ff2') ? 'inline' : 'inline-block').addClass('sms-error').text('Invalid from field. Please type your name.');
		return;
	}

	// check the country code
	if($('#smsoptions :text[name="smscellphone"]').val().indexOf('+') != 0 && $('#sendoptions select[name = "smscountry"]').val().length == 0) {
		$('#smsoptions .sms-result').css('display', $('body').hasClass('ff2') ? 'inline' : 'inline-block').addClass('sms-error').text('Invalid country code. Select a country from the list.');
		return;
	}

	// check the phone number is all digits
	var regex = new RegExp('^\\+?[0-9]+$');

	if(!regex.test($('#smsoptions :text[name="smscellphone"]').val())) {
		$('#smsoptions .sms-result').css('display', $('body').hasClass('ff2') ? 'inline' : 'inline-block').addClass('sms-error').text('Invalid phone number.');
		return;
	}

	// check that the message contains a token
	if(gettokenfromtext($('#smsoptions .sms-message').val()) == null) {
		$('#smsoptions .sms-result').css('display', $('body').hasClass('ff2') ? 'inline' : 'inline-block').addClass('sms-error').text('Invalid message. Your message should contain a valid location link.');
		return;
	}

	// collect data
	var from = $('#smsoptions .sms-from').val();
	var to = $('#smsoptions :text[name="smscellphone"]').val().indexOf('+') != 0 ?
		$('#sendoptions .sms-country-code').text().replace('+', '') + $('#smsoptions :text[name="smscellphone"]').val() :
		$('#smsoptions :text[name="smscellphone"]').val().replace('+', '');
	var msg = $('#smsoptions .sms-message').val();

	// display progress indicator
	$('#smsoptions .sms-progress').css('display', $('body').hasClass('ff2') ? 'inline' : 'inline-block');
	$('#smsoptions :button[name = "sendsms"]').attr('disabled', 'disabled');

	// send the sms and process the result
	$.getJSON(__wrurl + '/wr/02/_?op=send&id=' + getid('send') + '&t=share&to=' + to + '&subj=Wizi+Location+Map&invite=' +
			gettokenfromtext(msg) + '&body=' + Url.encode(from + ' says: ' + msg) + '&jscb=?', function(data) {
		processasyncevents(data);
	});
}

function setsmstoken(token) {
	var text = $('#smsoptions .sms-message').val();

	if(text == '') {
		debug('SMS text is empty, using default message.');
		text = 'I am here. Location map ' + __wrurl + '/' + token;
	}
	else {
		debug('SMS message present.');

		var regex = new RegExp('https?\:\/\/([a-z0-9]+\.)?wizi\.com\/([a-z0-9]+)', 'g');
		var match = regex.exec(text);
		
		if(match != null) {
			debug('Token is present in message.');
			text = text.replace(regex, __wrurl + '/' + token);
		}
		else {
			debug('Token not present.');
			text += ' ' + __wrurl + '/' + token;
		}
	}

	$('#smsoptions .sms-message').val(text);
	setremainingsmschars();	
}

function getremainingsmschars() {
	var body = $('#smsoptions .sms-from').val() + ' says: ' + $('#smsoptions .sms-message').val();
	return 160 - body.length;
}

function setremainingsmschars() {
	if(getremainingsmschars() < 0) {
		$('#smsoptions .sms-message-length').addClass('sms-error');
		$('#smsoptions .sms-result').css('display', 'inline-block').addClass('sms-error').text('Your message is too long.');
	}
	else {
		$('#smsoptions .sms-message-length').removeClass('sms-error');
		$('#smsoptions .sms-result').css('display', 'inline-block').removeClass('sms-error').text('');
	}

	$('#smsoptions .sms-message-length').text(getremainingsmschars());
}

/* ------------------------------------ *
 * User Profile Methods & Handlers
 * ------------------------------------ */

function checkwiziname(t) {
	var regex = new RegExp('^[a-zA-Z0-9_]+$');
	
	if(!regex.test($(t).val())) {
		$('#join .wiziname-message').css('color', '#c20f24').text('Invalid username');
		return;
	}

	$('#join .wiziname-progress').css('display', 'inline-block');
	$('#join .wiziname-message').text('');

	$.getJSON(__wrurl + '/wr/02/' + $(t).val() + '?jscb=?', function(data) {
		$('#join .wiziname-progress').css('display', 'none');

		if(data.length != 0 && data[0]['err'] == 'NA') {
			$('#join .wiziname-message').css('color', '#366d7c').text('Available');
		}
		else {
			$('#join .wiziname-message').css('color', '#c20f24').text('Already taken');
		}
	});
}

function checkpassword(t) {
	if($(t).val() != $('#join :input[name = "pwd"]').val()) {
		$('#join .pwdverify-message').css('color', '#c20f24').text('Passwords don\'t match');
	}
	else {
		$('#join .pwdverify-message').text('');
	}
}

function joinwizi() {
	var ok = true;
	var usr = $('#join :input[name = "wiziname"]').val().toLowerCase();

	if($('#join :input[name = "name"]').val() == '') {
		$('#join .nameverify-message').css('color', '#c20f24').text('Mandatory field');
		ok = false;
	}

	if(usr == '') {
		$('#join .wiziname-message').css('color', '#c20f24').text('Mandatory field');
		ok = false;
	}

	if($('#join .wiziname-message').text() != 'Available') {
		ok = false;
	}

	if($('#join :input[name = "pwd"]').val() == '') {
		$('#join .wizipwd-message').css('color', '#c20f24').text('Mandatory field');
		ok = false;
	}

	if($('#join .pwdverify-message').text() != '') {
		ok = false;
	}

	if($('#join :input[name = "email"]').val() == '') {
		$('#join .emailverify-message').css('color', '#c20f24').text('Mandatory field');
		ok = false;
	}

	if(!ok) {
		return; // perform all validations before exiting instead of showing only the first error
	}

	var name = Url.encode($('#join :input[name = "name"]').val());
	var pwd = Url.encode($('#join :input[name = "pwd"]').val());
	var mail = Url.encode($('#join :input[name = "email"]').val());

	// display progress image and hide cancel button
	$('#join .join-progress').css('display', 'inline-block').prev().css('display', 'none').prev().css('vertical-align', 'top');

	// now + 24 hours
	var ts = Math.round(86400 + new Date().getTime() / 1000.0);

	$.getJSON(__wrurl + '/wr/02/' + usr + '?op=put&cn=' + name + '&ancred=pw:' + pwd + '&email=' + mail + '&pubexpiry=' + ts + '&t=me&priv=pub&jscb=?', function(data) {
		if(data.length != 0 && data[0]['err'] == 'OK') {
			debug('Sign up went well, signing in...');

			$.getJSON(__wrurl + '/wr/02/_?op=signin&autoev=1&user=' + usr + '&pw=' + pwd + '&jscb=?', function(data) {
				if(data.length != 0 && data[0]['err'] == 'OK') {
					debug('Good, sign in OK!');
					$.cookie.set('wrusr', usr, { seconds: 365 * 24 * 3600, domain: '.wizi.com' });

					$('#join').slideUp(500, function() {
						$('#smsoptions :text[name = "smsfrom"]').removeClass('sms-grey').val($('#join :input[name = "name"]').val());

						$('#profile .wiziusr').attr('href', '/' + usr).text($('#join :input[name = "name"]').val());
						$('#profile .cn-edit-controls input').val($('#join :input[name = "name"]').val());
						$('#profile .status-message .message-text').html('<i>Set your status message...</i>');
						
						$('#account-popup .account-field').text(usr);
						$('#account-popup :text[name = "accountemail"]').val(mail);
						$('#account-popup .account-wizi-name .account-caption a').attr('href', '/' + usr).text('http://wizi.com/' + usr);

						$('#profile #visibility-amount').val('24 hours');
						$('#profile').slideDown(500, null);
					});

					$('#header .topnav .logged-out').fadeOut(500, function() {
						$('#header .topnav .logged-in').css('display', $('body').hasClass('ie7') ? 'inline' : 'inline-block').fadeIn(500, null);
					});

					// replace pin with my pin
					window.gme.setLatLng(window.gmap.getCenter());

					window.spin.hide();
					window.gme.show();

					$('#profile #sms-credit span').text('3');
					$('#tokenurl :input[name = "tokenurl"]').val(__wrurl + '/' + usr);
					$('a[href = "/move/avatartopin"], a[href = "/move/pintoavatar"]').show();
		
					updatetoken(true);
					return;
				}
			});

			return;
		}

		alert('API error.');  // TODO: check error message
	});
}

function signin() {
	$('#header .sign-in-form .signin-error').text('');

	// reset all form field errors
	$('#header .sign-in-form .signin-wiziname-error').css('display', 'none');
	$('#header .sign-in-form .signin-pwd-error').css('display', 'none');

	// get user and password
	var usr = $('#header :input[name = "signinwiziname"]').val().toLowerCase();
	var pwd = Url.encode($('#header :input[name = "signinpwd"]').val());

	// check that user and password have data
	if(usr == '') {
		$('#header .sign-in-form .signin-wiziname-error').css('display', 'inline-block');
		return;
	}
	if(pwd == '') {
		$('#header .sign-in-form .signin-pwd-error').css('display', 'inline-block');
		return;
	}

	// show loader
	$('#header :button[name = "cancelsignin"]').hide();
	$('#header .sign-in-form .loader-signin').css('display', 'inline');

	// try to login
	$.getJSON(__wrurl + '/wr/02/_?op=signin&id=' + getid('signin') + '&user=' + usr + '&pw=' + pwd + '&jscb=?', function(data) {
		processasyncevents(data);
	});
}

function signout() {
	$.getJSON(__wrurl + '/wr/02/_?op=logout&id=0&jscb=?', function(data) {
		debug('Logout OK!');
		$.cookie.clear('wrusr', { domain: '.wizi.com' });

		$('#header .logged-in .loader-signout').css('display', 'none'); // hide loader image
		window.gme.hide(); // hide my pin and info window
		window.gmap.closeInfoWindow();

		window.gmap.setCenter(window.gme.getLatLng());
		window.spin.show();

		// TODO: check this...

		if(window.token) {
			updatetoken(false); // not me	
		}
		else {
			createtoken();
		}

		$('a[href *= "/move/"]').hide();

		// hide full navigation and display sign in button
		$('#header .topnav .logged-in').fadeOut(500, function() {
			$('#header .sign-out-feedback').css('left', '-3000px')
			$('#header .topnav .logged-out').fadeIn(500, null);
		});

		// hide user profile and display the why join webpart
		$('#profile').slideUp(500, function() {
			$('#sidebar .why-join').slideDown(500, null);
		});
	});

	return false;
}

function changecommonname() {
	$('#profile .cn-edit-controls img.profile-cn-progress').css('display', 'inline');
	var name = $('#profile .cn-edit-controls input').val();

	$.getJSON(__wrurl + '/wr/02/' + $.cookie.get('wrusr') + '?op=upd&id=0&cn=' + Url.encode(name) + '&jscb=?', function(data) {
		$('#profile .cn-edit-controls').slideUp(500, function() {
			$('#profile .profile-cn a.change-cn').animate({ opacity: 1.0 }, 100, null);
		});

		$('#profile .profile-cn .profile-welcome a').text(name);
		$('#profile .cn-edit-controls img.profile-cn-progress').css('display', 'none');

		processasyncevents(data);
	});

	return false;
}

function changeavatar(img) {
	$('#profile .avatar-changer-popup ul li.selected-avatar').removeClass('selected-avatar');
	$('#profile .avatar-changer-popup ul li:last img').css('display', 'inline');
	$(img).parent().addClass('selected-avatar');

	var regex = new RegExp('\/avatars\/([^\.]+)\.png$');
	var match = regex.exec($(img).attr('src'));

	$.getJSON(__wrurl + '/wr/02/' + $.cookie.get('wrusr') + '?op=upd&id=0&avatar=' + Url.encode('#' + match[1]) + '&jscb=?', function(data) {
		$('#profile .avatar-changer-popup ul li:last img').css('display', 'none');

		$('#profile .avatar-changer-popup').fadeOut(1000, function() {
			$('#profile .avatar-container img, #token-icon').attr('src', '/avatars/' + match[1] + '.png');
			window.gme.setImage('/avatars/' + match[1] + '.png');
		}).css('opacity', '0.0').find('ul').css('display', 'none');

		processasyncevents(data);
	});
}

function changestatusmessage() {
	$('#profile .info-edit-controls img.profile-status-progress').css('display', 'inline');
	var status = $('#profile .status-message textarea').val();

	$.getJSON(__wrurl + '/wr/02/' + $.cookie.get('wrusr') + '?op=upd&info=' + Url.encode(status) + '&jscb=?', function(data) {
		$('#profile .info-edit-controls').slideUp(500, function() {
			$('#profile .status-message a.change-status').animate({ opacity: 1.0 }, 100, null);
		});

		$('#profile .status-message .message-text').text(status);
		$('#profile .info-edit-controls img.profile-status-progress').css('display', 'none');

		processasyncevents(data);
	});

	return false;
}

/* ------------------------------------ *
 * Geolocation Methods & Handlers
 * ------------------------------------ */

function findme() {
	window.cancelgeolocation = 0;

	// calculate position for progress notification
	var $map = $('#gmap');
	var $box = $('#map-progress');
	
	var top = $map.offset().top + ($map.height() - $box.height()) / 2;
	var left = $map.offset().left + ($map.width() - $box.width()) / 2;
	
	// center progress box over the map
	$box.css('top', top + 'px').css('left', left + 'px').fadeIn(1000, null);

	navigator.geolocation.getCurrentPosition(processgeolocation, geolocationerror, { enableHighAccuracy: true });
	return false; // stop event
}

function processgeolocation(position) {
	if(window.cancelgeolocation ++ == 0) {
		$('#map-progress').fadeOut(1000, null);
		window.gmap.setCenter(new GLatLng(position.coords.latitude, position.coords.longitude), 13, GMapType.G_NORMAL_MAP);

		//acts on pin when user is logged out or me when user is logged in
		if($.cookie.get('wrusr') != null) {
			window.gme.setLatLng(window.gmap.getCenter());
			
			window.spin.hide();
			window.gme.show();

			updatetoken(true); // me
		}
		else {
			window.spin.show();
			updatetoken(false); // not me
		}
	}
	else {
		debug('Geolocation replica!');
	}
}

function geolocationerror(error) {
	if(window.cancelgeolocation ++ == 0) {
		$('#map-progress').fadeOut(500, function() {
			var geolocationerrors = [ 'Upsss! Something went wrong. Please try again later.',
																'Wizi does not have permission to use your location.',
																'Upsss! Couldn\'t find your location. Please drag the pin to set your location manually.',
																'Upsss! Couldn\'t find your location. Please try again or drag the pin to set your location manually.' ];
	
			openmapalert(geolocationerrors[error.code]);
		});
	}
}

/* ------------------------------------ *
 * Map Methods & Handlers
 * ------------------------------------ */

function geticon(image) {
	// create a new icon as a copy of the default icon
	var icon = new GIcon(G_DEFAULT_ICON);
	icon.image = image;

	icon.iconSize = new GSize(32, 32);
	icon.iconAnchor = new GPoint(9, 24);

	icon.shadow = null;
	icon.shadowSize = new GSize(0,0);

	icon.infoWindowAnchor = new GPoint(18, 0);
	icon.infoShadowAnchor = new GPoint(22, 25);

	return icon;
}

function loadgmap() {
	window.gmap = new GMap2(document.getElementById("gmap"), { backgroundColor: '#666666' });
	window.gmap.setCenter(new GLatLng(0.0, -30.0), 1);
	window.gmap.disableInfoWindow();

	var ui = window.gmap.getDefaultUI();
	ui.maptypes.hybrid = true;
	ui.maptypes.physical = false;
	ui.controls.scalecontrol = false;

	window.gmap.setUI(ui);

	// wireup map events
	GEvent.addListener(window.gmap, "dragstart", function() {
		window.spin.show();
		$('#balloon').hide();
	});
	GEvent.addListener(window.gmap, "dragend", function() {
		updatetoken(false); // not me	
	});
	GEvent.addListener(window.gmap, "zoomend", function(ol, nl) {
		handlezoomchange(nl);
	});
	GEvent.addListener(window.gmap, "maptypechanged", function() {
		handlemaptypechange(window.gmap.getCurrentMapType().getUrlArg());
	});

	// get center coordinates of map, this will change when map size changes
	var center = window.gmap.fromLatLngToContainerPixel(window.gmap.getCenter());

	// add new static pin
	window.spin = new GScreenOverlay('/images/pin-red.png',
		new GScreenPoint(center.x, center.y), new GScreenPoint(10, 10), new GScreenSize(32, 32));
	window.gmap.addOverlay(window.spin);

	// hanlde static pin events: click & hover
	$('#gmap').delegate('img[src $= "pin-red.png"], img[src $= "flag-red.png"]', 'click', function() {
		// TODO: show info window
	});
	$('#gmap').delegate('img[src $= "pin-red.png"], img[src $= "flag-red.png"]', 'hover', function() {
		$(this).css('cursor', 'pointer');
	});

	// add pin, me and marker
	window.gmarker = new GMarker(window.gmap.getCenter(), { icon: geticon('/images/flag-red.png'), draggable: false, hide: true });
	window.gmap.addOverlay(window.gmarker);

	window.gme = new GMarker(window.gmap.getCenter(), { icon: geticon('/avatars/luka.png'), draggable: false, hide: true });
	window.gmap.addOverlay(window.gme);

	GEvent.addListener(window.gmarker, "click", function() {
		openballoon($('body').data('marker'), window.gmarker);
	});
	GEvent.addListener(window.gme, "click", function() {
		openballoon($('body').data('me'), window.gme);
	});
}

function loadlocation(args) {
	$.getJSON(__wrurl + '/wr/02/' + args.token + '?id=' + getid('load', { action: args.action, show: args.show }) + '&jscb=?', function(data) {
		processasyncevents(data);
	});	
}

function openballoon(data, sender) {
	debug('Open balloon.');
	$('#balloon-content .balloon-photo').hide();

	if(data['links']) {
		$.each(eval(Base64.decode(data['links'])), function(index, value) {
			if(value['cn'] == 'photo') {
				$('#balloon-content .balloon-photo').attr('href', 'http://wizi.com/map/photos/' + value['url'])
						.find('img').attr('src', 'http://wizi.com/map/getphoto.php?url=' + value['url'] + '&w=85').end()
					.show();
			}
		});
	}

	$('#balloon .balloon-cn').text(data['cn'] ? data['cn'] : data['url']);
	
	if(data['lastupd']) {
		$('#balloon .balloon-updated').text(getlastupdated(data['lastupd'])).show();
	}
	else {
		$('#balloon .balloon-updated').hide()
	}

	if(data['info']) {
		$('#balloon .balloon-info').text(data['info']).show();
	}
	else {
		$('#balloon .balloon-info').hide();
	}

	if(sender) {
		if(sender == window.gmarker || sender == window.gme) {
			var point = window.gmap.fromLatLngToContainerPixel(sender.getLatLng());
		
			var balloonx = $('#gmap').offset().left + point.x - 126;
			var balloony = $('#gmap').offset().top + point.y - 148;
		
			$('#balloon').css('left', balloonx + 'px').css('top', balloony + 'px').show();
		}
	}
	else {
		var balloonx = $('#gmap').offset().left + 205;
		$('#balloon').css('left', balloonx + 'px').show();
	}
}

// data - data object from WR
// action - pin to act on ['marker', 'pin' or 'me']
// show - show the pin or just set it's location on the map [true / false]
// zoom - zoom level in GMap format [1 - 20]
function setpinlocation(args) {
	var avatar = null;

	if(args.data && args.data['avatar']) {
		if(args.data['avatar'].indexOf('http') == 0) {
			avatar = args.data['avatar'];
		}
		else {
			debug('Avatar: ' + args.data['avatar'] + ' [' + args.data['url'] + ']');
			avatar = '/avatars/' + args.data['avatar'].replace('#', '') + '.png';
		}
	}

	// TODO: display address if exists
	// TODO: display link to zoom in to location (15x - 17x) if there is no cn / description

	$('body').data(args.action, args.data);
	
	if(args.show) {
		openballoon(args.data);
	}
	
	var maptype = translatemaptype(args.data);
	var zoom = window.gmap.getZoom();
	var ll = window.gmap.getCenter();

	if(args.data && args.data['lat'] && args.data['lon']) {
		ll = new GLatLng(args.data['lat'], args.data['lon']);
		zoom = 13;
	}

	if(args.data && args.data['zoom']) {
		var spans = [ 172983, 135783, 79962, 41444, 20872, 10454, 5228, 2615, 1307, 653, 326, 163, 81, 40, 20, 10, 5, 2, 1, 0, 0 ];
		var zoom = 0;

		$.each(spans, function(index, value) {
			if(args.data['zoom'] >= value) {
				zoom = index;
				return false;
			}
		});

		debug('WR zoom: ' + args.data['zoom']);
		debug('GMap zoom: ' + -- zoom);
	}

	var pin = eval('window.g' + args.action);
	pin.setLatLng(ll);

	if(avatar) {
		pin.setImage(avatar);
	}

	if(args.action == 'me') {
		if(avatar) {
			$('#profile .avatar-container img').attr('src', '/avatars/' + args.data['avatar'].replace('#', '') + '.png');
			$('#profile .avatar-changer-popup ul li img[src $= "/' + args.data['avatar'].replace('#', '') + '.png"]').parent().addClass('selected-avatar');
		}
	
		$('#account-popup .account-field').text(args.data['url']);
		$('#account-popup .account-wizi-name .account-caption a').attr('href', '/' + args.data['url']).text('http://wizi.com/' + args.data['url']);
	
		var cn = args.data['cn'] ? args.data['cn'] : args.data['url'];
	
		debug('CN: ' + cn);
	
		$('#profile .wiziusr').attr('href', '/' + args.data['url']).text(cn);
		$('#profile .cn-edit-controls input').val(cn);

		$('#smsoptions :text[name = "smsfrom"]').removeClass('sms-grey').val(cn);
	
		if(args.data['info'] && args.data['info'].length != 0) {
			$('#profile .status-message .message-text').text(args.data['info']);
			$('#profile .status-message textarea').val(args.data['info']);
		}
		else {
			$('#profile .status-message .message-text').html('<i>Set your status message...</i>');
		}
	
		if(args.data['saldo']) {
			$('#profile #sms-credit span').text(args.data['saldo']);
		}
		else {
			$('#profile #sms-credit span').text('0');
		}
	
		if(args.data['email']) {
			$('#account-popup :text[name = "accountemail"]').val(args.data['email']);
		}
	
		if(args.data['pubexpiry']) {
			if(args.data['pubexpiry'] == 0) {
				$('#profile #visibility-amount').val(getvisibilitylabel($('#profile #visibility-slider').slider('value', 0)));
			}
			else {
				var expiry = new Date(args.data['pubexpiry'] * 1000);
				var span = (expiry - new Date()) / 3600000;
		
				if(span < 0) {
					$('#profile #visibility-amount').val(getvisibilitylabel($('#profile #visibility-slider').slider('value', 0)));
				}
				else {
					var value = Math.round((Math.log(span) / Math.log(10)) * 10000);
					$('#profile #visibility-amount').val(getvisibilitylabel($('#profile #visibility-slider').slider('value', value)));
				}
			}
		}
	}

	pin.show();

	GEvent.clearListeners(window.gmap, "zoomend");

	if(args.show) {
		window.gmap.setCenter(ll, args.zoom ? args.zoom : zoom, maptype);
	}

	GEvent.addListener(window.gmap, "zoomend", function(ol, nl) {
		handlezoomchange(nl);
	});
}

function translatemaptype(data) {
	if(data && data['maptype'] == 'h') {
		var types = window.gmap.getMapTypes();

		for(i = 0; i < types.length; i ++) {
			debug('Type: ' + types[i].getUrlArg());

			if(types[i].getUrlArg() == data['maptype']) {
				return types[i];
			}
		}
	}

	return GMapType.G_NORMAL_MAP;
}

function getiplocation(setcenter) {
	var ip = $.query.get('ip') != null ? '&ip=' + $.query.get('ip') : '';

	$.getJSON(__wrurl + '/wr/02/_?op=iploc&id=' + getid('iploc', { setcenter: setcenter }) + ip + '&jscb=?', function(data) {
		processasyncevents(data);
	});
}

function handlezoomchange(level) {
	debug('New zoom level: ' + level);
	debug('WR zoom level: ' + getwrzoom());

	if(window.token != null && window.token == getlastupdatedtoken()) {
		updatetoken(false);
	}
	else if($.cookie.get('wrusr') != null) {
		updatetoken(true);
	}
}

function handlemaptypechange(type) {
	debug('New map type: ' + type);

	if(window.token != null && window.token == getlastupdatedtoken()) {
		updatetoken(false);
	}
	else if($.cookie.get('wrusr') != null) {
		updatetoken(true);
	}
}

function createtoken() {
	//$('#tokenurl .token-share').hide();
	//$('#tokenurl .token-progress').css('display', 'inline-block');

	var loc = window.gmap.getCenter();
	$('#tokenurl :input[name = "tokenurl"]').val('');

	$.getJSON(__wrurl + '/wr/02/_?op=gentok&id=0&priv=pub&lat=' + loc.lat() + '&lon=' + loc.lng()
			+ '&maptype=' + getmaptype() + '&zoom=' + getwrzoom() + '&jscb=?', function(data) {
		//$('#tokenurl .token-progress').hide();
		//$('#tokenurl .token-share').show();

		processasyncevents(data);
	});
}

function updatetoken(me) {
	if(__forcenewtoken) {
		__forcenewtoken = false;

		createtoken();
		return;		
	}

	if(!me && window.token == null) {
		createtoken();
		return;
	}

	var loc = window.gmap.getCenter();

	if(me && (window.gme.getLatLng().lat() != loc.lat() || window.gme.getLatLng().lng() != loc.lng())) {
		return;
	}

	//$('#tokenurl .token-share').hide();
	//$('#tokenurl .token-progress').css('display', 'inline-block');

	var token = me ? $.cookie.get('wrusr') : window.token;
	$('#tokenurl :input[name = "tokenurl"]').val(__wrurl + '/' + token);

	debug('Update "' + token + '". [me: ' + me + ']');
	setsmstoken(token);

	if(me) {
		$('#token-icon').attr('src', $('#profile .avatar-container img').attr('src'));
	}
	else {
		$('#token-icon').attr('src', '/images/pin-red.png');
	}

	var ts = Math.round(86400 + new Date().getTime() / 1000.0);

	$.getJSON(__wrurl + '/wr/02/' + token + '?op=upd&id=0&lat=' + loc.lat() + '&lon=' + loc.lng()
			+ '&zoom=' + getwrzoom() + '&maptype=' + getmaptype() /* + '&pubexpiry=' + ts */ + '&jscb=?', function(data) {
		//$('#tokenurl .token-progress').hide();
		//$('#tokenurl .token-share').show();

		processasyncevents(data);
	});
}

function getwrzoom() {
	var bounds = window.gmap.getBounds();
	return parseInt(1000 * Math.abs(bounds.getSouthWest().lat() - bounds.getNorthEast().lat()));
}

function getmaptype() {
	// wr: a = aerial, r = road (default), h = hybrid, b = bird's eye
	var map = { m: 'r', h: 'h' };
	return map[window.gmap.getCurrentMapType().getUrlArg()];
}

function openmapalert(message) {
	var $map = $('#gmap');
	var $box = $('#map-alert').find('span').text(message).end();

	var top = $map.offset().top + ($map.height() - $box.height()) / 2;
	var left = $map.offset().left + ($map.width() - $box.width()) / 2;

	// center progress box over the map
	$box.css('top', top + 'px').css('left', left + 'px').fadeIn(1000, null);
}

/* ------------------------------------ *
 * Utilities
 * ------------------------------------ */

function getlastupdated(unixtime) {
	var date = new Date(unixtime * 1000)
	var delta = parseInt((new Date().getTime() - date) / 1000) + new Date().getTimezoneOffset() * 60;

	if(delta < 60) {
		return 'a minute ago';
	}
	else if(delta < (45 * 60)) {
		return Math.ceil(delta / 60) + ' minutes ago';
	}
	else if(delta < (90 * 60)) {
		return 'an hour ago';
	}
	else if(delta < (24 * 60 * 60)) {
		return Math.ceil(delta / 3600) + ' hours ago';
	}
	else if(delta < (48 * 60 * 60)) {
		return 'one day ago';
	}
	else {
		return Math.ceil(delta / 86400) + ' days ago';
	}
}

function getlastupdatedtoken() {
	return gettokeninurl($('#tokenurl :input[name = "tokenurl"]').val());
}

function gettokenfromtext(text) {
	var regex = new RegExp('https?\:\/\/([a-z0-9]+\.)?wizi\.com\/([a-zA-Z0-9\/]+)');
	var match = regex.exec(text);

	return match != null ? match[2] : null;
}

function gettokeninurl(url) {
	var regex = new RegExp('^https?\:\/\/([a-z0-9]+\.)?wizi\.com\/([a-zA-Z0-9\/]+)(\\??.*)$');
	var match = regex.exec(url ? url : window.location.href);

	return match != null ? match[2] : null;
}

function getid(op, args) {
	// create new id for async send operation
	var id = Math.floor(Math.random() * 10000000);
	__eventids[id] = op;
	__eventargs[id] = args;

	return id;
}

/* ------------------------------------ *
 * Debug
 * ------------------------------------ */

function debug(s) {
	$('#debug #trace').prepend('<span>' + s + '</span>');
}

// EOF.2


