if((typeof window.console === 'undefined')) {
	window.console = {
		log: function() { },
		dir: function() { }
	}
};
var __log = console.log;

Object.extend = function() {
	var dest = arguments[0];
	for (var i = 1; i < arguments.length; i++) {
		var source = arguments[i];
		// copy properties, excluding this merge function
		for (var property in source) { if(property !== 'merge') { dest[property] = source[property]; } }
	};
	return dest;
};

Date.minutes = function(n) {
	return n * 60;
}
Date.hours = function(n) {
	return n * 3600;
}
Date.days = function(n) {
	return n * 86400; // 24 * 3600
}
Date.weeks = function(n) {
	return n * 604800; // 24 * 3600 * 7
}
Date.years = function(n) {
	return n * 31471200;
}
Math.limit = function(lower, value, higher) {
	return Math.min(Math.max(lower, value), higher);
};

var Quantity = function(value, units) {
	if (typeof value === 'string') {
		this.value = String(value);
		this.units = String(units);
	} else {
		var h = value.human();
		var p = h.split(/ /);
		this.value = p[0];
		if(p.length > 1) {
			this.units = p[1] + ' ' + units;
		} else {
			this.units = String(units);
		}
	}
};
Quantity.prototype = {
	toString: function() {
		return this.value + ' ' + this.units;
	}
};
Number.prototype.fix = function(n) {
	if(typeof n === 'undefined') { n = 9; };
	var pow = Math.pow(10, n);
	var f = Math.round(this * pow)/pow;
	return f;
};
Number.prototype.commas = function() {
	var nStr = String(this);
	var x = nStr.split('.'), x1 = x[0], x2 = (x.length > 1 ? '.' + x[1] : '');
	var rgx = /(\d+)(\d{3})/;
	while (rgx.test(x1)) {
		x1 = x1.replace(rgx, '$1' + ',' + '$2');
	}
	return x1 + x2;
};
Number.prototype.human = function() {
	var p = Math.log(this)/Math.log(10);
	var f = 1;
	if(p >= 6) {
		var names = ['', '', 'million', 'billion', 'trillion'];
		var n = Math.min(Math.floor(p/3), 4);
		if(n < 2) {
			f = 0;
		}
		return (this/Math.pow(10, n*3)).fix(f).commas() + ' ' + names[n];
	} else {
		var n = Math.floor(p);
		if(n >= 3) {
			f = 0;
		}
		return this.fix(f).commas();
	}
};
Number.prototype.to_distance = function(pow) {
	if(typeof pow === 'undefined') { pow = 0; }
	pow = Math.pow(10, pow);
	// gotta be a cleverer way of doing this
	// var v = this * pow;
	var v = this;
	if(v < 0.000000001) {
		return new Quantity('< 1','nanometres');
	} else if(v < 0.000001) {
		return new Quantity((v * 1000000000), 'nanometres')
	} else if(v < 0.0001) {
		return new Quantity((v * 1000000*pow), 'µm');
	} else if(v < 0.01) {
		return new Quantity((v * 1000*pow), 'mm');
	} else if(v < 1) {
		return new Quantity((v * 100* pow), 'cm');
	} else if(v < 1000) {
		return new Quantity(v, 'm')
	} else {
		return new Quantity((v/1000), 'km');
	}
};
Number.prototype.to_area = function() {
	var v = this;
	if(v < 0.0001) {
		return new Quantity('< 1','cm²');
	} else if(v < 1) {
		return new Quantity((v * 10000), 'cm²');
	} else if(v < 1000000) {
		return new Quantity(v, 'm²')
	} else {
		return new Quantity((v/1000000), 'km²');
	}
}
Number.prototype.to_volume = function() {
	var v = this;
	if(v < 1.0e-09) {
		return new Quantity('< 1','mm³');
	} else if(v < 1.0e-06) {
		return new Quantity((v * 1000000000), 'mm³');
	} else if(v < 1.0e-1) {
		return new Quantity((v * 1000000), 'cm³');
	} else if(v < 100000000) {
		return new Quantity(v, 'm³')
	} else {
		return new Quantity((v/1000000000), 'km³');
	}
}
Number.prototype.to_mass = function(places) {
	var p = Math.round( Math.log(this)/Math.log(10) );
	var f = 1;
	var names = [['gram', 'grammes'], ['kilogram', 'kilogrammes'], ['tonne', 'tonnes'], ['kilotonne', 'kilotonnes'], ['megatonne', 'megatonnes'], ['gigatonne', 'gigatonnes']];

	var n = 1, v = this;

	if (p < 0) {
		n = 0;
		v = this*1000.0;
	} else {
		var pow = Math.min(4, Math.floor(p/3.0))
		v = this/Math.pow(10, pow*3);
		n = pow + 1;
	}
	var plural = 1;
	if (places) { v = String(v.fix(places)); }
	if (v == 1) {
		plural = 0;
	}
	return new Quantity(v, names[n][plural]);
};

