/**
 * JavaScript for Knerd Messaging (internal mail)
 */

////
//// jQuery document ready block - set up dialogs, bindings, etc.
///
jQuery(document).ready(function($) {
	///
	/// Dialogs
	///
	KJMailbox.instance.setupBindings();
	KJMessage.instance.setupComposeBindings();

}); // end document.ready()


/************************************************************************
 * Encapsulation for "inbox" view / js functionality (Singleton model)
 ***********************************************************************/

function KJMailbox() {
	this.state = { // keeps track of the current "state" of the mailbox view
			mboxBeingDisplayed: '',
			mboxPage: 1
	};
	this.$mailboxLinks = null;

	this.$dlgMyMessages = null;
}
/**
 * set up a static reference to singleton
 * (setting it up this way for Eclipse's benefit, I know it's not optimal.)
 * @var KJMailbox
 */
KJMailbox.instance = new KJMailbox();
//KJMailbox.instance = (function() {
//		return new KJMailbox();
//})();

/**
 * setup jquery bindings for KJMailbox
 */
KJMailbox.prototype.setupBindings = function() {

	////
	//// Global bindings for message related buttons
	////

	// Define the dialog for 'my messages'
	this.$dlgMyMessages = $("#dlgMyMessages").dialog({
		bgiframe: true,
		autoOpen: false,
		show: 'slide',
		height: 500,
		width: 740,
		modal: true,
		buttons: {
			'Close':               function() { $(this).dialog('close');      }
			//'Compose New Message': function() { KJMessage.instance.compose(); }
		},
		open: function() {
		          // default to person's inbox when they initially open dlg
		          // by triggering a 'click' event on that .mailbox-link
		          $('#mailbox_ident_person_me_inbox').click();
		      }
	});

	// User clicks 'My Messages' button on dashboard tab
	$("#myMessagesButton").click(function(){
		KJMailbox.instance.$dlgMyMessages.dialog('open');
	});


	////
	//// Right pane bindings (thread list, message viewing, etc)
	////

	// user clicks on a thread in the messagelist
	$("#threadList > div.thread-summary .clickable").live("click", function() {
		var $thread = $(this).closest('.thread-summary');
//		var threadID = $thread.data("thread_id");
//		var ktmID    = $thread.data("ktm_id");
//		var threadSubject = $thread.find(".thread_subject > .content").text();
		KJMailbox.instance.displayThread( $thread );
	});

	// disable mailbox buttons to start
	this.disableTopButtons();

	// user checks checkbox next to a thread
	$("#threadList > div.thread-summary :checkbox").live("click", function() {
		var size = $("#threadList > div.thread-summary :checkbox").filter(":checked").size();
		if (size > 0) {
			KJMailbox.instance.enableTopButtons();
		} else {
			KJMailbox.instance.disableTopButtons();
		}
	});
	// button: specific thread delete
	$("#threadList > div.thread-summary .threadcol-delete :button").live("click", function() {
		// User clicked the delete 'X' on a specific message
		var del_ktm_id = $(this).closest(".thread-summary").data("ktm_id");
		KJMailbox.instance.deleteThreads([del_ktm_id]);
	});
	// button: delete ALL checked threads
	$("#btnDeleteCheckedThreads").click(function() {
		// User clicked the 'delete' button at the top, must delete checked messages
		var del_ktm_ids = KJMailbox.instance.getCheckedThreadData('ktm_id');
		KJMailbox.instance.deleteThreads(del_ktm_ids);
	});

	///// pagination bindings /////

	// changed thread list limit
	$("#selThreadListLimit").change(function() {
		KJMailbox.instance.$mailboxLinks.filter(".active").first().click();
	});

	// 'next' and 'prev' links
	$("#messagingRightDiv .pagination .page-jump a").click(function() {
		var currPage = KJMailbox.instance.state.mboxPage;

		if ( ! $(this).button("option","disabled") )
		{
			if ($(this).hasClass("prev")) { // PREV (newer)
				KJMailbox.instance.state.mboxPage = Math.max(1, (currPage - 1));
			}
			else { // NEXT (older)
				KJMailbox.instance.state.mboxPage = currPage + 1;
			}
			KJMailbox.instance.getThreadListJS(); // refresh the list!
		}
	});


	////
	//// LEFT pane bindings (mailbox list)
	////

	// User clicked a mailbox, switch to that mailbox
	KJMailbox.instance.$mailboxLinks = $("#messagingSideBar .mailboxDiv a.mailbox-link").click( this.switchToMailboxIdentity );

	// Collapse/Expand mailbox sub folders
	$("#mailboxList .mailboxDiv .mailbox-title").click(function() {
		$(this).toggleClass("collapsed");
		$(this).next(".collapsible").toggle();
	});



}; // end setupBindings for KJMailbox

