$(document).ready(function($)
{
	
	var d = $(this);
	
	// TODO This is a temporary hack, which should become obsolete as soon
	// as the rest of the old JS code is refactored.
	window.initialize(this);
	
	d.updateBehavior();
	
	$('a.media').media();
	
	d.setFlowCallback('onCommentAdded', function(entityType, entityId) {
		var where = $("#commentsList ul");

		$.get("/comments/add/" + entityType + "/" + entityId, null, function(result) {
			where.prepend(result).updateBehavior();
			$("li:first", where).hide().show('slow');
		});			
	});
		
	$(window).bind('changeQueryString', function() {

		if ($.queryString.contains('modal')) {
			var modalContentsUri = $.queryString.read('modal');
			$.flow.openModal(modalContentsUri);
		}
		var expand = [];
		var focus = null;
		var focusLi = null;
		if ($.queryString.contains('eventfocus')) {
			var values = $.map($.queryString.read('eventfocus'), function(v, i) {
				return parseInt(v);
			});
			expand = $.unique($.merge(expand, values));
			focus = values[0];
		}
		if ($.queryString.contains('eventexpand')) {
			var values = $.map($.queryString.read('eventexpand'), function(v, i) {
				return parseInt(v);
			});
			expand = $.unique($.merge(expand, values));
		}
		if (expand.length > 0) {
			$('#content .agendaList .item').each(function() {
				var data = $(this).metadata();
				// Should we expand this item?
				if ($.inArray(data.eventId, expand) != -1) {
					$(this).addClass('expanded');
				}
				// Should we scroll to this item?
				if (focus == data.eventId) {
					focusLi = $(this).parent('li');
				}
			});
		}
		
		if (focusLi != null) {
			$('#content .agendaList .items').not('.premiums').prepend(focusLi);
			var scrollDown = focusLi.offset().top + focusLi.height() - $(window).height() + 10;
			if (scrollDown > 0) {
				$('html, body').animate({scrollTop: '+=' + scrollDown + 'px'}, 2000, 'swing');
			}
			$.queryString.remove('eventfocus', focus);
			
			// TODO Add item to expanded events because it remains expanded
//			$.queryString.add('eventexpand', focus);
			
			// TODO Add fade highlight effect
			
		}
		
	});
	
	$(window).trigger('changeQueryString');
	
});

/*
 * Update behavior plugin
 */ 
(function($)
{

	$.fn.updateBehavior = function()
	{
		this.applyFlow();
		
		this.addEmptyMessageBehavior();
		
		// TODO This is a temporary hack, which should become obsolete as soon
		// as the rest of the old JS code is refactored.
		window.initializeUpdate(this);
	};

})(jQuery);

/*
 * Flow plugin
 */
