/*
 * jQuery Hotkeys Plugin
 * Copyright 2010, John Resig
 * Dual licensed under the MIT or GPL Version 2 licenses.
 *
 * Based upon the plugin by Tzury Bar Yochay:
 * http://github.com/tzuryby/hotkeys
 *
 * Original idea by:
 * Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
*/

(function(jQuery){

	jQuery.hotkeys = {
		version: "0.8",

		specialKeys: {
			8: "backspace", 9: "tab", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause",
			20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home",
			37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del",
			96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7",
			104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/",
			112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8",
			120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 191: "/", 224: "meta"
		},

		shiftNums: {
			"`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&",
			"8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<",
			".": ">",  "/": "?",  "\\": "|"
		}
	};

	function keyHandler( handleObj ) {
		// Only care when a possible input has been specified
		if ( typeof handleObj.data !== "string" ) {
			return;
		}

		var origHandler = handleObj.handler,
			keys = handleObj.data.toLowerCase().split(" ");

		handleObj.handler = function( event ) {
			// Don't fire in text-accepting inputs that we didn't directly bind to
			// vlad: removed, as undesired.
			//if ( this !== event.target && (/textarea|select/i.test( event.target.nodeName ) ||
				 //event.target.type === "text") ) {
				//return;
			//}

			// Keypress represents characters, not special keys
			var special = event.type !== "keypress" && jQuery.hotkeys.specialKeys[ event.which ],
				character = String.fromCharCode( event.which ).toLowerCase(),
				key, modif = "", possible = {};

			// check combinations (alt|ctrl|shift+anything)
			if ( event.altKey && special !== "alt" ) {
				modif += "alt+";
			}

			if ( event.ctrlKey && special !== "ctrl" ) {
				modif += "ctrl+";
			}

			// TODO: Need to make sure this works consistently across platforms
			if ( event.metaKey && !event.ctrlKey && special !== "meta" ) {
				modif += "meta+";
			}

			if ( event.shiftKey && special !== "shift" ) {
				modif += "shift+";
			}

			if ( special ) {
				possible[ modif + special ] = true;

			} else {
				possible[ modif + character ] = true;
				possible[ modif + jQuery.hotkeys.shiftNums[ character ] ] = true;

				// "$" can be triggered as "Shift+4" or "Shift+$" or just "$"
				if ( modif === "shift+" ) {
					possible[ jQuery.hotkeys.shiftNums[ character ] ] = true;
				}
			}

			for ( var i = 0, l = keys.length; i < l; i++ ) {
				if ( possible[ keys[i] ] ) {
					return origHandler.apply( this, arguments );
				}
			}
		};
	}

	jQuery.each([ "keydown", "keyup", "keypress" ], function() {
		jQuery.event.special[ this ] = { add: keyHandler };
	});

})( jQuery );