KJMailbox.prototype.disableTopButtons = function() {
	$("#messagingRightDiv .mailbox-buttons :button").button("disable");
};
KJMailbox.prototype.enableTopButtons = function() {
	$("#messagingRightDiv .mailbox-buttons :button").button("enable");
};

/**
 * loop through "checked" threads, and return .data(data_field) on them.
 * @param data_field E.g. can get thread id, ktm_id, etc.
 * @return array
 */
KJMailbox.prototype.getCheckedThreadData = function(data_field) {
	var ret = [];
	$.each( $("#threadList > div.thread-summary:has(input:checked)"), function(i,v) {
		ret.push($(v).data(data_field));
	});
	return ret;
};

KJMailbox.prototype.refreshCurrentMailbox = function() {
	// Find the 'active' mailboxlink, and go from there
	// Triggering refresh (same as if user clicked on mailbox link)
	$("#messagingSideBar .mailbox-link.active").click();
};

/**
 * Handle mailbox-link clicks, and switch to the requested mailbox.
 *
 * NOTE: this is a jQuery bound function, so "this" refers to jQuery's this, not KJMailbox.instance
 */
KJMailbox.prototype.switchToMailboxIdentity = function() {

	//debugLog("Switching mailbox identity to : " + $(this).attr("id"));
	var $mailbox_link = $(this);
	var mailbox_identity = $mailbox_link.attr("id");

	// update "state"
	KJMailbox.instance.state.mboxBeingDisplayed = mailbox_identity;
	KJMailbox.instance.state.mboxPage = 1;

	// update thread list
	KJMailbox.instance.getThreadListJS();

	// update .active style to show which mailbox we're on
	KJMailbox.instance.$mailboxLinks.removeClass("active"); // removes class from ANY mailbox-link
	$mailbox_link.addClass("active"); // adds class to the specific mailbox-link that was clicked
};

/**
 * Request thread list via ajax and update the #threadList div
 *
 * @param mailbox_identity is the 'id' for the a.mailbox-link that was clicked, E.g. "mailbox_ident_person_me" (special case) or "mailbox_ident_band_5"
 * @return
 */