Number.prototype.to_time = function() {
	var v = this;
	if(v < 0.000000001) {
		return new Quantity('< 1','nanoseconds');
	} else if(v < 0.000001) {
		return new Quantity((v * 1000000000), 'nanoseconds')
	} else if(v < 0.0001) {
		return new Quantity((v * 1000000), 'microseconds');
	} else if(v < 0.1) {
		return new Quantity((v * 1000), 'milliseconds');
	} else if (v < Date.minutes(1)) {
		return new Quantity(v, 'seconds')
	} else if (v < Date.hours(1)) {
		return new Quantity(v/Date.minutes(1), 'minutes')
	} else if (v < Date.days(1)) {
		return new Quantity(v/Date.hours(1), 'hours')
	} else if (v < Date.days(1)) {
		return new Quantity(v/Date.hours(1), 'hours')
	} else if (v < Date.days(14)) {
		return new Quantity(v/Date.days(1), 'days')
	} else if (v < Date.years(1)) {
		return new Quantity(v/Date.weeks(1), 'weeks')
	} else {
		return new Quantity(v/Date.years(1), 'years')
	}
};
var CQ = {
	MULTIPLIERS: ["grammes", "kilogrammes", "tonnes", "kilotonnes", "megatonnes", "gigatonnes"],
	TONNE: 1000,
	KILOTONNE: 1000000,
	MEGATONNE: 1000000000,
	GIGATONNE: 1000000000000,
	Substance: {
		'co2': 'CO<span class="co2">2</span>',
		'c': "C"
	},

	co2: function(mass, multiplier, callback) {
		return new CQ.Mass(mass, multiplier, 'co2', callback);
	},

	c: function(mass, multiplier, callback) {
		return new CQ.Mass(mass, multiplier, 'c', callback);
	},

	ppm: function(quantity, callback) {
		return new CQ.PPM(quantity, callback);
	},

	deg_to_rad: function(degrees) {
		return degrees * Math.PI/180;
	},

	rad_to_deg: function(rads) {
		return rads * 180 / Math.PI;
	}
};


for (i in CQ.MULTIPLIERS) {
	var m = CQ.MULTIPLIERS[i];
	CQ[m] = (function(multiplier) {
		return function(mass, callback) {
			return CQ.co2(mass, multiplier, callback);
		}
	})(m);
	CQ[m + '_of_c'] = (function(multiplier) {
		return function(mass, callback) {
			return CQ.c(mass, multiplier, callback);
		}
	})(m);
}

CQ.Mass = function(mass, multiplier, substance, callback) {
	this._mass = mass;
	this._multiplier = multiplier;
	this._substance = (substance);
	this._load_callback = callback;
	this.load();
}


CQ.Mass.prototype = {
	load: function() {
		var callback = (function(mass) {
			return function(data) {
				mass.loaded(data);
			};
		})(this);
		// TODO: make this framework agnostic/independent
		$.getJSON(this.json_url(), callback);
	},
	loaded: function(data) {
		this.data = data;
		Object.extend(this, data);
		for (p in CQ.Mass.visualisation_prototypes) {
			Object.extend(this[p], CQ.Mass.visualisation_prototypes[p]);
		}
		if(this._load_callback) { this._load_callback.call(this, this); }
	},

	url_path: function(controller) {
		controller = (controller || '/mass')
		return [controller, String(this._mass).replace(/\./, '_'), this._multiplier, this._substance];
	},
	url: function() {
		return this.url_path().join('/');
	},
	permalink: function() {
		var min = 1.0e40, mult = '', i = 0, s = (this._substance === 'c' ? '_of_c' : ''), first = true;
		for (i in CQ.MULTIPLIERS) {
			var m = CQ.MULTIPLIERS[i];
			var n = this[m + s];
			var l = Math.log(n)/Math.log(10);
			if (l >= 0 || first) {
				if (l < min) {
					min = n;
					mult = m;
					found = true;
				}
			}
			first = false;
		}
		return ['/mass', String(min.fix(3)).replace(/\./, '_'), mult, this._substance].join('/');
	},
	json_url: function() {
		return this.url()+'.json';
	}
};