chatHandler = {
	size: 400,
	isShown: false,
	isOn: false,
	chatCookie: null,
	chatCookieExpires: 3*60*1000,
	updateInterval: 5000,
	wasBannerShown: false,
	// setup by the page
	chatCtlUrl: null,
	// setup by the page
	chatPostUrl: null,
	// setup by the page
	updateUrl: null,
	// setup by the page
	standaloneUrl: null,

	lastChatUpdate: null,
	// NB: do not set directly. Use setIsUpdating.
	isUpdating: false,
	pendingFun: null,

	isStandalone: false,

	standaloneWindow: null,

	setIsUpdating: function(val) {
		if (val == false && chatHandler.pendingFun) {
			chatHandler.isUpdating = false;
			chatHandler.pendingFun();
			chatHandler.pendingFun = null;
		} else {
			chatHandler.isUpdating = val;
		}
	},

	lastDisplayedMessage: -1,

	updaterTimer: null,

	scrollToBottom: function() {
		$("#chat-content").animate({scrollTop: $("#chat-content").prop('scrollHeight')}, 250);
	},

	onPostDone: function(data) {
		chatHandler.lastChatUpdate = new Date();
		chatHandler.setIsUpdating(false);
		if (data.result == 'ok') {
			chatHandler.chatCookie = {value: data.cookie, updated: new Date(), kingdom_id: data.kingdom_id};
			chatHandler.addMessages(data.chats);

		} else {
			chatHandler.addMessages([
				{error: true, post_province_name: 'SYSTEM', post_data: 'Posting failed: ' + data.error_reason}],
				true);
		}
	},

	onPostError: function(req, textStatus, err) {
		chatHandler.lastChatUpdate = new Date();
		chatHandler.setIsUpdating(false);
		chatHandler.addMessages([
				{error: true, post_province_name: 'SYSTEM', post_data: 'Posting failed: ' + textStatus}
			], true);
	},

	onSubmit: function() {
		if (chatHandler.isUpdating) {
			if (!chatHandler.pendingFun) {
				chatHandler.pendingFun = chatHandler.onSubmit;
			}
			return;
		}

		var data = $('#chat-submit-line').val();
		chatHandler.setIsUpdating(true);
		$.ajax({
				type: 'post',
				url: chatHandler.chatPostUrl + (chatHandler.chatCookie ? chatHandler.chatCookie.value : ''),
				data: {message: data},
				success: chatHandler.onPostDone,
				error: chatHandler.onPostError,
				cache: false
			});

		$('#chat-submit-line').val('');
		$('#chat-submit-line').watermark('');
		$('#chat-submit-line').focus();
	},

	onChatUpdateDone: function(data) {
		chatHandler.lastChatUpdate = new Date();
		chatHandler.setIsUpdating(false);
		if (data.result == 'ok') {
			chatHandler.addMessages(data.chats);
			chatHandler.updaterTimer = setTimeout("chatHandler.contentsUpdater();", chatHandler.updateInterval);
		} else {
			chatHandler.addMessages([
				{error: true, post_province_name: 'SYSTEM', post_data: 'Update failed: ' + data.error_reason}
			], true);
		}
	},

	onChatUpdateError: function(req, textStatus, err) {
		chatHandler.setIsUpdating(false);
		chatHandler.addMessages([
				{error: true, post_province_name: 'SYSTEM', post_data: 'Update failed: ' + textStatus}
			], true);
	},

	contentsUpdater: function() {
		if (chatHandler.isUpdating || !chatHandler.isShown) {
			return;
		}

		var oldCookie = (chatHandler.chatCookie ? chatHandler.chatCookie.value : null);

		if ((!chatHandler.chatCookie) ||
			 ((new Date()) - chatHandler.chatCookie.updated.getTime() > chatHandler.chatCookieExpires)) {
			 chatHandler.setIsUpdating(true);
			 chatHandler.lastChatUpdate = new Date();
			 $.ajax({
					url: chatHandler.chatCtlUrl + (oldCookie ? oldCookie : ''),
				success: chatHandler.onChatCtlDone,
				error: chatHandler.onChatCtlError,
				cache: false
			 });
		} else {
			chatHandler.setIsUpdating(true);

			$.ajax({
					url: chatHandler.updateUrl + chatHandler.chatCookie.value + '/'  + chatHandler.chatCookie.kingdom_id +
						'/' + chatHandler.lastDisplayedMessage,
					success: chatHandler.onChatUpdateDone,
					error: chatHandler.onChatUpdateError,
					cache: false
				});
		}
	},

	startUpdater: function() {
		if ((new Date()) - chatHandler.lastChatUpdate.getTime() > chatHandler.updateInterval) {
			chatHandler.contentsUpdater();
		} else {
			chatHandler.updaterTimer = setTimeout("chatHandler.contentsUpdater();", chatHandler.updateInterval);
		}
	},

	addMessages: function(msgs, forceAdd) {
		var newMsgs = [];
		if (forceAdd) {
			newMsgs = msgs;
		} else {
			var maxId = chatHandler.lastDisplayedMessage;
			newMsgs = $.grep(msgs, function(el) {
					maxId = Math.max(maxId, el.post_id);
					return el.post_id > chatHandler.lastDisplayedMessage;
				});
			chatHandler.lastDisplayedMessage = maxId;
		}
		$.each(newMsgs.reverse(), function(index, el) {
				var t = $('<div/>', {'class': 'chat-line' + (el.error ? ' chat-error' : '')});
				if (el.timestamp) {
					var x = (new Date());
					x.setISO8601(el.timestamp);
					t.append($('<span/>', {'class': 'chat-line-time',
							text: sprintf("[%02u:%02u] ", x.getHours(), x.getMinutes())}));
				}
				t.append($('<span/>', {'class': 'chat-line-sender', text: el.post_province_name + '> '}));
				if (el.safe_data) {
					t.append(el.post_data);
				} else {
					t.append($('<span/>', {text: el.post_data}));
				}
				t.appendTo($('#chat-content'));
			});
		if (newMsgs.length > 0) {
			chatHandler.scrollToBottom();
		}
	},

	onChatCtlDone: function(data) {
		chatHandler.lastChatUpdate = new Date();
		chatHandler.setIsUpdating(false);
		if (data.result == 'ok') {
			chatHandler.chatCookie = {value: data.cookie, updated: new Date(), kingdom_id: data.kingdom_id};
			chatHandler.addMessages(data.chats);
			if ((!chatHandler.wasBannerShown) && (data.banner)) {
				chatHandler.addMessages([
						{error: true, post_province_name: 'SYSTEM', post_data: data.banner, safe_data: true}
					], true);
			}
			chatHandler.wasBannerShown = true;
			chatHandler.startUpdater();
		} else {
			chatHandler.addMessages([
				{error: true, post_province_name: 'SYSTEM', post_data: 'Chat error: ' + data.error_reason}
			], true);
		}

	},

	onChatCtlError: function(req, textStatus, err) {
		chatHandler.lastChatUpdate = new Date();
		chatHandler.setIsUpdating(false);
		chatHandler.addMessages([
				{error: true, post_province_name: 'SYSTEM', post_data: 'Chat error: ' + textStatus}
			], true);
	},

	chatUpdate: function() {
		if (chatHandler.isUpdating || !chatHandler.isShown) {
			return;
		}
		var oldCookie = (chatHandler.chatCookie ? chatHandler.chatCookie.value : null);

		if ((!chatHandler.chatCookie) ||
			 ((new Date()) - chatHandler.chatCookie.updated.getTime() > chatHandler.chatCookieExpires)) {
			 chatHandler.setIsUpdating(true);
			 chatHandler.lastChatUpdate = new Date();
			 $.ajax({
					url: chatHandler.chatCtlUrl + (oldCookie ? oldCookie : ''),
				success: chatHandler.onChatCtlDone,
				error: chatHandler.onChatCtlError,
				cache: false
			 });
		} else {
			chatHandler.startUpdater();
		}
	},

	updateContentHeight: function() {
		if (chatHandler.isStandalone) {
			$('#chatter-box').height(chatHandler.size);
		}
		$('#chat-content').height(chatHandler.size - $('#chat-submit').height());
	},

	launchStandalone: function() {
		if (chatHandler.isShown) {
			chatHandler.bringUp();
			chatHandler.bringUp = chatHandler.launchStandalone;
		}

		if (chatHandler.standaloneWindow == null || chatHandler.standaloneWindow.closed)	{
			chatHandler.standaloneWindow = window.open(chatHandler.standaloneUrl, 'utopia_chat',
					'resizable=yes,height=' + Math.floor($(window).height() * 0.6) +
					',width=' + Math.floor($(window).width() * 0.7) +
					'toolbar=no,menubar=no,location=no');
		}
		if (chatHandler.standaloneWindow && chatHandler.standaloneWindow.focus) {
			chatHandler.standaloneWindow.focus();
		}

		// Hide the link on the left-hand-side navigation pane
		//$('#nav-kingdom-chat').replaceWith("Chat open");
		return false;
	},

	bringUp : function() {
		if (!chatHandler.isOn) {
			if (!chatHandler.isStandalone) {
				chatHandler.size = Math.floor($(window).height() * 0.6);
			} else {
				chatHandler.size = Math.floor($(window).height());
			}
			$('#chatter-box').height(chatHandler.size);
			$('#chat-submit-line').watermark("Click here to enter your message; press Enter to post.");
			chatHandler.updateContentHeight();
		}

		if (!chatHandler.isStandalone) {
			if (!chatHandler.isShown) {
				chatHandler.scrollToBottom();
				$('#chatter-box').slideToggle('slow', function() {
					$('#chatter-box').resizable({handles: 's',
						stop: function(event, ui) {
							chatHandler.size = ui.size.height;
							chatHandler.updateContentHeight();
						},
						disabled: false
						});
				});
			} else {
				$('#chatter-box').resizable({disabled: true});
				$('#chatter-box').slideToggle('slow');
				// Cancel updater
				if (chatHandler.updateTimer) {
					clearTimeout(chatHandler.updaterTimer);
				}
			}
		} else {
			// We need to be aware of when the window resizes
			$(window).resize(function () {
					chatHandler.size = $(window).height();
					chatHandler.updateContentHeight();
				});
		}

		chatHandler.isShown = !chatHandler.isShown;
		chatHandler.isOn = true;
		chatHandler.chatUpdate();
	},

	init: function () {
		// bringUp can be changed at runtime when a popup is created, so we proxy it here.
		$(document).bind('keypress', 'ctrl+~',
			function(h) { chatHandler.bringUp(h); } );
	}
}



