var Planio = new Object();
Planio.page = '';
Planio.ignoreKeyPress = false;
Planio.waitingForServer = false;
Planio.documentReady = false;
Planio.focus_em = undefined;
Planio.pageTracker = undefined;
Planio.bigOperationInProgress = false;


$(document).ready(function() {
	// Trigger Google Analytics
	try {
		Planio.pageTracker = _gat._getTracker("UA-13178500-1");
		if (Planio.page == '') Planio.pageTracker._trackPageview();
	} catch(err) {}

	$("#notification").hover(function() { window.clearInterval($("#notification").data("timer")); }
	,function() { $("#notification").data("timer",window.setTimeout(function() { $("#notification").find(".close").click() }, $("#notification").data("delay") )) });
	
	$('#login_email').bind('focus', function(e) {
		if ($(this).val() == 'Email') $(this).val('');
	});
	$('#login_email').bind('blur', function(e) {
		if ($(this).val() == '') $(this).val('Email');
	});
	$('#login_password').bind('focus', function(e) {
		if ($(this).val() == 'Password') $(this).val('');
	});
	$('#login_password').bind('blur', function(e) {
		if ($(this).val() == '') $(this).val('Password');
	});
	
	$('.container').append('<div class="dropFeedback hidden"></div>')
	$('.dropFeedback').data('lastStamp', 0);
	$('#feedback_details').bind('focus', function(e) {
		Planio.ignoreKeyPress = true;
		Planio.focus_em = this;
		if ($(this).hasClass('empty')) {
			$(this).removeClass('empty');
			$(this).val('');
		}
	});
	$('#feedback_details').bind('blur', function(e) {
		Planio.ignoreKeyPress = false;
		Planio.focus_em = undefined;
		if ($.trim($(this).val()) == '') {
			$(this).addClass('empty');
			$(this).val('Type your feedback here to help us make Planio better!');
		}
	});
	$('#feedback_details').bind('keydown', function(e) {
		if (e.keyCode == 13) {
			feedback();
			stopEvent(e);
		}
		if (e.keyCode == 27) {
			$('.dropFeedback').addClass('hidden');
			$(this).blur();
		}
		//if (e.keyCode == 32) { showPopular(); }
	});
	$('#feedback_suggestion').bind('focus', function(e) {
		Planio.ignoreKeyPress = true;
		Planio.focus_em = this;
	});
	$('#feedback_suggestion').bind('blur', function(e) {
		Planio.ignoreKeyPress = false;
		Planio.focus_em = undefined;
	});
	
	$('#generic_dialog').dialog({
		autoOpen: false,
		bgiframe: true,
		modal: true,
		resizable: false,
		draggable: false,
		open: function() {
			Planio.ignoreKeyPress = true;
		},
		close: function() {
			setTimeout("Planio.ignoreKeyPress = false", 100);
		}
	});
	
	$('#login_password').bind('keydown', function(e) {
		if (e.keyCode == 13) {
			login();
			stopEvent(e);
		}
	});
	
	// Invite a user dialog
	$('.container').append('<form method="post" action="/manage/invite_to_project" id="invite_dialog" class="dialog hidden"><div class="content"></div></form>');
	addLoadingToDialog('#invite_dialog');
	$('#invite_dialog').dialog({
		autoOpen: false,
		bgiframe: true,
		modal: true,
		resizable: true,
		draggable: true,
		width: 500,
		height: 600,
		title: 'Add Someone',
		buttons: {
			'Cancel': function() {
				$(this).dialog('close');
				$('.addRoleTitle .asterisk').addClass('hidden');
			},
			'Invite': function() {
				if (Planio.waitingForServer == true) return;
				doAjax('/manage/invite_to_project',
					'POST', $('#invite_dialog').serialize(), 'json',
					function (object) {
						loadingOverlay('hide');
						if (object.code == 'ok') {
							$('#invite_dialog').dialog('close');
							if (Planio.page == 'manage') {
								// To do: Move to product.js
								$('.addRoleTitle .asterisk').addClass('hidden');
								var idProject = object.content.idProject;
								var idProduct = object.content.idProduct;
								var idPeople = object.content.idPeople;
								if(object.content.people_product != undefined) $('#productPeople_'+idProduct+' .peopleInvolved').append(object.content.people_product);
								else $('#peopleProjects_'+idPeople+'_'+idProduct).html(object.content.projects_alias);
								var peopleProjectRow = $('#peopleRow_'+idPeople+'_'+idProject);
								if(peopleProjectRow.length > 0) peopleProjectRow.replaceWith(object.content.people_row);
								else $('#projectContent_'+idProject+' .people_description').append(object.content.people_row);
							}
							notify({message:object.content.message, delay:5000});
						} else {
							alert(object.content);
						}
					}
				);
			}
		}
	});
	
	// If tips are shown, update arrows
	tips_update_arrows();
	
	//adjustTableContentHeight();
	//$(window).bind('resize', adjustTableContentHeight);
	Planio.documentReady = true;
	
	// Are we running IE6 or IE7?
	if ($.browser.msie == true) {
		var version = parseInt($.browser.version);
		if (version == 6 || version == 7) {
			var html = '<div style="background:orange; font-size:0.7em; color:black; padding: 2px; text-align:center;">We have detected that you are using an old Web Browser: Microsoft Internet Explorer '+version+'. For a better experience, please upgrade your browser.</div>';
			$('body>.container').prepend(html);
		}
	}
	
	$("#optionsJumpMenu select").combobox({
		change:function(e,ui) {
			if (e.type=="reset")
				return false;
			if (ui.selection.items && ui.selection.items.length>0 && ui.selection.items[0].disabled==false) {
				eval(ui.selection.items[0].value);
				//document.location = ui.selection.items[0].value; 
			}
		}
		, mode: "button"
		, buttonText: "Actions"
	});


	// This is our famous fake console.
	if (!window.console) {
		window.console = {log:function(m) { window.console.stack.push(m)}, stack:[]}
		$("<div/>").css({position:"fixed",height:30,width:30, top:0, left:0}).appendTo("body").dblclick(function() {
				var console = $("<div/>").css({position:"fixed",height:300, width:300, overflow:"auto", top:0, left:0, padding:30, border:"1px solid black", background:"#999"}).html(window.console.stack.join("<br>")).mousedown(function(e) { e.stopPropagation() }).appendTo("body");
				$("body").one("mousedown", function() { console.remove() });		
		});
	}

});
function showInviteDialog(product_id, project_id, productName, projectName, event) {
	if (typeof(event) != 'undefined') stopEvent(event);
	if (Planio.waitingForServer) return;
	// Hide the content and show the loading
	$('#invite_dialog>.content').hide();
	$('#invite_dialog>.loading').show();
	
	var title = 'Add Someone';
	if (product_id != '') title += ' to '+productName;
	if (project_id != '') title += ' - '+projectName;
	$('#invite_dialog').dialog('option', 'title', title);
	
	// Open the dialog
	$('#invite_dialog').dialog('open');
	
	// Reload the dialog content through AJAX
	var url = '/manage/populate_invite_dialog';
	if (product_id != '') url += '/'+product_id;
	if (project_id != '') url += '/'+project_id;
	doAjax(url, 'GET', '', 'json',
		function (object) {
			if (object.code == 'ok') {
				$('#invite_dialog>.content').replaceWith(object.content);
				$('.addRoleTitle .asterisk').removeClass('hidden');
				var projects_em = $('#invite_dialog .projects');
				if (projects_em.length == 1) {
					var projects = eval('('+projects_em.text()+')');
					$('#invite_dialog .projectDropContainer>input').combobox({
						data: projects,
						map: {value:'id'},
						change: function(event, ui) {
							if (ui.selection.items.length > 0) {
								var selection = ui.selection.items[0];
								if (selection.value && selection.value != null)
									$('#invite_dialog #project_id').val(selection.value);
							}
						}
					});
				}
				doAjax('/api/get_resources', 'GET', '', 'json',
					function (object) {
						if (object.code == 'ok') {
							var names = [];
							var emails = [];
							var names_map = [];
							var emails_map = [];
							for (index in object.content) {
								var resource = object.content[index];
								emails.push(resource.email);
								names.push(resource.name);
								emails_map[resource.name] = resource.email;
								names_map[resource.email] = resource.name;
							}
							$("#email").deprecated_autocomplete(emails, {
								'hideCallback': function () {
									$('#name').val(names_map[$("#email").val()]);
								}
							});
							$("#name").deprecated_autocomplete(names, {
								'hideCallback': function () {
									$('#email').val(emails_map[$("#name").val()]);
								}
							});
						} else {
							alert(object.content);
						}
					}
				);
				$('#invite_dialog>.loading').hide();
			} else {
				alert(object.content);
			}
		}
	);
}
function showAddNewRole() {
	$('.add_role_button').removeAttr('onclick');
	$('.add_role_button').addClass('disabled');
	$('.addRoleDescription').removeClass('hidden');
}
function addNewRole() {
	var name_em = $('#addRoleName');
	var alias_em = $('#addRoleAlias');
	var name = $.trim(name_em.val());
	var alias = $.trim(alias_em.val());
	
	if (name == '' || alias == '') {
		alert('Name or alias is missing!');
		return;
	}
	if (alias.length > 4) {
		alert("Alias '"+alias+"' is too long. Four characters maximum allowed.");
		return;
	}
	var full = name+' ('+alias+')';
	
	var error = '';
	$('#tableRole label').each(function() {
		var role = $.trim($(this).text());
		var pieces = role.split(' ');
		var role_name = pieces[0];
		var role_alias = pieces[1].replace('(', '').replace(')', '');
		if (role.toLowerCase() == full.toLowerCase()) {
			error = "Role '"+full+"' already exists.";
			return false;
		}
		if (role_name.toLowerCase() == name.toLowerCase()) {
			error = "Role name '"+name+"' already exists.";
			return false;
		}
		if (role_alias.toLowerCase() == alias.toLowerCase()) {
			error = "Role alias '"+alias+"' already exists.";
			return false;
		}
	});
	if (error != '') {
		alert(error);
		return;
	}
	
	if ($('#tableRole tbody tr:last td').length == 0) {
		$('#tableRole tbody tr:last').remove();
		$('#tableRole tbody').append('<tr><td><input id="newRole_'+name+'_'+alias+'" type="checkbox" name="newRole_'+name+'" value="newRole_'+name+'_'+alias+'" class="newRole" checked="checked" /><label for="newRole_'+name+'_'+alias+'">'+full+'</label></td></tr>');
	} else {
		$('#tableRole tbody tr:last').append('<td><input id="newRole_'+name+'_'+alias+'" type="checkbox" name="newRole_'+name+'" value="newRole_'+name+'_'+alias+'" class="newRole" checked="checked" /><label for="newRole_'+name+'_'+alias+'">'+full+'</label></td>');
		$('#tableRole tbody').append('<tr></tr>');
	}
	name_em.val('');
	alias_em.val('');
	$('.add_role_button').bind('click', showAddNewRole);
	$('.add_role_button').removeClass('disabled');
	$('.addRoleDescription').addClass('hidden');
}
function cancelAddNewRole() {
	$('#addRoleName').val('');
	$('#addRoleAlias').val('');
	$('.add_role_button').bind('click', showAddNewRole);
	$('.add_role_button').removeClass('disabled');
	$('.addRoleDescription').addClass('hidden');
}
/*
function adjustTableContentHeight() {
	// Adjust height of table content
	var table = $('.table_content');
	if (table.length == 0) return;
	
	var winHeight = $(window).height();
	var tableTop = Math.floor(($(table).offset().top));
	var tableHeight = Math.floor($(table).height());
	var footer = $('.footer');
	var footerHeight = Math.floor($(footer).height());
	var newHeight = Math.floor(winHeight - tableTop - footerHeight)-10;
	//alert('win='+winHeight+'  table='+tableTop+', '+tableHeight+'  footer='+footerHeight+'  newHeight='+newHeight);
	$(table).height(newHeight);
}
*/
function login() {
	doAjax('/application/login', 'POST', $('#header_form_login').serialize(), 'json',
		function(object) {
			if (object.code == 'ok') {
				$('.header_login_form_message').css('color', 'green');
				$('.header_login_form_message').html(object.content);
			} else {
				$('.header_login_form_message').css('color', 'red');
				$('.header_login_form_message').html(object.content);
				$('#login_password').val('');
			}
			if (object.redirect != '') {
				window.location = object.redirect;
			}
		}
	);
}
function doAjax(url, type, data, dataType, func) {
	Planio.waitingForServer = true;
	$.ajax({
		url: url,
		type: type,
		dataType: dataType,
		data: data,
		beforeSend: function(xhrObj) {
			var uri = window.location.toString();
			xhrObj.setRequestHeader("Planio-URI", uri);
		},
		success: function(object, status) {
			Planio.waitingForServer = false;
			if (typeof(object.code) == 'string' && object.code == 'redirect' && 
				typeof(object.redirect) == 'string' && object.redirect != '') {
				window.location = object.redirect;
				return;
			}
			func.apply(this, [object]);
		},
		error: function(xhr, status, error) {
			Planio.waitingForServer = false;
			if (Planio.documentReady == undefined || Planio.documentReady == false) return;
			var object = {code: 'error', content: strip_tags(xhr.responseText)};
			func.apply(this, [object]);
		}
	});
	//Keeping only the two first tokens. (Controller/Method) for Google Analytics
	var gaUrl = url.split("/");
	if (gaUrl[0] == "") gaUrl.shift(); //remove the first element if empty.
	gaUrl = "/" + gaUrl.slice(0,2).join("/")
	try {pageTracker._trackPageview(gaUrl);} catch(err) {}
}
$.editable.addInputType('url', {});
$.editable.addInputType('success', {});
$.editable.addInputType('error', {});
$.editable.addInputType('keep_local', false);
$.editable.addInputType('submitonenter', false);
function submitJEditable(value, settings) {
	var em = this;
	var origvalue = em.revert;
	var submitdata = {};
	submitdata[settings.name] = value;
	submitdata[settings.id] = em.id;
	/* add extra data to be POST:ed */
	if ($.isFunction(settings.submitdata)) {
		$.extend(submitdata, settings.submitdata.apply(em, [em.revert, settings]));
	} else {
		$.extend(submitdata, settings.submitdata);
	}
	// Disable edit in place during AJAX call
	$(em).data('disabled.editable', true);
	Planio.waitingForServer = true;
	var returned = $.ajax({
		url: settings.url, 
		type: "POST",
		data: submitdata,
		dataType: 'json',
		success: function(object, status) {
			Planio.waitingForServer = false;
			$(em).data('disabled.editable', false);
			if (object.code == 'error') {
				//alert(object.content);
				$(em).html(origvalue);
				if (object.redirect != '') {
					window.location = object.redirect;
				}
				settings.success.apply(em, [object, settings]);
			} else {
				if (settings.keep_local == true) {
					if (value != '') {
						$(em).html(value);
					} else {
						$(em).html(settings.placeholder);
					}
				} else {
					if (object.content != '') {
						$(em).html(object.content);
					} else {
						$(em).html(settings.placeholder);
					}
				}
				settings.success.apply(em, [object, settings]);
			}
		},
		error: function(xhr, status, error) {
			Planio.waitingForServer = false;
			if (Planio.documentReady == undefined || Planio.documentReady == false) return;
			$(em).html(origvalue);
			$(em).data('disabled.editable', false);
			var message = strip_tags(xhr.responseText);
			settings.error.apply(em, [message, settings]);
		}
	});
   return(settings.indicator);
}
function iteration_filter_item_click(event, id) {
	var em = $('#iteration_filter_dialog .item.'+id+'>input');
	if (em.attr('checked') === true) {
		em.attr('checked', false);
	} else {
		em.attr('checked', true);
	}
}
function showdialog(selector) {
	$(selector).dialog('open');
};
function addLoadingToDialog(selector) {
	$(selector).append('<div class="loading" style="display: none;"><span>Loading...</span><br/><img src="/img/loading.gif" alt="Loading"></img></div>');
}
function stopEvent(e) {
	if(!e) var e = window.event;
	
	//e.cancelBubble is supported by IE - this will kill the bubbling process.
	e.cancelBubble = true;
	e.returnValue = false;

	//e.stopPropagation works only in Firefox.
	if (e.stopPropagation) {
		e.stopPropagation();
		e.preventDefault();
	}
	return false;
}
function loadingOverlay(action) {
	if (action == 'show') {
		var top = $(window).scrollTop() + $(window).height()/2 - $('#loading_overlay').height()/2;
		var left = $(window).scrollLeft() + $(window).width()/2 - $('#loading_overlay').width()/2;
		$('#loading_overlay').css({
			display: 'block',
			top: top,
			left: left
		});
	} else {
		if (action != 'hide') alert("Invalid action '"+action+"'.  Must be show or hide.");
		$('#loading_overlay').css('display', 'none');
	}
}
function dialogWait(em, action) {
	var buttons = $(em).parent().find('.ui-dialog-buttonpane button');
	if (action == 'start') {
		loadingOverlay('show');
		$(em).dialog('disable');
		$(buttons).addClass('ui-state-disabled');
	} else {
		if (action != 'stop') alert("Invalid action '"+action+"'.  Must be show or hide.");
		$(buttons).removeClass('ui-state-disabled');
		$(em).dialog('enable');
		loadingOverlay('hide');
	}
}
function strip_tags (str, allowed_tags) {
    // Strips HTML and PHP tags from a string  
    // 
    // version: 909.322
    // discuss at: http://phpjs.org/functions/strip_tags
    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   improved by: Luke Godfrey
    // +      input by: Pul
    // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   bugfixed by: Onno Marsman
    // +      input by: Alex
    // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +      input by: Marc Palau
    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +      input by: Brett Zamir (http://brett-zamir.me)
    // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   bugfixed by: Eric Nagel
    // +      input by: Bobby Drake
    // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   bugfixed by: Tomasz Wesolowski
    // *     example 1: strip_tags('<p>Kevin</p> <br /><b>van</b> <i>Zonneveld</i>', '<i><b>');
    // *     returns 1: 'Kevin <b>van</b> <i>Zonneveld</i>'
    // *     example 2: strip_tags('<p>Kevin <img src="someimage.png" onmouseover="someFunction()">van <i>Zonneveld</i></p>', '<p>');
    // *     returns 2: '<p>Kevin van Zonneveld</p>'
    // *     example 3: strip_tags("<a href='http://kevin.vanzonneveld.net'>Kevin van Zonneveld</a>", "<a>");
    // *     returns 3: '<a href='http://kevin.vanzonneveld.net'>Kevin van Zonneveld</a>'
    // *     example 4: strip_tags('1 < 5 5 > 1');
    // *     returns 4: '1 < 5 5 > 1'
    var key = '', allowed = false;
    var matches = [];
    var allowed_array = [];
    var allowed_tag = '';
    var i = 0;
    var k = '';
    var html = '';

    var replacer = function (search, replace, str) {
        return str.split(search).join(replace);
    };

    // Build allowes tags associative array
    if (allowed_tags) {
        allowed_array = allowed_tags.match(/([a-zA-Z0-9]+)/gi);
    }

    str += '';

    // Match tags
    matches = str.match(/(<\/?[\S][^>]*>)/gi);

    // Go through all HTML tags
    for (key in matches) {
        if (isNaN(key)) {
            // IE7 Hack
            continue;
        }

        // Save HTML tag
        html = matches[key].toString();

        // Is tag not in allowed list? Remove from str!
        allowed = false;

        // Go through all allowed tags
        for (k in allowed_array) {
            // Init
            allowed_tag = allowed_array[k];
            i = -1;

            if (i != 0) { i = html.toLowerCase().indexOf('<'+allowed_tag+'>');}
            if (i != 0) { i = html.toLowerCase().indexOf('<'+allowed_tag+' ');}
            if (i != 0) { i = html.toLowerCase().indexOf('</'+allowed_tag)   ;}

            // Determine
            if (i == 0) {
                allowed = true;
                break;
            }
        }

        if (!allowed) {
            str = replacer(html, "", str); // Custom replace. No regexing
        }
    }

    return str;
}
// Converts a date string in the format 'year-month-day' to 
// 'month day, year' such as  Jan 2, 2010.
function formatDate(dateString) {
	var pieces = dateString.split('-');
	var months = Array('', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
	return months[parseInt(pieces[1])]+" "+pieces[2]+", "+pieces[0];
}
// Splits seconds into hours, minutes and seconds in a nice format.
function splitTime(seconds) {
	var h=Math.floor(seconds/3600);
	var m=Math.floor(seconds/60)-(h*60);
	var s=seconds-(h*3600)-(m*60);
	if (h >= 1) {
		return (Math.floor(4*seconds/3600)/4)+' hour(s)';
	} else if (m >= 1) {
		return m+' minute(s)';
	} else {
		return s+' second(s)';
	}
}
function addDays(dateString, days) {
	var pieces = dateString.split('-');
	var day = parseInt(pieces[2]);
	var month = parseInt(pieces[1]);
	var year = parseInt(pieces[0]);
	var date = new Date();
	date.setFullYear(year);
	date.setMonth(month-1);
	date.setDate(day+days);
	var ayear = date.getFullYear();
	var amonth = date.getMonth()+1;
	var aday = date.getDate();
	return ayear+'-'+amonth+'-'+aday;
}

function feedback() {
	if (Planio.waitingForServer) return;
	var text = $('#feedback_details').val();
	var prefix = $('#feedback_suggestion').val();
	var feedback = prefix+' '+text;
	var email = $('#header .login_email').html();
	if ($.trim(text) == '') return;
	
	// Change text to say that we are working
	$('#feedback_details').val('Sending...');
	$('#feedback_details').addClass('sending');
	
	// Disabled all entries
	$('.feedback_bar').addClass('disabled');
	$('#feedback_suggestion').attr('disabled', true);
	$('#feedback_details').attr('disabled', true);
	
	// Call the JS API
	Planio.feedback({
		feedback: feedback,
		page_title: window.location.pathname.replace('/', ''),
		user_email: email,
		forward_email: 'feedback@planio.com',
		onsuccess: function(message) {
				notify({message:message, delay:5000});
				// Re-enable all entries
				$('#feedback_suggestion').attr('disabled', false);
				$('#feedback_details').attr('disabled', false);
				$('.feedback_bar').removeClass('disabled');
				$('#feedback_details').removeClass('sending');
				// Clear
				$('#feedback_details').addClass('empty');
				$('#feedback_details').val('Type your feedback here to help us make Planio better!');
				$('.dropFeedback').addClass('hidden');
		},
		onerror: function(message) {
				alert(message);
				// Re-enable all entries and reset text
				$('#feedback_suggestion').attr('disabled', false);
				$('#feedback_details').attr('disabled', false);
				$('.feedback_bar').removeClass('disabled');
				$('#feedback_details').removeClass('sending');
				$('#feedback_details').val(text);
		}
	});
}

function showPopular() {
	feedback_details = $('#feedback_details');
	var text = feedback_details.val();
	if(text == "") return;
	var section = Planio.page;
	var dropFeedback = $('.dropFeedback');
	var currentStamp = dropFeedback.data('lastStamp') + 1;
	dropFeedback.data('lastStamp', currentStamp);
	doAjax('/api/getPopularFeedback/1/'+section, 'POST', 'text='+text, 'json',
		function(object) {
			if (object.code == 'ok') {
				if(currentStamp == dropFeedback.data('lastStamp')) {
					dropFeedback.html(object.content.feedback_popular_view_html);
				}
				if(dropFeedback.hasClass('hidden')) {
					var offset = $('.feedback_bar').offset();
					var x = offset.left;
					var y = offset.top + $('.feedback_bar').height() + 5;
					dropFeedback.css({position: 'absolute', zIndex: '1000000', left: x, top: y});
					dropFeedback.removeClass('hidden');
					$('body').one('click', function() {dropFeedback.addClass('hidden')});
				}
			} 
		}
	);
}

function vote(feedback_id) {
	doAjax('/api/vote/'+feedback_id, 'POST', '', 'json',
		function (object) {
			if (object.code == 'ok') {
				$('.dropFeedback').addClass('hidden');
				alert("We have received your feedback. Thank you for taking the time to help us help you!");
			} else {
				alert(object.content);
			}
		}
	);
}

function change_show_option(checkbox) {
	if (typeof checkbox == "string")
		checkbox = $(checkbox);

	$.each(checkbox, function() {
		if (!$(this).is(":checkbox") || !$(this).attr("name"))
			return true;
		var url = "/filter/change_show_option/" + $(this).attr("name") + "/" + (($(this).is(":checked")) ? "1":"0");
		doAjax(url , 'POST', {}, 'json',
			function(object) {
				if (object.code == 'ok') {
					return true;
				} else {
					alert(object.content);
				}
			}
		);	
	})
}

function tips_toggle(action) {
	if (Planio.page == '') {
		alert('No tips are available for this page.');
		return;
	}
	var url = '/tips/';
	if (action === undefined) {
		action = 'show';
		if ($('#tips_bar').hasClass('selected')) action = 'hide';
	}
	$('#tips_pane>.content').hide();
	$('#tips_pane>.loading').show();
	if (action == 'show') {
		url += 'show/'+Planio.page;
		$('#tips_pane').show();
		$('#tips_bar').addClass('selected');
		$('#tips_bar>label').html('Hide Tips');
	} else {
		url += 'hide';
		$('#tips_pane').hide();
		$('#tips_bar').removeClass('selected');
		$('#tips_bar>label').html('Show Tips');
	}
	doAjax(url, 'GET', '', 'json',
		function(object, status) {
			if (object.code == 'ok') {
				if ($('#tips_bar').hasClass('selected')) {
					$('#tips_pane>.loading').hide();
					$('#tips_pane>.content').replaceWith(object.content);
					$('#tips_pane>.content').show();
					tips_update_arrows();
				}
			} else {
				alert(object.content);
			}
		}
	);
}
function tips_hide() {
	tips_toggle('hide');
}
function tips_change_section(em) {
	em = $(em); if (em.length == 0) return;
	
	// Determine section to select
	var classes = em.attr('class');
	var section = $.trim(classes.replace('button', '').replace('selected', ''));
	
	// Find old section to select
	var old_section = '';
	var old_em = em.parent().children('.selected');
	if (old_em.length == 1) {
		classes = old_em.attr('class');
		old_section = $.trim(classes.replace('button', '').replace('selected', ''));
	}
	if (section == old_section) return;
	
	// Hide old and show new
	old_em.removeClass('selected');
	em.addClass('selected');
	$('#tips_pane .tip_content>.'+old_section).addClass('hidden');
	$('#tips_pane .tip_content>.'+section).removeClass('hidden');
	tips_update_arrows();
}
function tips_scroll(e, pixels) {
	var em = $('#tips_pane .tip_content');
	if (em.length == 0) return;
	stopEvent(e);
	var delta = em.attr('scrollHeight') - em.height();
	var new_top = em.attr('scrollTop') + pixels;
	if (new_top < 0) {
		new_top = 0;
	} else if (new_top > delta) {
		new_top = delta;
	}
	em.attr('scrollTop', new_top);
	tips_update_arrows();
}
function tips_update_arrows() {
	var em = $('#tips_pane .tip_content');
	if (em.length == 0) return;
	if (em.attr('scrollHeight') <= em.height()) {
		em.children('.arrow').addClass('disabled');
		return;
	}
	em.children('.arrow').removeClass('disabled');
	var delta = em.attr('scrollHeight') - em.height();
	if (em.attr('scrollTop') <= 0) {
		em.children('.arrow.up').addClass('disabled');
	} else if (em.attr('scrollTop') >= delta) {
		em.children('.arrow.down').addClass('disabled');
	}
}
function message_hide(message_id) {
	var url = '/application/message_hide/'+message_id;
	doAjax(url, 'GET', '', 'json',
		function(object, status) {
			if (object.code == 'ok') {
				$('#message_'+message_id).remove();
			} else {
				alert(object.content);
			}
		}
	);
}
function welcome_submit(choice) {
	$("#welcome_form input[name='choice_radio']").val(choice);
	var url = '/application/welcome_submit';
	doAjax(url, 'POST', $('#welcome_form').serialize(), 'json',
		function(object, status) {
			if (object.code == 'ok') {
				window.location = object.redirect;
			} else {
				alert(object.content);
			}
		}
	);
}
function bindDatePicker(selector, empty_text) {
	$(selector).datepicker({dateFormat: 'd M yy'});
	$("#ui-datepicker-div").css('display','none');
	$("#ui-datepicker-div").css('z-index',9999);
}

/* notify will display a notification that will stick to the viewport for a given time
options:
	message: string | jquery,  the message to be displayed
	delay: integer, the delay in ms. after which the notification will go away
*/
function notify(options) {
	options.delay = options.delay || 10000;
	if (!options.message) return;

	if (typeof(options.message) == "string") options.message = $("<span>" + options.message + "</span>");

	$("#notification .message").html(options.message);
	$("#notification").fadeIn("slow");
	$("#notification .close").one("click",function() { $("#notification").fadeOut("slow").removeData("timer"); });
	$("#notification").data("delay",options.delay);
	$("#notification").data("timer",window.setTimeout(function() { $("#notification .close").click() }, options.delay));
}

/*Helper function organiseArrayByKey() takes two input and return an response.
//Input:
//  inputArray: An array of responses that share a different value for key
//  key: the key to organise the array by
//Output:
//  an response organised by key
//Example:
//	organiseArrayByKey([{"type":"apple","color":"red"}, {"type":"pear","color":"yellow"}], "type")
//	return {"apple" : {"type":"apple","color":"red"}, "pear": {"type":"pear","color":"yellow"}}
*/
function organiseArrayByKey(inputArray, key)
{
	var output = {};
	$.each(inputArray, function(i, v)
	{
		if (output[v[key]]) //This key existed but we are now turning it into an array since it's there more than once.
		{
			return false;
		}
		else	//First time we encounter this, let's assign it a value.
			output[v[key].toString()] = v;
	})	
	return output;
}

function groupArrayByKey(inputArray, key)
{
	var output = {};
	$.each(inputArray, function(i, v)
	{
		if (output[v[key]]) //This key existed but we are now turning it into an array since it's there more than once.
		{
			output[v[key]].push(v);
		}
		else	//First time we encounter this, let's assign it a value.
			output[v[key]] = [v];
	})	
	return output;
}

// takes an array of object and returns an array of their key value
// ex: flattenWithKey([{"A":"B"},{"A":"C"}],"A") === ["B","A"]
function flattenWithKey(inputArray, key)
{	
	var a = [];
	$.each(inputArray, function(i,r) {
		if (key=="*")
			a.push(r);
		else
			if (r[key])
				a.push(r[key])
	})
	return a;
}

// distinct takes an array of string or number as input and output an array of distinct values
function distinct(arr,key) {
	if (!$.isArray(arr) || arr.length == 0)
		return [];
	if (!arr[key] && !arr[0][key]) key=undefined;

	var a = {};
	$.each(arr, function(i,v) { 
		if (typeof v == "string")
			a[v] = v; 
		else 
			a[v[key]] = v;
		
	});
	var r = [];
	$.each(a, function(i,v) { r.push(v); });

	if (typeof key == "string")
		r = r.sort(function(a,b) { return a[key].toLowerCase() > b[key].toLowerCase() })
	else
		r = r.sort(function(a,b) { return a.toLowerCase() > b.toLowerCase() });
	return r;
}


function sortByKey(arr, key) {
	if ($.isArray(arr))
		return arr.sort(function(a,b) { return (a[key].toLowerCase() < b[key].toLowerCase()) ? -1:1 })
}

// Takes two array of string or number and count the number of time the sets intersect
function arrayIntersect(a,b) {
	var r=0;
	$.each(a, function(i,v) {
		if ($.inArray(v,b) >=0) r++;
	})
	return r;
}

// Return the union between array a and b in a unique set.
function arrayUnion(a,b) {
	var r=[];
	$.each(a, function(i,v) {
		if ($.inArray(v,b) >=0) r.push(v)
	})
	return distinct(r);
}

// Take template (a jQuery object), clone it for every row in data.
function cloneAndFill(template, data)
{
	if (!$.isArray(data)) // Try to see the problem differently by turning data into an array.
		data = [data];
	
	$.each(data, function(index, record)
	{
		var newEm = template.clone().removeClass("template").addClass("tentativeRow");
		fill(newEm, record);
		record.em = newEm.data("record",record);
		template.parent().append(newEm);		
	});

	return template.siblings(".tentativeRow").removeClass(".tentativeRow");
}

//Fill parent with data. Parent has children. Children have class they want data in.
function fill(parent, data)
{
	$.each(data, function(key, val)
	{	var em = parent.find("." + key);
		if (em.is("img"))
			em.attr("src",val)
		else if (em.is("a") && em.attr("href"))
			em.attr("href",val)
		else if (em.attr("contenteditable") == "true" && val=="" && em.attr("data-novalue").length > 0)
			em.text(em.attr("data-novalue"))
		else
			em.text(val);
	})
}
// implement JSON.stringify serialization
// Source: http://www.sitepoint.com/blogs/2009/08/19/javascript-json-serialization/
JSON.stringify = JSON.stringify || function (obj) {
	var t = typeof (obj);
	if (t != "object" || obj === null) {
		// simple data type
		if (t == "string") obj = '"'+obj+'"';
		return String(obj);
	}
	else {
		// recurse array or object
		var n, v, json = [], arr = (obj && obj.constructor == Array);
		for (n in obj) {
			v = obj[n]; t = typeof(v);
			if (t == "string") v = '"'+v+'"';
			else if (t == "object" && v !== null) v = JSON.stringify(v);
			json.push((arr ? "" : '"' + n + '":') + String(v));
		}
		return (arr ? "[" : "{") + String(json) + (arr ? "]" : "}");
	}
};


function localFilters() {
	var self=this;
	this.filterStore = {}
	this.filterCount = 0;
	this.pass = {};
	this.fail = {};
	this.postFilterHook = {};

	this.addFilter = function(target, name, testFun, onRemove) {
		var alreadyExisting = false;
		if (!this.filterStore[target + "-" + name]) {
			this.filterCount++;
		} else {
			alreadyExisting=true;		
			// We are replacing a rule in the store that has been defined previously.. The rule is being replaced by either a more restrictive or a broader one.. Better reset the pass/fail cache.
			this.resetCache(target);
		}

		this.filterStore[target + "-" + name] = {target:target, testFun: testFun, onRemove:onRemove}
	}
	
	this.registerPostFilterHook = function(target, hook) {
		this.postFilterHook[target] = hook;	
	}

	this.removeFilter = function(target, name) {
		if (name=="*") {
			$.each(this.filterStore, function(n,v) {
				if (n.split("-")[0] == target)
					self.removeFilter(target,n.split("-")[1])
			})
			return;
		}
	
		if (this.filterStore[target + "-" + name]) {
			var onRemove = this.filterStore[target + "-" + name].onRemove;
			delete this.filterStore[target + "-" + name];
			this.filterCount--;
			onRemove();
			this.resetCache(target);
		}
	}
	
	this.filter = function(target, fail_class) {
		var globalFail = this.fail[target] || $(); // Fail one test and you are here.
		var globalPass = this.pass[target] || $(target);
		fail_class = fail_class || "hidden";

		var store = groupArrayByKey(this.filterStore, "target");
		if (!store[target]) {
			// Absolutely no filters on that target, set them free!
			globalPass = this.pass[target] = $(target).removeClass(fail_class);
			if (this.postFilterHook[target])
				this.postFilterHook[target]();
			globalFail = this.fail[target] = $();
			return;
		}	
		store=store[target];
		
		$.each(store, function(index, filter) { // Iterate trough each rule.
			if (typeof(filter.testFun) == "function")
				filter.testFun = [filter.testFun];

			globalPass.each(function() {
				var row = $(this);
				var flag=false; // By default in a OR you do not pass.
				$.each(filter.testFun, function(testIndex, testFunction) {
					var result = testFunction(row);
					if (result == true) {
						flag=true;
						return false; //stop iteration trough the rules.
					}
				})
				if (flag === false) { // You failed all the rules in the array so you go in the FAIL bin.
					globalPass = globalPass.not(row[0]);
					globalFail = globalFail.add(row[0]);
				}
			})

		})

		globalPass.removeClass(fail_class);
		globalFail.addClass(fail_class);
		if (this.postFilterHook[target]) this.postFilterHook[target]();
		this.fail[target] = globalFail;
		this.pass[target] = globalPass;
	}

	this.resetCache = function(target) {
		var self=this;
		self.pass[target] = $(target);
		self.fail[target] = $();
	}

}