KJMailbox.prototype.getThreadListJS = function() {

	// Keep track of which mailbox and what page offset is currently displayed
	// (makes for easier refreshing and pagination)
	var mailbox_identity = KJMailbox.instance.state.mboxBeingDisplayed;
	var pageNum          = KJMailbox.instance.state.mboxPage;

	$msgList = $("#threadList");
	$msgList.empty();
	$msgList.append($("<div class='loading-messagelist'>Loading</div>"));

	this.disableTopButtons();

	var limit = $("#selThreadListLimit").val();

	$.get("/scripts/messaging/ajax-messaging.php", {
			'class':  "KMailbox",
			'method': "ajax_getThreadList",
			'args': [mailbox_identity, limit, pageNum] // what mailbox and how many msgs to retrieve
		},
		function(response) {
			$msgList.empty();
			try {
				var json = $.parseJSON(response);

				if (!json.logged_in) {
					// If not logged in, close dialog and warn
					KJMailbox.instance.$dlgMyMessages.dialog("close");
					warnNoLoginSession();
				}
				else if (json.success) {
					var $newThread;
					$.each(json.data, function(i,v) {
						$newThread = $("#threadTemplate").clone()
							.removeAttr("id")
							.data({        thread_id: v.thread_id,
							                  ktm_id: v.ktm_id,
							        mailbox_identity: mailbox_identity })
							.appendTo($msgList)
							.show();
						$newThread.find(".thread_from span.content").text(v.senders.join(', '));
						$newThread.find(".thread_subject span.content").text(v.subject);
						$newThread.find(".thread_time span.content").text(v.formatted_time);
						$newThread.find(".thread_preview span.content").text(v.preview);

						if (v.has_unread == 1) {
							$newThread.addClass("unread");
						}
					});

					if (json.new_unread_count) {
						var mboxIdentLinkID = "#"+mailbox_identity;
						var $unread = $(mboxIdentLinkID).find(".unread-count");
						var oldCount = parseInt($unread.text());
						var diff = json.new_unread_count - oldCount;
						if (diff != 0) {
							// Count changed! updating json.new_unread_count
							$unread.text(json.new_unread_count);

							KJMailbox.instance.updateTotalMessageCount();
						}
					}

					// update pagination controls
					KJMailbox.instance.updatePagination(json.has_more_messages);
				}
				else {
					// failed to load messages
					$("<div style='padding:10px;'>Failed to load messages</div>")
						.addClass("ui-state-error")
						.appendTo($msgList);
				}
			} catch (err) {
				debugLog(err);
			}
		},
		'html'
	); // .get
}; // end getThreadListJS

/**
 * hide/show the 'prev' and 'next' links
 */
KJMailbox.prototype.updatePagination = function(has_more) {

	var $pagerLinks = $("#messagingRightDiv .pagination .page-jump a");

	if (has_more) { // There are more messages!
		$pagerLinks.filter(".next").button("enable"); // enable the 'next' button

	} else {        // there are NO more messages
		$pagerLinks.filter(".next").button("disable"); // disable next button
	}

	// if already on first page of results, do not allow the 'previous' button.
	if (this.state.mboxPage > 1) {
		$pagerLinks.filter(".prev").button("enable"); // enable 'prev'
	} else {
		$pagerLinks.filter(".prev").button("disable"); // disable 'prev'
	}
};

/**
 * Tally up total unread messages across all inboxes, and update any
 * elements that display that total identified by $(".combined-inbox-unread-count")
 */
KJMailbox.prototype.updateTotalMessageCount = function() {
	// loop through inboxes, and tally up the total.
	var newTotal = 0;
	$.each( $("#messagingSideBar .mailboxDiv .unread-count"), function(i, el) {
		newTotal += parseInt($(el).text());
	});

	// .combined-inbox-unread-count applies to TWO spots. The dashboard "my messages" button, and
	// also the combined inbox total which is displayed when the inbox is collapsed
	$(".combined-inbox-unread-count").text(newTotal);



};

/**
 * Delete threads, given an array of thread id's
 * @param del_ktm_ids Array of thread_id's to delete
 * @return
 */
KJMailbox.prototype.deleteThreads = function(del_ktm_ids)
{

	if (del_ktm_ids && del_ktm_ids.length > 0) {

		var confMsg;
		if (del_ktm_ids.length > 1) {
			confMsg = "Move selected messages to trash?";
		} else {
			confMsg = "Move message to trash?";
		}
		jConfirm(confMsg, "Confirm Delete", function(resp) {
			if (resp) {
				$.get("/scripts/messaging/ajax-messaging.php", {
						'class': 'KMailbox',
						'method': 'ajax_deleteThreads',
						'args': [del_ktm_ids.join(",")]
					},
					function(response) {
						try {
							var json = $.parseJSON(response);
							if (json.success) {
								// threads deleted successfully, refresh the thread list
								KJMailbox.instance.refreshCurrentMailbox();
							}
							else {
								// failure..
								jAlert("Failed to delete messages");
							}
						} catch (err) {
							jAlert("Oops! An error occurred. Please try again");
							debugLog(err);
						}
					},
					'html'
				); // $.get
			}
		}); // jConfirm
	}
};

