// no. of ms to wait before again telling the server that i'm typing
var g_tell_server_i_am_typing_timestamp = 0;

var g_adding_entry_flag = false;
var g_i_just_added_something = false;

var g_fetch_interval_ms = 1000;

var g_ajax_error_internal_error = "Failed to fetch data from server";
var g_latest_fetched_id = 0;


var g_client_unique_id = "";

var g_active_para_len = 0;
var g_pending_paragraphs = 0;
var g_users_typing = 0;

var g_sound = undefined;

var g_current_par_len_attr = "current_para_len";

$(document).ready(function() {
	
	// generate my unique client id
	g_client_unique_id = generateUniqueId();
	
	// ajax setup
	$.ajaxSetup({
	  async : true,
	  cache : false,
	  timeout : 3000,
	  type : 'post'
	});	
	
	// add shortcut key tooltip for clear button
	if ('Mac' == $.client.os)
		$("button#quick_delete").attr("title","Clear [ALT + DEL]");
	else
		$("button#quick_delete").attr("title","Clear [SHIFT + DEL]");
	
	// how to play
	$("#how_to_play").show();
	$("#how_to_play a").click(function(){
		if ($("#how_to_play_blurb").is(":visible")) {
			$("#how_to_play_blurb").hide();
		} else {
			var coords = $(this).offset();
			var blurbWidth = $("#how_to_play_blurb").width(); 
			$("#how_to_play_blurb")
				.css("position","absolute")
				.css("top", (coords.top + this.offsetHeight + 5) + "px")
				.css("left", (coords.left + this.offsetWidth - blurbWidth) + "px")
				.show();
		}
	});
	
	// add hint to text field
	var hint = "enter your 3 words";
	var inputElem = getInputField();
	inputElem
		.css("color","#999").css("font-style","italic").val(hint)
		.keyup(function(e){
			
			// ignore ENTER (form submission)
			if (13 == e.which)
				return true;
			
			// Shift+DEL clears it
			if (46 == e.which && e.shiftKey)
			{
				$("button#quick_delete").click();
				return false;
			}
				
			var val = $(this).val();
			if (undefined != val && '' != val)
			{
				$("button#quick_delete").show();
				tellServerIAmTyping();
			}
			else
				$("button#quick_delete").hide();
			
			return false;
		})
		.focus(function(){
			if (hint == $(this).val())
				$(this).val("");
			$(this).css("color","#666").css("font-style","normal");
		})
		.blur(function(){
			if ('' == $(this).val())
				$(this).css("color","#999").css("font-style","italic").val(hint);
		})
	;
	
	// form is POSTed via AJAX
	$("form#my_words").submit(function(){
		addEntry();
		return false;
	});
	
	// quick delete button
	$("button#quick_delete").click(function(){
		var f = getInputField();
		f.val("").blur().focus();
		$(this).hide();
		return false;
	})
	.hide();

	// fetch more button
	$("button#fetch_more_older").click(function(){
		fetchOlderEntries(false,true);
		return false;
	});
	
	// panels
	$("div#embed_panel, form#email_friends").show();
	
	// add hint to text field
	var hint2 = "enter emails";
	var inputElem2 = $("form#email_friends input[name=emails]");
	inputElem2
		.css("color","#999").css("font-style","italic").val(hint2)
		.focus(function(){
			if (hint2 == $(this).val())
				$(this).val("");
			$(this).css("color","#333").css("font-style","normal");
		})
		.blur(function(){
			if ('' == $(this).val())
				$(this).css("color","#999").css("font-style","italic").val(hint2);
		})
	;
	$("form#email_friends").submit(function(){
		emailFriends();
		return false;
	});
		
	// initial params
	$("div#input div.words").attr(g_current_par_len_attr,"0");
	
	// first lets fetch latest paragraphs. And then we'll trigger
	// the 'fetchLatest()' loop (the true param below).
	setTimeout('fetchOlderEntries(true,false)',0);
	
	// focus on the input field
	getInputField().blur().focus();
});

/**
 * Show AJAX progress indicator
 */
function showAjaxInProgress(jQueryAjaxLoadingElemRef, jQueryTriggerRef)
{
	if (undefined != jQueryTriggerRef)
		jQueryTriggerRef.attr("disabled","disabled");
	jQueryAjaxLoadingElemRef.show();
}

/**
 * End AJAX progress indicator
 */
function endAjaxInProgress(jQueryAjaxLoadingElemRef, jQueryTriggerRef)
{
	if (undefined != jQueryTriggerRef)
		jQueryTriggerRef.removeAttr("disabled");
	jQueryAjaxLoadingElemRef.hide();
}


var g_last_msg_id = 0;


/**
 * Show an error msg
 */