CQ.PPM = function(quantity, callback) {
	this.quantity = quantity;
	this._load_callback = (function(ppm) {
		return function() {
			// now we know the mass in terms of kilogrammes, add in the values
			this._mass = this.gigatonnes
			this._multiplier = 'gigatonnes'
			callback.call(this, this)
		}
	})(this);
	this._substance = 'co2';
	this.load();
};

CQ.PPM.prototype = Object.extend({}, CQ.Mass.prototype, {
	url: function(controller) {
		return ['/ppm', String(this.quantity).replace(/\./, '_')].join('/')
	}
});

// not sure i need these anymore...
CQ.Mass.visualisation_prototypes = {
	patch: { },
	sphere: { },
	cube: { }
};


CQ.V = {
	use: function(to_visualisation) {
		if (this.current && to_visualisation !== this.current.name) {
			this.hide_current();
			this.current = this[to_visualisation];
			this.tab(this.current).addClass('active')
			this.current.display(this.mass);
		}
	},
	hide_current: function() {
		this.tab(this.current).removeClass('active')
		this.current.hide();
	},
	tab: function(visualisation) {
		return $('#volume #'+visualisation.name);
	},
	display: function(mass, overwrite_mass) {
		for (var i = 0; i < this.available.length; i++) {
			this.available[i].reset();
		};
		// if (overwrite_mass || !this.mass) { this.mass = mass; }
		this.mass = mass;
		this.current.display(mass);
		this.tab(this.current).addClass('active')
	},
	layout: false,
	mass: false,
	current: false,
	timescale: 'year',
	available: [],
	onload: false
};

CQ.V.Cube = {
	name: 'Cube',
	loaded: function(mass) {

	},
	reset: function() {
		// this.canvas().html('');
		this.mass = false;
	},
	display: function(mass) {
		if (!this.mass || (mass.kilogrammes != this.mass.kilogrammes)) {
			this.mass = mass;
			var faded = (function(v) {
				return function() {
					v.canvas().addClass('loading').html('<h3 class="loading">Loading...</h3>');
				}
			})(this);
			// this.canvas().find('img').fadeOut(100, faded);
			faded();
			var loaded = (function(v) {
				return function() {
					v.canvas().removeClass('loading').find('.loading').remove();
					// v.canvas().empty();
					// $(this).hide();
					// v.canvas().append(this);
					// $(this).fadeIn(200)
				}
			})(this);

			var i = new Image();
			i.onload = loaded;
			i.src = mass.mass.url_path(this.action()).join("/") + '.png';
			$(i).hide();
			// console.log(i.src)
			this.canvas().append(i).show();
			$(i).fadeIn();
		} else {
			this.canvas().show();
		}
	},
	action: function() {
		return "/visualise/cube";
	},
	hide: function() {
		this.canvas().hide();
	},
	canvas: function() {
		return $('#cube-canvas');
	}
};
CQ.V.available.push(CQ.V.Cube);

CQ.V.Sphere = Object.extend({}, CQ.V.Cube, {
	name: 'Sphere',
	action: function() {
		return "/visualise/sphere";
	},
	canvas: function() {
		return $('#sphere-canvas');
	}
});

CQ.V.available.push(CQ.V.Sphere);

