function mid(a, b) {
	if (a.length > 1 && b.length > 1) {
		return [ (a[a.length - 2][1] + b[b.length - 2][1]) / 2,
				(a[a.length - 1][1] + b[b.length - 1][1]) / 2 ];
	} else {
		return [];
	}
}

(function($) {
	var cometd = $.cometd;

	$(document)
			.ready(function() {

				var refreshOnData = false;

				function reset() {
					refreshOnData = false;
					_connectionSucceeded();
				}

				// Idempotent function called every time the connection
					// with the Bayeux server is (re-)established
					function _connectionSucceeded() {

						$('#placeholder').removeClass('disconnected');

						var london_buy = [];
						var zurich_buy = [];
						var nyc_buy = [];

						var london_sell = [];
						var zurich_sell = [];
						var nyc_sell = [];

						var gold_spot = [];
						var silver_spot = [];

						var london_silver_sell = [];
						var london_silver_buy = [];

						security_series = {
							'gold' : [ {
								tooltip : 'London Buy',
								id : 'london_buy',
								data : london_buy,
								color : 'red',
								lines : {
									lineWidth : 0.4
								}
							}, {
								label : 'London',
								tooltip : 'London Sell',
								color : 'red',
								data : london_sell,
								lines : {
									show : true,
									lineWidth : 0.4,
									fill : 0.15
								},
								fillBetween : 'london_buy',
								midprice : function() {
									return mid(london_sell, london_buy);
								}
							}, {
								id : 'zurich_buy',
								tooltip : 'Zurich Buy',
								color : 'blue',
								data : zurich_buy,
								lines : {
									lineWidth : 0.4
								}
							}, {
								tooltip : 'Zurich Sell',
								label : 'Zurich',
								color : 'blue',
								data : zurich_sell,
								lines : {
									show : true,
									lineWidth : 0.4,
									fill : 0.15
								},
								fillBetween : 'zurich_buy',
								midprice : function() {
									return mid(zurich_sell, zurich_buy);
								}
							}, {
								id : 'nyc_buy',
								tooltip : 'NYC Buy',
								color : 'green',
								data : nyc_buy,
								lines : {
									lineWidth : 0.4
								}
							}, {
								label : 'New York Gold',
								tooltip : 'NYC Sell',
								color : 'green',
								data : nyc_sell,
								lines : {
									show : true,
									lineWidth : 0.4,
									fill : 0.15
								},
								fillBetween : 'nyc_buy',
								midprice : function() {
									return mid(nyc_sell, nyc_buy);
								}
							}, {
								label : 'Gold Spot',
								id : 'gold_spot',
								tooltip : 'Gold Spot',
								color : 'rgb(80, 80, 80)',
								data : gold_spot,
								lines : {
									lineWidth : 4
								},
								midprice : function() {
									return mid(gold_spot, gold_spot);
								}
							} ],
							'silver' : [
									{
										id : 'london_silver_buy',
										tooltip : 'London Silver Buy',
										color : 'rgb(80, 80, 80)',
										data : london_silver_buy,
										lines : {
											lineWidth : 0.4
										}
									},
									{
										id : 'london_silver_sell',
										label : 'London Silver',
										tooltip : 'London Silver Sell',
										color : 'rgb(80, 80, 80)',
										data : london_silver_sell,
										lines : {
											fill : 0.15,
											lineWidth : 0.4
										},
										fillBetween : 'london_silver_buy',
										midprice : function() {
											return mid(london_silver_sell,
													london_silver_buy);
										}
									},
									{
										id : 'silver_wholesale',
										label : 'Spot Silver',
										tooltip : 'Spot Silver',
										color : 'black',
										data : silver_spot,
										lines : {
											lineWidth : 0.4
										},
										midprice : function() {
											return mid(silver_spot, silver_spot);
										}
									} ]
						};

						function _plotChart() {

							var plot = $
									.plot(
											$("#placeholder"),
											security_series[config.series],
											{
												xaxis : {
													mode : 'time',
													max : new Date().getTime(),
													min : new Date().getTime()
															- config.duration
												},
												grid : {
													hoverable : true,
													clickable : true
												},
												legend : {
													position : 'nw',
													labelFormatter : function(
															label, series) {
														var mid = series
																.midprice();
														var latestValue = mid[mid.length - 1];
														var isDown = false;
														if (series.data.length > 1) {
															isDown = latestValue < mid[mid.length - 2];
														}
														var figClass = isDown ? 'down'
																: 'up';
														if (latestValue == mid[mid.length - 2]) {
															figClass = "";
														}
														return '<span class="legend">'
																+ label
																+ '<span style="float: right; margin: 0 0.5em 0 1em;">  ( <span class="'
																+ figClass
																+ '">'
																+ Math
																		.round(latestValue)
																+ '</span> )</span></span>';
													}
												}
											});

							function showTooltip(x, y, contents) {
								$('<div id="tooltip">' + contents + '</div>')
										.css( {
											position : 'absolute',
											display : 'none',
											top : y + 5,
											left : x + 5,
											border : '1px solid #fdd',
											padding : '2px',
											'background-color' : '#fee',
											opacity : 0.80
										}).appendTo("body").fadeIn(200);
							}

							var previousPoint = null;
							$("#placeholder")
									.unbind("plothover")
									.bind(
											"plothover",
											function(event, pos, item) {
												$("#x").text(pos.x.toFixed(2));
												$("#y").text(pos.y.toFixed(2));
												if (item) {
													if (previousPoint != item.datapoint) {
														previousPoint = item.datapoint;

														$("#tooltip").remove();
														var x = item.datapoint[0]
																.toFixed(2), y = item.datapoint[1]
																.toFixed(2);
														x = new Date(pos.x);
														x.setTime(x);
														x = x.toUTCString();
														showTooltip(
																item.pageX,
																item.pageY,
																	x
																	+ "<br />"
																	+ y
																);
													}
												} else {
													$("#tooltip").remove();
													previousPoint = null;
												}
											});
						}

						function _addPrice(message, data) {
							data
									.push( [ message.data.time,
											message.data.price ]);
							data = data.sort(function(a, b) {
								return a[0] - b[0];
							});
							data = data.filter(function(a) {
								return a[0] < new Date().getTime()
										- (config.duration * 2);
							});

							if (refreshOnData) {
								_plotChart();
							}
						}
						;

						cometd
								.batch(function() {

									cometd
											.subscribe(
													'/price/AUXZU/' + config.currency + '/BUY',
													function(message) {
														_addPrice(message,
																zurich_buy);
													});
									cometd
											.subscribe(
													'/price/AUXLN/' + config.currency + '/BUY',
													function(message) {
														_addPrice(message,
																london_buy);
													});
									cometd
											.subscribe(
													'/price/AUXNY/' + config.currency + '/BUY',
													function(message) {
														_addPrice(message,
																nyc_buy);
													});

									cometd
											.subscribe(
													'/price/AUXZU/' + config.currency + '/SELL',
													function(message) {
														_addPrice(message,
																zurich_sell);
													});
									cometd
											.subscribe(
													'/price/AUXLN/' + config.currency + '/SELL',
													function(message) {
														_addPrice(message,
																london_sell);
													});
									cometd
											.subscribe(
													'/price/AUXNY/' + config.currency + '/SELL',
													function(message) {
														_addPrice(message,
																nyc_sell);
													});

									cometd
											.subscribe(
													'/price/AUX/' + config.currency + '/BUY',
													function(message) {
														_addPrice(message,
																gold_spot);
													});
									cometd
											.subscribe(
													'/price/AGXLN/' + config.currency + '/SELL',
													function(message) {
														_addPrice(message,
																london_silver_sell);
													});
									cometd
											.subscribe(
													'/price/AGXLN/' + config.currency + '/BUY',
													function(message) {
														_addPrice(message,
																london_silver_buy);
													});
									cometd
											.subscribe(
													'/price/AGX/' + config.currency + '/BUY',
													function(message) {
														_addPrice(message,
																silver_spot);
													});

									cometd.subscribe('/chart/start', function(
											message) {
										_plotChart();
										refreshOnData = true;
									});

									cometd.publish('/datasince', {
										since : new Date().getTime()
												- config.duration
									});

								});
					}

					function _connectionBroken() {
						$('#placeholder').addClass('disconnected');
						refreshOnUpdate = false;
					}

					// Function that manages the connection status with the
					// Bayeux server
					var _connected = false;
					function _metaConnect(message) {
						var wasConnected = _connected;
						_connected = message.successful === true;
						if (!wasConnected && _connected) {
							_connectionSucceeded();
						} else if (wasConnected && !_connected) {
							_connectionBroken();
						}
					}

					// Disconnect when the page unloads
					$(window).unload(function() {
						cometd.disconnect();
					});

					var cometURL = location.protocol + "//" + location.host
							+ contextPath + "/cometd";
					cometd.configure( {
						url : cometURL,
						logLevel : 'debug'
					});

					cometd.addListener('/meta/connect', _metaConnect);

					cometd.handshake();

					$("#duration").slider( {
						range : 'max',
						value : config.duration / (60 * 1000),
						min : 1,
						max : 60 * 12,
						change : $.throttle( 550,
							function(event, ui) {
								config.duration = ui.value * 60 * 1000;
								$.bbq.pushState(config);
							}
						)});

					$('#currency li a').click($.debounce( 250,
						function() {
							config.currency = this.id;
							$.bbq.pushState(config);
					}));

					$('#series li a').click( $.debounce( 250,
						function() {
							config.series = this.id;
							$.bbq.pushState(config);
					}));

					$(window).resize(function() {
						_plotChart();
					});

					$(window)
							.bind(
									'hashchange',
									function(e) {
										$.extend(config, $.bbq.getState());
										reset();
										$('#currency li a, #series li a')
												.removeClass('selected');
										$(
												'#' + config.currency + ', #'
														+ config.series)
												.addClass('selected');
									});

					$(window).trigger('hashchange');
				});
})(jQuery);