function showError(_jQueryContainerElem, _msg)
{
	++g_last_msg_id;
	var uniqueId = "errormsg" + g_last_msg_id;	
	_jQueryContainerElem.append("<div style=\"display:none\" id=\"" + uniqueId + "\" class=\"error\">" + _msg + "</div>");
	$("div#"+uniqueId).fadeIn(1000);
	setTimeout("hideMsg('" + uniqueId + "')", 5000);
}

/**
 * Show a success msg
 */
function showSuccess(_jQueryContainerElem, _msg)
{
	++g_last_msg_id;
	var uniqueId = "msg" + g_last_msg_id;
	_jQueryContainerElem.append("<div style=\"display:none\" id=\"" + uniqueId + "\" class=\"msg\">" + _msg + "</div>");
	$("div#"+uniqueId).fadeIn(1000);
	setTimeout("hideMsg('" + uniqueId + "')", 5000);
}

/**
 * Hide a previously shown message.
 * 
 * You do not need to call this method directly. It is called asynchronously. 
 */
function hideMsg(_id)
{
	$("div#"+_id).fadeOut(1000);
}


function generateUniqueId() {
    var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'.split('');
    
    var str = '';
    for (var i = 0; i < 20; i++) {
        str += chars[Math.floor(Math.random() * chars.length)];
    }
    
    str += String((new Date()).getTime()).replace(/\D/gi,'');
    
    return str;
}



function getInputField()
{
	return $("form#my_words input[name=" + g_words_input_field + "]");
}

function truncateText(text, max_chars)
{
	if (text.length > max_chars)
		return text.substring(0,max_chars-3) + "...";
	else
		return text;
}

/**
 * Build 'tweet this' button HTML for the given sentence.
 */
function buildTweetButtonHtml(text,backlink)
{
	backlink = g_short_base_url + backlink;
	
	// find max total length (minus backlink length)
	// twitter allows upto 140 chars
	var max_text_length = 139 - backlink.length;
	
	// truncate text
	text = truncateText(text,max_text_length);
	
	var twitterUrl = 'http://twitter.com/home?status='+encodeURIComponent(text + ' ' + backlink);
	return "<a class=\"tweet\" target=\"_blank\" href=\"" + twitterUrl + "\" title=\"Tweet this!\">" +
			"<img src=\"http://twitter-badges.s3.amazonaws.com/t_small-b.png\" alt=\"Tweet this\"/>"
			+ "</a>"
	;
}


/**
 * Build 'Share on Facebook' button HTML for the given sentence.
 */
function buildFacebookButtonHtml(text,backlink)
{
	text = encodeURIComponent(truncateText(text,100));
	backlink = encodeURIComponent("http://m3w.in/fb" + backlink);
	
	return '<a class="fbshare" href="http://www.facebook.com/sharer.php?u='+backlink+'&t='+text+'" target="blank"' + 
			' title="Share on Facebook"><img src="' + g_img_base_url + '/icon_facebook.png" /></a>';
}


/**
 * Build sentence HTML to output to page.
 * @param storyId story id
 * @param entryArray array of entries
 * @param isPending whether this paragraph is actually pending insertion to db.
 * @return object. key 'html' = HTML to show. key 'hash' = md5 has of text.
 */
function buildSentence(storyId, entryArray,isPending)
{
	var html = ""; 
	var txt = "";
	for (var j=0; j<entryArray.length; ++j)
	{
		var entry = entryArray[j];
		
		// censor data if needed
		if (0 < (entry.meta & g_flag_censored) )
			entry.data = entry.data.replace(/\w/g,'.');
		
		txt += entry.data + " ";
		
		html += '<span id="entry'+entry.id+'" style="color:'+entry.color+'">'+entry.data+'</span> ';
	}	
	if (!isPending)
	{
		var backlink = "/" + storyId;
		html += buildTweetButtonHtml(txt,backlink);
		html += buildFacebookButtonHtml(txt,backlink);
	}
	else
		html += "<span class=\"pending\" title=\"Building...\">&nbsp;</span>";
	
	var obj = new Object;
	obj['hash'] = hex_md5(txt);
	obj['html'] = "<div id=\"story" + storyId + "\" class=\"sentence" + (isPending?" pending":"") + "\" hash=\"" + obj['hash'] + "\">" + html + "</div>";
	
	return obj;
}