CQ.V.Figures = {
	name: 'Figures',
	loaded: function(mass) {

	},
	reset: function() {
		this.canvas().html('<h3 class="loading">Loading...</h3>');
		this.mass = false;
	},
	display: function(mass) {
		if (!this.mass || (mass.kilogrammes != this.mass.kilogrammes)) {
			this.mass = mass;
			var path = mass.mass.url_path("/tools/facts");
			this.canvas().addClass("loading").show();
			this.canvas().load(path.join('/'), function(responseText, textStatus, XMLHttpRequest) {
				$(this).removeClass("loading")
				$('.volume').each(function() {
					var val = parseFloat($(this).text(), 10);
					$(this).text(val.to_volume().toString())
				})
				$('.distance').each(function() {
					var val = parseFloat($(this).text(), 10);
					$(this).text(val.to_distance().toString())
				});
				$('.timescale .'+mass.timescale, this).css('display', '')
				if (true || !mass.absolute) {
					var m = CQ.V.reference_mass.scale(1, mass.timescale);
					var rate_calculation = (function(tab, mass) {
						return function() {
							$('#rate-description').html(mass.to_s() + ' per ' + mass.timescale);
							var factors = {
								year: mass.scaling.second,
								day: (24 * 3600),
								second: 1
							}
							var kg_per_second = mass.kilogrammes / factors[mass.timescale];
							var scales = ['year', 'day', 'second'];
							for(i in scales) {
								var s = scales[i];
								$('.timescale.rates.time', tab).find('.'+s).text((kg_per_second * factors[s]).to_mass().toString())
							}
							var masses = ['kilogramme', 'tonne', 'kilotonne', 'megatonne'];
							factors = {
								kilogramme: 1,
								tonne: 1.0e+3,
								kilotonne: 1.0e+6,
								megatonne: 1.0e+9
							};
							for (var i = 0; i < masses.length; i++) {
								var m = masses[i];
								$('.timescale.rates.mass', tab).find('.'+m).text((factors[m]/kg_per_second ).to_time().toString());
							};

							factors = {
								metre: 1,
								kilometre: Math.pow(1000, 3)
							};
							var vol_of_1_kg = mass.mass.volume / mass.kilogrammes;
							var vol_per_second = vol_of_1_kg * kg_per_second;
							var volumes = ['metre', 'kilometre'];
							for (var i = 0; i < volumes.length; i++) {
								var v = volumes[i];
								$('.timescale.rates.volumetric', tab).find('.'+v).text((factors[v]/vol_per_second ).to_time().toString())
							};
							$('.timescale.rates', tab).css('display', '');
						}
					})(this, m);
					m.load(rate_calculation
					)
					// rate_calculation.call(this, m)
				}
				$('#facts-figures').fadeIn();
			});
		} else {
			this.canvas().show();
		}
	},
	canvas: function() {
		return $('#figures-canvas')
	},
	hide: function() {
		this.canvas().hide();
	}
};
CQ.V.available.push(CQ.V.Figures);

CQ.V.Patch = {
	name: 'Patch',
	current_visualisation: false,
	loaded: function(mass) {

	},
	reset: function() {
		if (this.current_visualisation) {
			this.current_visualisation.reset();
		}
	},
	display: function(mass) {
		$('#patch-canvas').show();
		if(this.current_visualisation) {
			this.current_visualisation.reset();
		}
		if(mass.percentage() < 0.003) {
			this.current_visualisation = GoogleMapVisualisation;
		} else {
			this.current_visualisation = WorldMapVisualisation;
		}
		this.current_visualisation.display(mass);
	},
	hide: function() {
		$('#patch-canvas').hide();
	}
}
CQ.V.available.push(CQ.V.Patch);

CQ.V.current = CQ.V.Patch;

var editing_mass = false;
var first_time = true;

var edit = function(mass, lat, lng, timescale) {
	$('#units-pulldown').val(mass.units, true);
	$('#mass-input').val(mass.quantity);
	$('#mode_user-entry').trigger('click');
	load(mass, lat, lng, timescale);
};
var load = function(mass, lat, lng, timescale) {
	CQ.V.mass = mass;
	if (lat && lng) {
		set_centre(lat, lng);
	}
	if(timescale) { CQ.V.timescale = timescale; }
	// reference mass is used so that scaled fixed masses
	// scale from a fixed point, rather than from a scaled
	// version
	CQ.V.reference_mass = mass;
	CQ.V.must_update = false;
	re_scale();

};
var set_centre = function(lat, lng) {
		GoogleMapVisualisation.centre = {
			lat: parseFloat(lat, 10),
			lng: parseFloat(lng, 10)
		};
};
var set_value = function(select) {
	var values = active_layout('select.value');
	var mass;

	mass = data[CQ.V.layout];
	if (values.length > 0) {
		mass = mass[values.val()];
	}
	load(mass);
};
var scale = function(timescale, mult) {
	timescale = (timescale || CQ.V.timescale);
	CQ.V.timescale = timescale;
	if (CQ.V.must_update) {
		load_user_mass();
	}
	var mass = CQ.V.mass;
	if (typeof mult === 'undefined') { mult = mass.multiplier; }
	mass = CQ.V.reference_mass.scale(mult, timescale);
	CQ.V.onload = function(mass) {
		if (mass.db) {
			$('#db-value').html(mass.to_s());
			$('#db-result').show();
			$('#source').html(mass.source);
			$('#source-wrap').show();
		}
		$('#mass-in-words').html(mass.to_s())
	}
	visualise(mass);
};