(function($)
{
	
	var modal = null;
	
	// TODO Move fn-methods to $.fn.flow object.
	
	$.fn.applyFlow = function()
	{
		if (modal == null) {
			modal = $('#modal').jqm({
				overlay: 70,
				modal: true
			});
		}
		
		$('form', this).submit(onFormSubmit);
		$('.toFillable', this).click(onToFillableClick);
		$('.toModal', this).click(onToModalClick);		
		$('.closeModal', this).click(function() {
			hideModal();
			return false;
		});
		
		return this;
	};
	
	var instructions = {};
	
	$.fn.setFlowInstructions = function(instr)
	{
		$.each(instr, function(k, v) {
			instructions[unescape(k)] = (typeof(v) == 'string') ? unescape(v) : v;
		});
	};
	
	var callbacks = {};
	
	$.fn.setFlowCallback = function(cbName, cb)
	{
		callbacks[cbName] = cb;
	};
	
	$.flow = {
	
		openModal: function(uri)
		{
			simulateToModalClick(uri);
		}
	
	};
	
	var evalCallback = function(evalCode)
	{
		var beginParams = evalCode.indexOf('(');
		var cbName = evalCode.substr(0, beginParams);
		eval('callbacks[cbName]' + evalCode.substr(beginParams));
	};
	
	var showModal = function(contents)
	{
		if (contents != null) {
			var modalContent = $('.modalContent', modal);
			modalContent.html(contents);
			modalContent.updateBehavior();
		}
		modal.jqmShow();
	};
	
	var hideModal = function()
	{
		modal.jqmHide();
	};
	
	var fillFillable = function(contents)
	{
		var fillable = eventSource.parents('.fillable:last');
		fillable.html(contents);
		fillable.updateBehavior();
	};
	
	var eventSource;
	var processContents;
	
	var onFormSubmit = function()
	{
		eventSource = $(this);
		
		indicateLoading();
		
		eventSource.hideEmptyMessages();
		
		processContents = fillFillable;
		instructions = {};
		eventSource.ajaxSubmit({
			target: '<div />',	// Make sure any Javascript is evaluated.
			// TODO Make CloseKeepAlive action on AppController.
			closeKeepAlive: '/closekeepalive.php',
			success: interpretResult,
			// TODO Handle errors nicely.
			error: function() {
				deindicateLoading();
			}
		});

		return false;
	};
	
	var onToFillableClick = function()
	{
		eventSource = $(this);
		processContents = fillFillable;
		
		indicateLoading();
				
		requestContent(interpretResult);
		
		return false;
	};
	
	var onToModalClick = function()
	{
		eventSource = $(this);
		processContents = showModal;
		
		indicateLoading();
				
		requestContent(interpretResult);
		
		return false;
	};
	
	var simulateToModalClick = function(contentsUri)
	{
		onToModalClick.apply($('<a href="' + contentsUri + '" />')[0]);
	};
	
	var requestContent = function(successFn)
	{
		instructions = {};
		// We load the result into an anonymous div to make sure any Javascript
		// is evaluated.
		$('<div />').load(eventSource.attr('href'), null, successFn);
	};
	
	var interpretResult = function(result)
	{
		if (instructions.error) {
			eventSource.handleValidationErrors(instructions.error);
			eventSource.showEmptyMessages();
			deindicateLoading();
			return;
		}
		if (instructions.redirect) {
			redirect(instructions.redirect);
			return;
		}
		if (instructions.finalize) {
			deindicateLoading();
			jitLogin(instructions.finalize, instructions.loginView, instructions.afterLogin);
			return;
		}
		
		// Scripts are already evaluated, so prevent they get evaluated again.
		// Note that stripScripts returns a jQuery object and not raw HTML.
		result = stripScripts($(result));
		processContents(result);
		if (instructions.callback) {
			evalCallback(instructions.callback);
		}
		
		deindicateLoading();
	};
	
	var stripScripts = function(contents)
	{
		return contents.not('script');
	};
	
	var redirect = function(to)
	{
		// Make sure we don't include any parameters or anchors of the current
		// location, because that might conflict with the parameters already
		// in the redirect variable.
		var currentLocation = window.location.protocol + '//' + window.location.host + window.location.pathname;
		uri = to.replace('[refresh]', currentLocation);
		window.location.replace(uri);
		// If upcoming script is executed, we only changed the fragment identifier.
		// An explicit [refresh] in the redirect location means we want a refresh
		// no matter what (f.e. due to changed independencies).
		if (to.indexOf('[refresh]') != -1) {
			window.location.reload();
		}
		// If upcoming script is executed, all we need is a notification that the
		// fragment identifier has changed.
		$(window).trigger('changeQueryString');
	};
	
	var jitLogin = function(finalize, loginView, afterLogin)
	{
		var params = new Array();
		params.push('finalize=' + finalize);
		if (afterLogin != null) {
			params.push('redirect=' + afterLogin);
		}
		params.push('scope=modal');
		var emailInput = $('#email', eventSource);
		if (emailInput.size() == 1) {
			params.push('email=' + emailInput.attr('value'));
		}
		
		simulateToModalClick('/users/login/' + loginView + '?' + params.join('&'));
	};
	
	var indicateLoading = function()
	{
		$('body').css('cursor', 'wait');
		$(':submit, :button', eventSource).attr('disabled', true);
	};
	var deindicateLoading = function()
	{
		$('body').css('cursor', '');
		$(':submit, :button', eventSource).attr('disabled', false);
	};
		
})(jQuery);

/*
 * Validation plugin
 */