KJMailbox.prototype.displayThread = function($thread) {
	var threadID = $thread.data("thread_id");
	var ktmID    = $thread.data("ktm_id");
	var dlgTitle = $thread.find(".thread_subject > .content").text();

	// create dialog, and load thread into it
	var $threadDialog = $("<div><div class='ajax-content'>Loading</div></div>")
		.dialog({
			autoOpen: true,
			width: 700,
			height: 500,
			resizable: true,
			title: dlgTitle,
			buttons: { 'Close': function() { $(this).dialog("close"); } }
		});

	this._loadThreadIntoDialog($threadDialog, threadID, ktmID, function() {
		KJMailbox.instance.markThreadRead($thread);
	});

};

/**
 * helper function that makes ajax call and populates a thread view with the content of the thread
 * @param $threadDialog
 * @param threadID
 * @param ktmID
 * @param callback_func
 * @return
 */
KJMailbox.prototype._loadThreadIntoDialog = function($threadDialog, threadID, ktmID, callback_func)
{
	$threadDialog.find(".ajax-content").load("/scripts/messaging/ajax.thread_view.php", {
		thread_id: threadID,
		   ktm_id: ktmID
		}, function() {
			// Set up bindings for elements in new dialog
			$threadDialog.find(".knerd-button").button(); // need to run this after elements added to DOM
			KJMessage.instance.setupReplyBindings($threadDialog, threadID, ktmID);

			// Execute provided callback function
			if (callback_func) { callback_func(); }
		});
};

KJMailbox.prototype.markThreadRead = function($thread) {
	if ($thread.hasClass("unread")) {
		// Thread WAS unread, so mark it read

		// 1. remove CSS stylings so that it appears "read" in the thread list.
		$thread.removeClass("unread");

		// 2. update the specific mailbox unread count that this thread was opened from
		var mboxIdentLinkID = '#'+$thread.data("mailbox_identity");

		var $countLabel = $(mboxIdentLinkID).find(".unread-count");
		var oldCount = parseInt($countLabel.text());
		if (oldCount > 0) {
			// Only decrement unread count for this mailbox if it's not already 0
			$countLabel.text(oldCount-1);
		}

		// 3. Update the "total" unread count displayed in the 'my messages' button on dashboard
		this.updateTotalMessageCount();
	}
};


/**************************************************************************************
 *  singleton model definition of KJMessage for encapsulating knerd message compose
 *************************************************************************************/
function KJMessage() {
	this.$composeDialog = null;
	this.$composeFeedbackDiv = null;
}

/**
 * singleton static reference
 * @var KJMessage
 */
KJMessage.instance = new KJMessage();
//KJMessage.instance = (function() {
//	return new KJMessage();
//})();


/**
 * Clear recipients, error messages, subject, message, etc
 * Basically put the compose dialog widgets back in their blank state, so that they're ready
 * for the next compose event.
 *
 * This can be called when the user cancels or successfully sends a message
 */
KJMessage.prototype.closeAndResetComposeDialog = function() {
	// Remove error messages
	//KJMessage.instance.$composeFeedbackDiv.removeClass("ui-state-error").empty(); // works
	KJMessage.instance.$composeFeedbackDiv.empty().removeClass("ui-state-error");

	// Remove recipients added by previous 'compose' call
	KJMessage.instance.clearRecipients();

	// Reset the form
	$("#frmComposeMessage").resetForm();

	// Finally, close the dialog
	KJMessage.instance.$composeDialog.dialog("close");
};

/**
 * setup jquery bindings that KJMessage depends on
 */