var re_scale = function() {
	var multiplier = active_layout('input.multiplier'), mult = CQ.V.mass.multiplier;
	var timescales = active_layout('select.timescale');

	if (multiplier.length > 0) {
		mult = parseFloat(multiplier.val(), 10);
	}
	pluralise_inputs(mult);
	scale(timescales.val(), mult);
};



var pluralise_inputs = function(mult) {
	var transform = null;
	if (mult > 1) {
		active_layout('.plural').show();
		transform = function() {
			var t = $(this);
			if(!t.data('plural')) {
				t.html(t.html() + 's');
				t.data('plural', true);
			}
		}
	} else {
		active_layout('.plural').hide();
		transform = function() {
			var t = $(this);
			if(t.data('plural')) {
				t.html(t.html().replace(/s$/, ''));
				t.data('plural', false);
			}
		}
	}
	active_layout('select.pluralise option').each(transform);
};

var set_units = function(units, silent) {
	$('#units-pulldown').val(units, silent)
};

var calculate = function(mass) {
	try {
		mass.load(function(m) {
			if(CQ.V.onload) {
				CQ.V.onload(mass);
				CQ.V.onload = false;
			}
			if($('#summary').is(':visible')) {
				$('#mass-in-words').flashText('#000', mass.to_s())
			} else {
				$('#mass-in-words').html(mass.to_s())
				$('#summary').fadeIn();
			}
			var results = {
				'volume': mass.volume().to_volume(),
				'patch': mass.patch_area().to_area().toString(),
				'dimension': mass.patch_dimension().to_distance().value +'×'+ mass.patch_dimension().to_distance(),
				'sphere': mass.sphere().dimension.to_distance().toString(),
				'cube': mass.cube().dimension.to_distance().toString()
			};
			var results_pane = $('#volume');
			if (results_pane.is(':visible')) {
				$('#volume .tab').each(function(i, tab) {
					$('.result', tab).each(function() {
						var r = $(this);
						var id = r.attr('id');
						window.setTimeout(function() {
							r.html(results[id]);
							$(tab).flashText('#000')
						}, i*60);
					});
				});
			} else {
				$('#volume strong.result').each(function() {
					var id = $(this).attr('id');
					$(this).html(results[id])
				});
				results_pane.fadeIn(200);
			}
			$('#recalculate').removeClass('changed');
			CQ.V.display(mass);
			Help.refresh();
		});
	} catch (e) {}
};

var visualise = function(mass) {
	Help.off();
	Sharing.update(mass);
	Sharing.hide();
	var calc = function() { calculate(mass); }
	if($('#introduction').length > 0 && $('#introduction:visible')) {
		$('#introduction').fadeOut(300, calc);
	} else {
		calc.call();
	}
};

var active_layout = function(s) {
	var l = '#' + CQ.V.layout;
	if (typeof s === 'string') { l += ' ' + s; }
	return $(l);
};

var calculate_mass = function() {
	var quantity = parseFloat($('#mass-input').val(), 10);
	var units = $('#units-pulldown').val();
	var mass = new UserEmission(quantity, units)
	mass = mass.scale(1, CQ.V.timescale);
	return mass;
};
var load_user_mass = function() {
	var mass = calculate_mass();
	CQ.V.mass = mass;
	CQ.V.reference_mass = mass;
	CQ.V.must_update = false;
	return mass;
};