function fetchLatest()
{
	var latest_id = 0;
	var firstStory = $("div#old_words div[class=sentence]:first");
	if (0 < firstStory.size()) {
		// ids are always in form:  storyXX  (where XX is the number we want)
		latest_id = parseInt( firstStory.attr("id").substring(5),10);
		if (NaN == latest_id || undefined == latest_id)
			latest_id = 0;
	}
	
	$.ajax({
		timeout : 59000,  /* long polling */ 
		url : g_base_url + "/ajax/fetch_latest/" + latest_id + "/" + g_active_para_len + "/" + g_pending_paragraphs + "/" + g_users_typing,
		dataType : "json",
	    error : function(_XMLHttpRequest, _textStatus, _errorThrown)
		{
			// ignore timeouts since they're expected
			if ('timeout' != _textStatus)
				showError($("div#fetch_new_errors"), "Unexpected error: " + _textStatus);
		},				
		success : function(_data, _textStatus, _XMLHttpRequest) {
			if (undefined != _data)
			{
				// paras
				if (undefined != _data.paras && 0 < _data.paras.length)
				{
					var html = '';
					for (var i=0; i<_data.paras.length; ++i)
					{
						var s = buildSentence(_data.paras[i].id, _data.paras[i].entries,false);
						// if already showing as a pending sentence then replace
						var existingSentence = $("div#old_words div[hash=" + s['hash'] + "]");
						if (0 < existingSentence.size())
							existingSentence.replaceWith(s['html']);
						else
							html = s['html'] + html;
					}
					$("div#old_words div.dummy_top_marker").after(html);
				}
				
				// pending
				if (undefined != _data.pending_paras)
				{
					var html = '';
					for (var i=0; i<_data.pending_paras.length; ++i)
					{
						var s = buildSentence(-1, _data.pending_paras[i],true);
						// if para not already showing
						var existingSentence = $("div#old_words div[hash=" + s['hash'] + "]");
						if (0 >= existingSentence.size())
							html = s['html'] + html;
					}
					$("div#old_words div.dummy_top_marker").after(html);
					g_pending_paragraphs = _data.pending_paras.length;
				}
				
				// entries (active para)
				if (undefined != _data.current_para)
				{
					var html = '<span class="prefix">&raquo; </span>';
					for (var i=0; i<_data.current_para.length; ++i)
					{
						var entry = _data.current_para[i];
						html += '<span id="entry'+entry.id+'" style="color:'+entry.color+'">'+entry.data+'</span> ';
					}
					html += '<span class="typing"></span>';
					$("div#input div.words").html(html);
					
					// new entries added by someone else?
					if (!g_i_just_added_something && _data.current_para_len != g_active_para_len)
						playAlertSound();
					
					g_active_para_len = _data.current_para_len;
				}
				
				// users currently typing
				$("div#input div.words span.typing").text("");
				g_users_typing = 0;
				if (undefined != _data.users_typing)
				{
					g_users_typing = _data.users_typing.length;
					
					// display it, excluding me
					var users_typing_to_show = g_users_typing; 
					if (0 <= jQuery.inArray(g_client_unique_id, _data.users_typing))
						users_typing_to_show--;
					if (0 < users_typing_to_show)
						$("div#input div.words span.typing").text(users_typing_to_show + (4 <= users_typing_to_show ? "+" : "") + " typing...");
				}
				
			} // if _data not null
		},
		complete : function(_XMLHttpRequest,_textStatus) {
			g_i_just_added_something = false;
			setTimeout('fetchLatest()',0);
		}		
	});
}


/**
 * @param initialCall if TRUE then fetchLatest() will be called via setTimeout() once this AJAX call has completed.
 * @return
 */
function fetchOlderEntries(initialCall, showErrorIfNoItemsFound)
{
	var ajaxLoadingElem = $("div#old_words .ajax_loading");
	var buttonElem = $("button#fetch_more_old");  
	showAjaxInProgress(ajaxLoadingElem, buttonElem);
	
	var latest_id = 0;
	var lastStory = $("div#old_words div[class=sentence]:last");
	if (0 < lastStory.size()) {
		// ids are always in form:  storyXX  (where XX is the number we want)
		latest_id = parseInt( lastStory.attr("id").substring(5),10);
		if (NaN == latest_id || undefined == latest_id)
			latest_id = 0;
	}
	
	// if no fetch history then use larger timeout
	var timeout_ms = 3000;
	if (0 == latest_id)
		timeout_ms = 5000;
	
	$.ajax({
		timeout : timeout_ms,
		url : g_base_url + "/ajax/fetch_old/" + latest_id,
		dataType : "json",
	    error : function(_XMLHttpRequest, _textStatus, _errorThrown)
		{
			showError($("div#fetch_more_errors"), "Unexpected error: " + _textStatus);
			// if this was initial call then redo it after a delay
			if (initialCall)
				setTimeout('fetchOlderEntries(true,'+showErrorIfNoItemsFound+')',3000);			
		},				
		success : function(_data, _textStatus, _XMLHttpRequest) {
			if (undefined != _data && 0 <= _data.length)
			{
				// no more to fetch?
				if (0 == _data.length && showErrorIfNoItemsFound) {
					showError($("div#fetch_more_errors"), "No more items to fetch!");
					return;
				}
				
				var html = '';
				for (var i=0; i<_data.length; ++i)
				{
					var o = buildSentence(_data[i].id, _data[i].entries, false); 
					html = o['html'] + html;
				}
				
				$("div#old_words div.dummy_bottom_marker").before(html);
			}
			
			// if this was initial call then trigger 'fetch latest'
			if (initialCall)
				setTimeout('fetchLatest()',0);				
		},
		complete : function(_XMLHttpRequest,_textStatus) {
			endAjaxInProgress(ajaxLoadingElem, buttonElem);
		}	
	});
}