(function($)
{
	
	$.fn.handleValidationErrors = function(errors)
	{
		if (this.is('form')) {
			putErrorsInForm(this, errors);
		}
		else {
			var alertMsg = '';
			if (typeof(errors) == 'string') {
				alertMsg = errors;
			}
			else {
				alertMsg = "One or more of the data fields are not acceptable";
			}
			alert("Oeps! Er is iets mis gegaan. Stuur een mailtje naar tim@nightbee.nl, zodat wij het probleem zo snel mogelijk uit de wereld kunnen helpen!\n\nError message: " + alertMsg);
		}
		
		return this;
	};
	
	var putErrorsInForm = function(frm, errors)
	{
		$('.field', frm).removeClass('errored');
		
		if (typeof(errors) == 'string') {
			$('.comment.error.general', frm).html(errors).show();
			return;
		}
		
		$('.field', frm).each(function() {
			showFormFieldError(this, getFormFieldError(this, errors));
		});
	};
	
	var getFormFieldError = function(field, errors)
	{
		var fieldError = null;
		var inps = $(':input', field);
		var id;
		for (var i = 0; i < inps.size(); i++) {
			id = inps[i].id.substr(inps[i].id.indexOf('-') + 1);
			if (id && errors[id]) {
				fieldError = errors[id];
				if (errors[id] != true) {
					return fieldError;
				}
			}
		}
		return fieldError;
	};
	
	var showFormFieldError = function(field, fieldError)
	{
		if (fieldError == null) {
			// Do nothing.
			return;
		}
		if (fieldError == true) {
//			$('.comment.correct', field).show();
			return;
		}
		$('.comment.error', field).html(fieldError);
		$('.comment.info', field).hide();
		$(field).addClass('errored');
	};
	
})(jQuery);

/*
 * Inputs that show a message when empty plugin
 */
(function($)
{
	
	$.emptyMessageSelector = 'input[emptyMessage], textarea[emptyMessage]';
	
	$.fn.addEmptyMessageBehavior = function()
	{
		var addTo = $($.emptyMessageSelector, this);
		
		showMessage.apply(addTo);
		
		addTo.focus(hideMessage);
		addTo.blur(showMessage);
		
		return this;
	};
	
	$.fn.hideEmptyMessages = function()
	{
		hideMessage.apply($($.emptyMessageSelector, this));
	};
	$.fn.showEmptyMessages = function()
	{
		showMessage.apply($($.emptyMessageSelector, this));
	};
	
	var hideMessage = function()
	{
		var i = $(this);
		
		if (i.attr('value') == i.attr('emptyMessage')) {
			i.removeClass('empty');
			i.attr('value', '').removeClass('emptyMessage');
		}
	};
	
	var showMessage = function()
	{
		var i = $(this);
		
		var currentValue = $.trim(i.attr('value'));
		if (currentValue == '' || currentValue == i.attr('emptyMessage')) {
			i.addClass('empty');
			setTimeout(function() {
					i.attr('value', i.attr('emptyMessage'));
				}, 100);
		}
	};
		
})(jQuery);

/*
 * Query string plugin
 */
(function($)
{
	
	var params = null;
	
	$.queryString = {
	
		contains: function(param, value)
		{
			parseParameters();
			if (value == null) {
				return !!params[param];
			}
			else {
				return (this.contains(param) && $.inArray(value, params[param]) != -1);
			}
		},
		
		read: function(param)
		{
			parseParameters();
			if (!this.contains(param)) {
				return null;
			}
			return params[param];
		},
		
		add: function(param, value)
		{
			parseParameters();
			if (!this.contains(param)) {
				params[param] = [];
			}
			if (this.contains(param, value)) {
				return;
			}
			params[param].push(value);
			rebuild();
		},
		
		remove: function(param, value)
		{
			parseParameters();
			if (!this.contains(param, value)) {
				return;
			}
			if (value == null || params[param].length == 1) {
				delete params[param];
			}
			else {
				params[param].splice($.inArray(value, params[param]), 1);
			}
			rebuild();
		}
		
	};
	
	var parseParameters = function()
	{
		if (params == null) {
			params = {};
			if (window.location.hash.length > 1) {
				var param;
				$.each(window.location.hash.substr(1).split('&'), function() {
					param = this.split('=');
					params[param[0]] = param.slice(1).join('=').split(',');
				});
			}
		}
	};
	
	var rebuild = function()
	{
		parseParameters();
		var queryString = '#';
		$.each(params, function(name) {
			queryString += name + '=' + this.join(',');
		});
		window.location.replace(queryString);
		$(window).trigger('changeQueryString');
	};
	
})(jQuery);