var Help = {
	init: function() {
		$('.helptext:visible').click(Help.off);
		$('.help').bind('click.help', function(e) {
			var text_id = '#' + $(this).attr("id") + '-popup';
			var text_box = $(text_id);
			var hidden = true;
			if(text_box.is(':visible')) {
				hidden = false;
			}
			Help.off();
			if (hidden) {
				// $('.pointer', text_box).css('left', text_)
				text_box.click(Help.off).addClass('active').attr('title', "Click to close").fadeIn();
				$(this).addClass('active');
			}
			return false;
		});
	},
	refresh: function() {
		$('.help').unbind('click.help');
		this.init();
	},
	off: function() {
		$('.helptext:visible').hide().removeClass('active');
		$('.help.active').removeClass('active');
	}
}
$(document).ready(function() {
	$('#units-pulldown').unitsSelector();
	$('#mode').explorerTabs();
	$('#volume').visualisationTabs();
	$('a.descriptive').visualAlt();

	$('#conversion').submit(function() {
		visualise(load_user_mass());
		return false;
	});

	$('#units-pulldown').change(function() {
		visualise(load_user_mass());
		return false;
	});

	$('#configuration').change(function() {
		if(CQ.V.layout) {
			$('#' + CQ.V.layout).hide();
		}
		CQ.V.layout = $(this).val();
		if (CQ.V.layout === 'user') {
			$('#db-result').hide();
			$('#source-wrap').hide();
		} else {
			$('#' + CQ.V.layout + ' select.value').change(function() {
				set_value(this);
			});
			$('#' + CQ.V.layout + ' select.timescale').add('.multiplier').change(function(e) {
				re_scale();
				e.preventDefault();
				e.stopPropagation();
				return false;
			});
			$('.multiplier').keydown(function(e) {
				// catch return in the multiplier input to stop
				// submission of the conversion form
				if(e.which === 13) {
					re_scale();
					e.preventDefault();
					e.stopPropagation();
					return false;
				}
			});
			$('#' + CQ.V.layout).show();
			set_value(this);
		}
	});
	$('#mass-input').keyup(function(e) {
		if(e.which !== 13) {
			$('#recalculate').trigger('changed');
		}
		// bit of a hack to let us know when things need to be reloaded
		CQ.V.must_update = true;
		return true;
	});

	$('#db-result a').click(function(e) {
		set_value();
		return false;
	});

	$('#recalculate').bind('changed', function() {
		$(this).addClass('changed');
	});
	$('#mass-input').focus();
	Help.init();
	$('.concertina li').click(function() {
		var close = function() {
			$('.concertina li.active').animate({
				height: 37
			}, function() {
				$('.concertina li.active').removeClass('active');
			})
		};
		if(!$(this).hasClass('active')) {
			close();
			$(this).animate({
				height: 230
			}, function() {
				$(this).addClass('active')
			})
		} else {
			close();
		}
		return false;
	});
	if(!editing_mass) {
		if (typeof geo_ip !== 'undefined' )  {
			var db_country = geo_ip[GoogleMapVisualisation.country] || 'uk';
			$('#percapita_emissions select.value').val(db_country)
			$('#configuration').trigger('change')
		}
	}
	Sharing.init();
});