KJMessage.prototype.setupComposeBindings = function() {

	this.$composeFeedbackDiv = $("#frmComposeMessage .submit_feedback");

	this.$composeDialog = $("#dlgComposeMessage").dialog({
		bgiframe: true,
		autoOpen: false,
		height: 500,
		width: 700,
		modal: true,

		buttons: {
			'Cancel': function() {
				jConfirm("Are you sure?", "Cancel Message?", function(resp) {
					if (resp) { // user confirmed, abandone composition and close dialog
						KJMessage.instance.closeAndResetComposeDialog();
					}
				});
			},
			'Send': function() { $("#frmComposeMessage").submit(); }
		},

		open: KJMessage.instance.refreshComposeFromIdentities
	});

	/**
	 * TODO: make this nicer or take it out.
	 * add recipient from text input
	 */
	$("#btnAddRecip").click( function() {
		$input = $(this).parent().find("input");
		var recip_type = 'person'; // TODO: handle support for bands..
		var recip_id   = $input.val();
		var recip_name = recip_type+"_"+recip_id; // TODO: get recip name..
		KJMessage.instance.addRecipient(recip_type, recip_id, recip_name);

		$input.val(""); // clear input
	});

	////
	//// Message Composition Form (ajaxForm)
	////
	$("#frmComposeMessage").ajaxForm({

		dataType: 'json',

		// Perform validation and other pre-flight checks
		beforeSubmit: function(formData, jqForm, options) {
			// TODO: validate compose form.
			KJMessage.instance.$composeFeedbackDiv.empty().removeClass("ui-state-error");
			$("#composeMsgSpinner").show(); // start spinner

			return true;
		},

		// 'success' event is triggered after form is successfully submitted
		// it doesn't mean the backend processing was necessarily successful
		// so we still check that here.
		success: function(json, statusText, xhr, $jqform) {
			$("#composeMsgSpinner").hide(); // stop spinner

			// Show feedback messages, if provided
			//$feedbackDiv = $("#frmComposeMessage .submit_feedback"); // setup KJMessage.instance.$composeFeedbackDiv instead!
			KJMessage.instance.$composeFeedbackDiv.empty();
			if (json.messages.length > 0) {
				$.each(json.messages, function(i,msg) {
					KJMessage.instance.$composeFeedbackDiv.append("<p>"+msg+"</p>");
				});
			}

			if (json.success) {
				// Message successfully sent!

				// Do some cleanup
				KJMessage.instance.closeAndResetComposeDialog();

				jAlert("Message sent!"); // Give user a nice message
			}
			else {
				// Failure / error
				KJMessage.instance.$composeFeedbackDiv.addClass("ui-state-error");
				if (json.messages.length == 0) {
					// error occured but no message provided, show generic message
					KJMessage.instance.$composeFeedbackDiv.html("<p>An error occured and your message could not be sent. Please check all fields and try again</p>");
				}
			}
		}
	});
}; // end setupComposeBindings

/**
 * Bindings for the 'Reply' form
 * @param $threadDialog
 * @return
 */
KJMessage.prototype.setupReplyBindings = function($threadDialog, threadID, ktmID) {
	var $replyForm = $threadDialog.find(".reply-form");
	$replyForm.ajaxForm({

		dataType: 'json',
		resetForm: true,

		// Perform validation and other pre-flight checks
		beforeSubmit: function(formData, jqForm, options) {
			// TODO: validate compose form.
			$replyForm.find(".submit_feedback").empty().removeClass("ui-state-error");
			$replyForm.find(".replyMsgSpinner").show(); // start spinner

			return true;
		},

		// 'success' event is triggered after form is successfully submitted
		// it doesn't mean the backend processing was necessarily successful
		// so we still check that here.
		success: function(json, statusText, xhr, $jqform) {
			$replyForm.find(".replyMsgSpinner").hide(); // stop spinner

			// Show feedback messages, if provided
			$feedbackDiv = $replyForm.find(".submit_feedback");
			$feedbackDiv.empty();
			if (json.messages.length > 0) {
				$.each(json.messages, function(i,msg) {
					$feedbackDiv.append("<p>"+msg+"</p>");
				});
			}

			if (json.success) {
				// Message successfully sent!

				// Do some cleanup
				$feedbackDiv.removeClass("ui-state-error");

				// Refresh the thread view window so that the reply gets displayed
				KJMailbox.instance._loadThreadIntoDialog($threadDialog, threadID, ktmID, function() {
					// REPLY SENT!
					// scroll to last message, and run highlightFade on it too..
					$threadDialog.find(".thread-messages-wrapper").scrollTo("max", 500, {
						axis: 'y',
						onAfter: function() {
							$threadDialog.find(".thread-messages-wrapper > div.thread-message-block:last").highlightFade();
						}
					});
				});

			}
			else {
				// Failure / error
				$feedbackDiv.addClass("ui-state-error");
				if (json.messages.length == 0) {
					// error occured but no message provided, show generic message
					$feedbackDiv.html("<p>An error occured and your reply could not be sent. Please check all fields and try again</p>");
				}
			}
		}
	});
};


