/**
 * meCommentThread clientside functionality
 * 
 * @depencies jQuery
 */

var meCommentThread = (function() {
	var pub = {};
	
	/**
	 * @var string commandProxy URL of the command proxy
	 */
	var commandProxy = null;
	
	/**
	 * @var string commandParamName Parameter name used to pass ajax commands
	 */
	var commandParamName = null;
	
	/**
	 * @var string cookiePath Path under which to set cookies
	 */
	var cookiePath = null;
	
	/**
	 * @var map localizations Localizations
	 */
	var localizations = {};
	
	
	/**
	 * Get localized string
	 * 
	 * @param string l Localization ident
	 * @return string
	 */
	function getLoc(l) {
		if(localizations[l] === undefined)
			loadLocalizations();
		
		if(localizations[l] === undefined)
			return l;
		
		return localizations[l];
	}
	
	/**
	 * Perform serverside command
	 * 
	 * @param string cmd Command
	 * @param object args Command parameters
	 * @param function callback Callback to perform after command has executed
	 * @return void
	 */
	function sendCommand(cmd, args, callback) {
		var url = commandProxy + "?" + commandParamName + "=" + cmd;
		var success = function(data) {
			callback.call(this, data);
		};
		
		$.ajax({
			"url" : url,
			"data" : args,
			"async" : true,
			"cache" : false,
			"type" : "POST",
			"dataType" : "json",
			"success" : success
		});
	}
	
	/**
	 * Load localizations from server
	 * 
	 * @return void
	 */
	function loadLocalizations() {
		var url = commandProxy + "?" + commandParamName + "=" + "getLocalizations";
		
		//perform syncronous ajax request
		$.ajax({
			"url" : url,
			"async" : false,
			"timeout" : 3,
			"cache" : true,
			"type" : "POST",
			"dataType" : "json",
			"success" : (function(data) {
				localizations = data.loc;
			})
		});
	}
	
	/**
	 * Show preview for message
	 * Options:
	 * 	tid:	Thread ID
	 * 	pid:	Message parent ID
	 * 
	 * @param object opts Options
	 * @return void
	 */
	function showPreview(opts) {
		var args = {
			"tid": opts.tid,
			"pid": opts.pid,
			"title": $("#message-input-title-" + opts.tid + "-" + opts.pid).val(),
			"author": $("#message-input-author-" + opts.tid + "-" + opts.pid).val(),
			"message": $("#message-input-content-" + opts.tid + "-" + opts.pid).val()
		};
		
		toggleEditorLoadIndicator(opts.tid, opts.pid, true);
		sendCommand("getMessagePreview", args, function(data) {
			$("#message-preview-" + opts.tid + "-" + opts.pid).html(data.html);
			toggleEditorLoadIndicator(opts.tid, opts.pid, false);
		});
	}
	
	/**
	 * Send message for save
	 * Options:
	 * 	tid:	Thread ID
	 * 	pid:	Message parent ID
	 * 
	 * @param object opts Options
	 * @return void
	 */
	function sendMessage(opts) {
		var args = {
			"tid": opts.tid,
			"pid": opts.pid,
			"title": $("#message-input-title-" + opts.tid + "-" + opts.pid).val(),
			"author": $("#message-input-author-" + opts.tid + "-" + opts.pid).val(),
			"message": $("#message-input-content-" + opts.tid + "-" + opts.pid).val()
		};
		
		toggleEditorLoadIndicator(opts.tid, opts.pid, true);
		sendCommand("addMessage", args, function(data) {
			toggleEditorLoadIndicator(opts.tid, opts.pid, false);
			if(data.error !== undefined) {
				$("#message-error-" + opts.tid + "-" + opts.pid).html(data.error);
				return;
			}
			
			//save author name to cookie
			if(cookiePath !== null)
				setCookie("author", args.author, 2592000, cookiePath);
			
			$("#thread-tree-" + opts.tid).html(data.html);
			clearEditor(opts.tid, opts.pid);
			
			//if message is initially visible, scroll to it
			if(data.visible) {
				$("#message-node-" + data.mid).addClass("message-node-new");
				scrollToElement("#message-node-" + data.mid);
			//message is not visible, but notice was received
			} else if(data.notice) {
				$("#message-playground-" + opts.pid).html(data.notice);
				scrollToElement("#message-node-" + opts.pid);
			}
		});
	}
	
	/**
	 * Set cookie
	 * 
	 * @param string key Cookie name
	 * @param string value Cookie value
	 * @param int expiry Expiry time in seconds
	 * @param string path Cookie path
	 * @return void
	 */
	function setCookie(key, value, expiry, path) {
		var date = new Date();
		if(expiry === undefined || expiry === null)
			expiry = 2592000;
		date.setTime(date.getTime() + Math.floor(expiry * 1000));
		if(path === undefined || path === null)
			path = "/";
		
		var str = "meCommentThread[" + escape(key) + "]=" + escape(value) + ";"
			+ " expires=" + date.toGMTString() + "; path=" + escape(path);
		document.cookie = str;
	}
	
	/**
	 * Scroll to given element ID
	 * 
	 * @param string eid Element ID
	 * @return void
	 */
	function scrollToElement(eid) {
		var offset = ($(eid).offset()).top - 50;
		if(offset > 0)
			window.scrollTo(0, offset);
	}
	
	/**
	 * Clear editor inputs
	 * 
	 * @param int tid Thread ID
	 * @param int mid Message ID
	 * @return void
	 */
	function clearEditor(tid, mid) {
		$("#message-input-title-" + tid + "-" + mid).val("");
		$("#message-input-author-" + tid + "-" + mid).val("");
		$("#message-input-content-" + tid + "-" + mid).val("");
		$("#message-preview-" + tid + "-" + mid).remove();
	}
	
	/**
	 * Set event handlers for message editor buttons
	 * 
	 * @param int tid Thread ID
	 * @param int pid Parent message ID
	 * @return void
	 */
	function hookEditorButtons(tid, pid) {
		//apply event handler for preview button
		$("#message-preview-btn-" + tid + "-" + pid).click(function() {
			showPreview({"tid": tid, "pid": pid});
		});
		
		//apply event handler for send button
		$("#message-send-btn-" + tid + "-" + pid).click(function() {
			sendMessage({"tid": tid, "pid": pid});
		});
		
		//apply event handler for cancel button
		$("#message-cancel-btn-" + tid + "-" + pid).click(function() {
			$("#message-playground-" + pid).html("<!-- -->");
		});
		
		//apply event handlers for formatting buttons
		$("#message-fmtbtn-bold-" + tid + "-" + pid).click(function() {
			formatMessage(tid, pid, "b");
		});
		$("#message-fmtbtn-italic-" + tid + "-" + pid).click(function() {
			formatMessage(tid, pid, "i");
		});
		$("#message-fmtbtn-underline-" + tid + "-" + pid).click(function() {
			formatMessage(tid, pid, "u");
		});
		$("#message-fmtbtn-quote-" + tid + "-" + pid).click(function() {
			formatMessage(tid, pid, "quote");
		});
	}
	
	/**
	 * Apply formatting code to selected area in message content
	 * 
	 * @param int tid Thread ID
	 * @param int id Message ID
	 * @param string tag Formatting tag
	 * @return void
	 */
	function formatMessage(tid, id, tag) {
		var txt = getSelectedText(tid, id);
		txt = "<" + tag + ">" + txt + "</" + tag + ">";
		replaceSelectedText(tid, id, txt);
	}
	
	/**
	 * Get currently selected text in message content
	 * 
	 * @param int tid Thread ID
	 * @param int id Message ID
	 * @return string Selected text
	 */
	function getSelectedText(tid, id) {
		var el = $("#message-input-content-" + tid + "-" + id).get(0);
		if(document.selection) {
			el.focus();
			return (document.selection.createRange()).text;
		} else {
			return el.value.substring(el.selectionStart, el.selectionEnd);
		}
	}
	
	/**
	 * Replace currently selected text in message content with repl
	 * 
	 * @param int tid Thread ID
	 * @param int id Message ID
	 * @param string repl Replacement string
	 * @return void
	 */
	function replaceSelectedText(tid, id, repl) {
		var el = $("#message-input-content-" + tid + "-" + id).get(0);
		if(document.selection) {
			el.focus();
			(document.selection.createRange()).text = repl;
		} else {
			var val = el.value;
			el.value = val.substring(0, el.selectionStart) + repl + val.substring(el.selectionEnd);
		}
	}
	
	/**
	 * Toggle editor ajax load indicator
	 * 
	 * @param int tid Thread ID
	 * @param int id Message ID
	 * @param boolean show Whether to show indicator
	 */
	function toggleEditorLoadIndicator(tid, id, show) {
		$("#editor-load-indicator-" + tid + "-" + id).css("visibility", show ? "visible" : "hidden");
	}
	
	/**
	 * Toggle message ajax load indicator
	 * 
	 * @param int tid Thread ID
	 * @param int id Message ID
	 * @param boolean show Whether to show indicator
	 */
	function toggleMessageLoadIndicator(tid, id, show) {
		$("#message-load-indicator-" + tid + "-" + id).css("visibility", show ? "visible" : "hidden");
	}
	
	/**
	 * Delete message
	 * Options:
	 * 	tid:	Thread ID
	 * 	id:		Message ID
	 * 
	 * @param object opts Options
	 * @return void
	 */
	pub.deleteMessage = function(opts) {
		if(!confirm(getLoc("delete_confirm")))
			return;
		
		var args = {
			"tid": opts.tid,
			"id": opts.id
		};
		
		toggleMessageLoadIndicator(opts.tid, opts.id, true);
		sendCommand("deleteMessage", args, function(data) {
			toggleMessageLoadIndicator(opts.tid, opts.id, false);
			$("#thread-tree-" + opts.tid).html(data.html);
		});
	}
	
	/**
	 * Publish message
	 * Options:
	 * 	tid:	Thread ID
	 * 	id:		Message ID
	 * 
	 * @param object opts Options
	 * @return void
	 */
	pub.publishMessage = function(opts) {
		var args = {
			"tid": opts.tid,
			"id": opts.id
		};
		
		toggleMessageLoadIndicator(opts.tid, opts.id, true);
		sendCommand("publishMessage", args, function(data) {
			toggleMessageLoadIndicator(opts.tid, opts.id, false);
			$("#thread-tree-" + opts.tid).html(data.html);
		});
	}
	
	/**
	 * Publish message
	 * Options:
	 * 	tid:	Thread ID
	 * 	id:		Message ID
	 * 
	 * @param object opts Options
	 * @return void
	 */
	pub.unpublishMessage = function(opts) {
		var args = {
			"tid": opts.tid,
			"id": opts.id
		};
		
		toggleMessageLoadIndicator(opts.tid, opts.id, true);
		sendCommand("unpublishMessage", args, function(data) {
			toggleMessageLoadIndicator(opts.tid, opts.id, false);
			$("#thread-tree-" + opts.tid).html(data.html);
		});
	}
	
	/**
	 * Get message editor for new message
	 * Options:
	 * 	tid:	Thread ID
	 * 	pid:	Message parent ID
	 * 
	 * @param object opts Options
	 * @return void
	 */
	pub.getMessageEditor = function(opts) {
		var args = {
			"tid": opts.tid,
			"pid": opts.pid,
			"quote": !!opts.quote
		};
		
		//hide all playground contents
		$(".message-playground").html("<!-- -->");
		toggleMessageLoadIndicator(opts.tid, opts.pid, true);
		sendCommand("getMessageEditor", args, function(data) {
			toggleMessageLoadIndicator(opts.tid, opts.pid, false);
			//set editor html to playground
			$("#message-playground-" + opts.pid).html(data.html);
			
			hookEditorButtons(opts.tid, opts.pid);
			
			//if author field doesnt have default value, focus to it, otherwise focus to content textarea
			if($("#message-input-author-" + opts.tid + "-" + opts.pid).val() === "")
				$("#message-input-author-" + opts.tid + "-" + opts.pid).get(0).focus();
			else
				$("#message-input-content-" + opts.tid + "-" + opts.pid).get(0).focus();
		});
	}
	
	/**
	 * Initialize message editor for new root depth messages
	 * 
	 * @param int tid Thread ID
	 * @return void
	 */
	pub.initEditor = function(tid) {
		hookEditorButtons(tid, 0);
	}
	
	/**
	 * Initialize client side variables
	 * 
	 * @param object data Init data
	 * @return void
	 */
	pub.init = function(data) {
		commandProxy = data.commandProxy;
		commandParamName = data.commandParamName;
		cookiePath = data.cookiePath;
	}
	
	return pub;
})();