var Sharing = {
	sites: [],
	visible: false,
	title: "",
	preserve_location: true,
	init: function() {
		if (this.menu().is(":visible")) { this.visible = true; }

		var c = (function(sharing) {
			return function() {
				sharing.toggle();
			}
		})(this);

		$('#share-mass').click(c);
		this.menu().click(function() {
			return false;
		});

		var update = (function(sharing) {
			return function(e) {
				e.stopPropagation();
				sharing.update_location(this);
				return true;
			}
		})(this);
		$('#share-location').click(update);
		$('label[for="share-location"]').click(function(e) {
			e.stopPropagation();
			return true;
		});
		update = (function(sharing) {
			return function() {
				sharing.update_title(this);
			}
		})(this);
		$('input#share-title').keyup(update);

		update = (function(sharing) {
			return function() {
				sharing.refresh();
				return false;
			}
		})(this);
		$('#share-mass form').bind('update', update);

		$('#share-mass form').submit(function() {
			$(this).trigger('update');
			return false;
		});
		this.link().click(function(e) {
			e.stopPropagation();
			return true;
		})
		c = (function(sharing) {
			return function() {
				sharing.toggle();
			}
		})(this);
		$("button.done").click(c);
		this.title = $('input#share-title').val();
		for (var i = 0; i < this.sites.length; i++) {
			var s = this.sites[i];
			s.init(this.menu());
		};
	},
	update: function(mass) {
		this.mass = mass;
	},
	toggle: function() {
		if(this.visible) {
			this.hide();
		} else {
			this.show();
		}
	},
	hide: function() {
		this.menu().fadeOut('fast');
		this.visible = false;
		$('#share-mass').removeClass('active');
	},
	show: function() {
		this.refresh();
		this.menu().fadeIn('fast');
		this.visible = true;
		$('#share-mass').addClass('active');
	},
	url: function() {
		var l = window.location;
		this._url = l.protocol + '//' + l.host + this.mass.mass.permalink();
		var t = this.title_attr(), l = this.location_attr(), qs = '', s = this.timescale();
		if (t || l || s) {
			qs = "?";
			if (t) { qs += t; }
			if (l) {
				if (t) { qs += "&"; }
				qs += l;
			}
			if(s) {
				if (t || l) { qs += "&"; }
				qs += s;
			}
		}
		return this._url + qs;
	},
	timescale: function() {
		var t = CQ.V.timescale;
		if (t === 'year') {
			return false;
		} else if (t === 'day') {
			return 's=d';
		} else if (t === 'second') {
			return 's=s';
		}
		return false;
	},
	title_attr: function() {
		if (this.title && this.title !== "") {
			var et = escape( this.title.replace(/ /g, '_') );
			return "t=" + et;
		}
		return false;
	},
	location_attr: function() {
		if (this.preserve_location) {
			var c = this.map_coords();
			return "l=" + c.lat + "," + c.lng
		}
		return false;
	},
	menu: function() {
		return $("#sharing-options");
	},
	link: function() {
		return $('#mass-url');
	},
	update_location: function(input) {
		var l = $('#share-location');
		this.preserve_location = l.attr( 'checked' );
		this.refresh();
	},
	update_title: function(input) {
		this.title = $('input#share-title').val();
		this.refresh();
	},
	map_coords: function() {
		return GoogleMapVisualisation.centre;
	},
	refresh: function() {
		var u = this.url(), c = this.map_coords();
		this.link().attr('href', u).text(u);
		$('#share-coordinates').text(c.lat.fix(3) + ', ' + c.lng.fix(3));
		for (var i = 0; i < this.sites.length; i++) {
			var s = this.sites[i];
			s.refresh(this.url(), this.title);
		};
	},
	map_moved: function() {
		if (this.visible) {
			this.refresh();
		}
	},
	Site: {
		link: "",
		title: "",
		className: "",
		description: "",
		init: function(parent) {
			var c = (function(site) {
				return function(e) {
					return site.click(e);
				}
			})(this);
			this.icon = $('.social .'+this.className, parent);
			this.icon.click(c)
			this.description = this.icon.attr('title');
			this.icon.attr('title', '');
			c = (function(site) {
				return function(e) {
					site.message_show(site.description);
				};
			})(this);
			this.icon.mouseenter(c);
			c = (function(site) {
				return function(e) {
					site.message_hide();
				};
			})(this);
			this.icon.mouseleave(c);
		},
		refresh: function(link, title) {
			this.link = link;
			this.title = title;
		},
		url: function() {
			return null;
		},
		click: function() {
			return false;
		},

		progress_show: function() {
			var p = this.icon.position(), s = this.progress_spinner();
			s.css('left', p.left);
			this.progress_spinner().show();
		},
		progress_hide: function() {
			this.progress_spinner().hide();
		},
		progress_spinner: function() {
			return $('#share-mass .social .progress');
		},
		message_show: function(m) {
			$('#share-messages').text(m);
		},
		message_hide: function() {
			$('#share-messages').text('');
		},
		message_holder: function() {
			return $('#share-messages');
		}
	},
	Twitter: function() {

	},
	Bitly: {
		shorten: function(url, requester_callback) {
			// can't use bitly directly because of cross domain request restrictions
			// what a pain
			var cb = (function(bitly, callback) {
				return function(data) {
					var short_url;
					for (var r in data.results) {
						short_url = data.results[r].shortUrl;
						break;
					}
					callback(short_url)
				};
			})(this, requester_callback);
			BitlyCB.shorten_response = cb;
			BitlyClient.call('shorten', {'longUrl': url}, 'BitlyCB.shorten_response');
		}
	}
};
Object.extend(Sharing.Twitter.prototype, Sharing.Site, {
	className: "twitter",
	url: function() {
		return "http://twitter.com/home"
	},
	click: function() {
		var cb = (function(twitter) {
			return function(short_url){
				var s = {
					status: twitter.title + ((twitter.title !== '') ? ' ' : '' ) + short_url
				}
				// the following doesn't work -- get's blocked by popup blockers
				// window.open(twitter.url() + "?" + $.param(s), '_blank');
				window.location.href = twitter.url() + "?" + $.param(s);

			}

		})(this);
		this.progress_show();
		Sharing.Bitly.shorten(this.link, cb);
		return false;
	}
});
Sharing.sites.push(new Sharing.Twitter());