/**
 * Opens message composisition dialog. If recipient is provided, will populate the 'to' field.
 *
 * @param recip_type can be 'band' or 'person'
 * @param recip_id The id of the 'band' or 'person'
 * @param recip_name the person's full name
 * @param subject optionally specify the subject to pre-populate
 */
KJMessage.prototype.compose = function(recip_type, recip_id, recip_name, subject) {
	if (this.$composeDialog) {
		this.$composeDialog.dialog("open");
		this.clearRecipients();
		this.addRecipient(recip_type, recip_id, recip_name);
		if (typeof(subject) != "undefined" && subject) {
			this.$composeDialog.find(".subject").val(subject);
		}
	}
};

/**
 * format and add recipient to the recipient list
 *
 * @param recip_type
 * @param recip_id
 * @param recip_name
 */
KJMessage.prototype.addRecipient = function(recip_type, recip_id, recip_name) {
	if (recip_type && recip_id && recip_name) {
		//debugLog("Add recip: " + recip_type + ":"+recip_id + " name="+recip_name);

		// Clone and customize the recipient div
		var $recipEntry = $("#recip_template").clone()
			.addClass("recip_type_"+recip_type)
			.removeAttr("id")
			.data("recip_type", recip_type)
			.data("recip_id",   recip_id);

		$recipEntry.find(".recip_name").text(recip_name);

		// add a 'remove' button with appropriate bindings
		$recipEntry.find(".recip_remove").one("click", function() { $recipEntry.remove(); KJMessage.instance.gatherRecipientIDs(); });

		// add to the DOM
		$("#recip_list").append($recipEntry);
		$recipEntry.show(); // Safari requires this be on its own line, not as part of the .append()
	}

	// gather recipient ids and set hidden field:
	this.gatherRecipientIDs();
};

/**
 * Loops through recipients and builds a comma delimited list of their IDs and saves
 * in a hidden form input for submission
 */
KJMessage.prototype.gatherRecipientIDs = function() {
	var recip_id, recip_type;
	var recipient_id_list = [];
	$.each( $("#recip_list .recipient:visible"), function(i, recip) {
		recip_type = $(recip).data("recip_type");
		recip_id   = $(recip).data("recip_id");

		recipient_id_list.push(recip_type+"_"+recip_id);
	});

	$("#recip_list input:hidden").val(recipient_id_list.join(","));
};

/**
 * removes previously added recipients (leaves the #recip_template tho)
 * @return
 */
KJMessage.prototype.clearRecipients = function() {
	$("#recip_list .recipient").not("#recip_template").remove();
	$("#recip_list input:hidden").val("");
};

/**
 * builds and populates the 'From' dropdown in the compose window
 * This method is triggered every time the compose dialog recieves the 'open' event.
 * @return
 */
KJMessage.prototype.refreshComposeFromIdentities = function() {
	// Populate 'from' options
	$.get("/scripts/messaging/ajax-messaging.php", {
			'class': 'KMessageCompose',
			'method': 'ajax_getValidBandIdentities'
		},
		function(response) {
			try {
				var json = $.parseJSON(response);
				var $bandList = $("#selComposeFromOverride optgroup:last");
				$bandList.empty();
				var $newoption;
				$.each(json.data, function(i,v) {
					$newoption = $("<option></option>").val(v.band_id).text(v.band_name);
					$bandList.append($newoption);
				});

				if (!json.logged_in) {
					// Not logged in!  Close compose dialog and warn user
					KJMessage.instance.closeAndResetComposeDialog();
					warnNoLoginSession();
				}

			} catch (err) {
				debugLog(err);
			}
		},
		'html'
	); // $.get
};