function addEntry()
{
	if (g_adding_entry_flag)
		return;
	g_adding_entry_flag = true; // only one add at a time
	
	var ajaxLoadingElem = $("form#my_words .ajax_loading");
	var inputElem = getInputField();  
	if ('' == inputElem.val())
		return;

	showAjaxInProgress(ajaxLoadingElem, inputElem);
	$("button#quick_delete").hide();

	params = new Object;
	params[inputElem.attr("name")] = inputElem.val(); 
	g_i_just_added_something = true;	

	$.ajax({
		url : g_base_url + "/ajax/add",
		timeout : 5000,
		data : params,
		dataType : "json",
	    error : function(_XMLHttpRequest, _textStatus, _errorThrown)
		{
			showError($("div#input_errors"), "Unexpected error: " + _textStatus);
		},			
		success : function(_data, _textStatus, _XMLHttpRequest) {
			// errors?
			if (undefined != _data.error) {
				showError($("div#input_errors"),_data.error);
				return;
			}
			$("button#quick_delete").click();
		},
		complete : function(_XMLHttpRequest,_textStatus) {
			endAjaxInProgress(ajaxLoadingElem, inputElem);
			$("button#quick_delete").show();
			inputElem.blur().focus();
			g_adding_entry_flag = false;
		}
	});
}


/**
 * Tell the server I am typing.
 */
function tellServerIAmTyping()
{
	var date = new Date();
	
	// only do this if enough time has passed
	if (date.getTime() - g_tell_server_i_am_typing_timestamp < g_tell_server_i_am_typing_server_delay)
		return;
	
	g_tell_server_i_am_typing_timestamp = date.getTime();
	
	$.ajax({
		url : g_base_url + "/ajax/type/" + g_client_unique_id,
		timeout : 2000,
		data : { id : g_client_unique_id },
		dataType : "json",
	    error : function(_XMLHttpRequest, _textStatus, _errorThrown) {},			
		success : function(_data, _textStatus, _XMLHttpRequest) {},
		complete : function(_XMLHttpRequest,_textStatus)
		{
			g_tell_server_i_am_typing_timestamp = date.getTime();
		}
	});	
}


/**
 * Tell the server I am typing.
 */
function emailFriends()
{
	var ajaxLoadingElem = $("div#general_ajax_indicator");
	var ajaxTriggerElemRef = $("form#email_friends input, form#email_friends button");
	showAjaxInProgress(ajaxLoadingElem, ajaxTriggerElemRef);
	
	var recipients = $("form#email_friends input").val();
	
	$.ajax({
		url : g_base_url + "/ajax/email_friends",
		timeout : 3000,
		data : { emails : recipients },
		dataType : "json",
	    error : function(_XMLHttpRequest, _textStatus, _errorThrown)
	    {
			showError($("div#notifications"), "Unexpected error: " + _textStatus);
	    },			
		success : function(_data, _textStatus, _XMLHttpRequest)
		{
	    	if (undefined != _data.error)
	    	{
				showError($("div#notifications"), _data.error);
	    	}
	    	else
	    	{
				showSuccess($("div#notifications"), "Emails sent successfully.");
				$("form#email_friends input").val("");
	    	}
	    },
		complete : function(_XMLHttpRequest,_textStatus)
		{
	    	endAjaxInProgress(ajaxLoadingElem, ajaxTriggerElemRef);
		}
	});	
}





// playing sounds
soundManager.onready(function() {
  if (soundManager.supported() && undefined != g_sound_url) {
	// load the alert sound
	g_sound = soundManager.createSound({
		id : "alert_sound", 
		url : g_sound_url
	});
	
	// add sound icon
	$("a#rss_feed").after("<a id=\"toggle_sound\" href=\"#\" title=\"Turn off alert sound\">&nbsp;</a>");
	$("a#toggle_sound").click(function(){
		if ( $(this).hasClass("disabled") )
			$(this).attr("title","Turn off alert sound");
		else
			$(this).attr("title","Turn on alert sound");
				
		$(this).toggleClass("disabled");
	});
  }
});

		  
/**
 * Play the alert sound.
 */
function playAlertSound() {
	// if alert sound defined and enabled
	if (undefined != g_sound && !$("a#toggle_sound").hasClass("disabled")) {
		g_sound.play();
	}
}


