var evaluation = {
	started: false,				// indicates if the evaluation has started
	background_node: false,		// the background DOM element
	background_opacity: 0.5,	// set the opacity level of the background
	introduction_node: false,	// the introduction DOM element
	container_node: false,		// the container DOM element
	toolbar_node: false,		// the toolbar DOM element
	screenshot_node: false,		// the screenshot image element
	markers: [],				// array with all markers
	marker_limit: 25,			// the maximum number of markers
	marker_height: 37,			// the height of a marker
	marker_width: 39,			// the width of a marker
	allow_notes: true,	 		// set to false to disable notes
	notes: [],					// array containing all the notes
	notes_limit: 10,			// the maximum number of notes
	task_timer: null,			// holds the timer object
	task_time: 0,				// holds the time elapsed in milliseconds
	one_click_test: null,		// set to true if test is a one click test
	alive_interval: 10,			// interval in minutes for the keep-alive function
	data: {},					// contains data for this evaluation

	/**
	 * Initialize the evaluation functionality
	 */
	init: function ()
	{
		// require the drag-n-drop source
		if(typeof dojo !== 'undefined') {
			dojo.require("dojo.dnd.Moveable");
		}

		$('a.external').attr('target', '_blank');

		// get the container and background node
		if(!evaluation.background_node) evaluation.background_node = $('#evaluation_background');
		if(!evaluation.introduction_node) evaluation.introduction_node = $('#evaluation_introduction');
		if(!evaluation.container_node) evaluation.container_node = $('#evaluation_container');
		if(!evaluation.toolbar_node) evaluation.toolbar_node = $('#toolbar');
		if(!evaluation.screenshot_node) evaluation.screenshot_node = $('#evaluation_screenshot img');
		if(!evaluation.loading_node) evaluation.loading_node = $("#evaluation_loading");

		// connect onclick handlers
		evaluation.container_node.bind("click", evaluation.place);
		if(!$(evaluation.introduction_node).hasClass('finished')) {
			evaluation.introduction_node.bind('click', evaluation.start_test);
			// hide loader
			$("#evaluation_task_loading").css("display", "none");
			// show start button
			$(".start").show().animate({
				opacity: 1
			}, "normal", null, null);
		}

		// if browser is IE, also attach placement handlers to the image itself
		if($.browser.msie) {
			evaluation.screenshot_node.bind("click", evaluation.place);
		}

		// determine if a test is a one-click test
		evaluation.one_click_test = evaluation.screenshot_node.parent().hasClass('one-click');

		// set the toolbar to be visible
		evaluation.toolbar_node.visible = true;
		evaluation.toolbar_node.normal_height = $('#ParticipantFeedbackNavigation').outerHeight() - 2;
		
		// set the height of the overlay
		evaluation.background_node.css('opacity', 0.1);
		
		// set transparent background for introduction if the task isn't a 1-click-task
//		if(evaluation.one_click_test == false) {
//			evaluation.introduction_node.css('background', 'url(/gfx/bg_landing.png)');
//		}
	
		// check if this isn't the first page
		if(evaluation.introduction_node == "")
		{
			// mark the evaluation as started
			evaluation.started = true;
			evaluation.show_overlay();
		}

		// set the upper limit for markers or notes
		evaluation.update_counter_limit();

		// keep the session alive
		window.setInterval(evaluation.keep_alive, (evaluation.alive_interval * 60000));

		// hide the toolbar counter
		$('#maximum').hide();
	},

	/**
	 * Start the test
	 */
	start_test: function (e)
	{
		e.preventDefault();

		// mark the evaluation as started
		evaluation.started = true;

		// hide the introduction dialog
		//evaluation.introduction_node.wipeOut().play();
		$(evaluation.introduction_node).animate({
			height: "hide",
			opacity: "hide"
		});

		// change opacity of background to focus on content
		evaluation.show_overlay();

		// start the timer
		evaluation.timer_start();

		// show the scrollbar
		$("body").css("overflow", "auto");
	},

	/**
	 * Start the timer
	 */
	timer_start: function ()
	{
		evaluation.task_timer = window.setInterval(evaluation.timer_tick, 1);
	},

	/**
	 * Execute this function on every tick of the timer
	 */
	timer_tick: function ()
	{
		evaluation.task_time += 1;
	},

	/**
	 * Stop the timer
	 */
	timer_stop: function ()
	{
		window.clearInterval(evaluation.task_timer);
	},

	/**
	 * Keep the PHP session alive
	 */
	keep_alive: function ()
	{
		// make an ajax call to keep the session alive
		var href = window.location.href;
		$.get(href + '/alive');
	},

	/**
	 * Submit the datapoints to the database
	 */
	submit: function ()
	{
		// show load indicator		
		evaluation.loading_node.css("visibility", "visible");
		// fade in indicator
		if (!$.browser.msie) 
		{
			evaluation.loading_node.show().animate({
				opacity: 1
			}, "normal", null, null);
		}
		else 
		{
			evaluation.loading_node.show();
		} 
		
		
		// stop the timer
		evaluation.timer_stop();

		// set the callback function
		var callback = function ()
		{
			evaluation.send_time(evaluation.data.test, evaluation.data.page, evaluation.data.task);
		};

		// connect the callback to the animation end
		evaluation.background_node.animate({opacity: "hide"}, "normal", "swing", callback);

		// fade the datapoints and the background
//		evaluation.fade_out('.evaluation_dot');
	},

	/**
	 * Submit the datapoints to the JSON-RPC service
	 */
	send_datapoints: function (test, page, task)
	{
		// setup the datapoints array
		var points = [];

		// loop through the stored markers and store their datapoints
		for(var i = 0; i < evaluation.markers.length; i++)
		{
			// get the marker x and y coordinates
			points.push([evaluation.markers[i].x, evaluation.markers[i].y]);
		}
		
		// send the datapoints to the database
		custom.rpc.rate.saveDatapoints(test, page, task, points).addCallback(gui.goToUrl);
	},

	/**
	 * Submit the elapsed time for the current tas to the JSON-RPC service
	 */
	send_time: function (test, page, task)
	{
		var callback = function ()
		{
			evaluation.send_notes(test, page, task);
		};
		
		// send the time to the database
		custom.rpc.rate.saveTime(task, evaluation.task_time).addCallback(callback);
	},

	/**
	 * Submit the notes to the JSON-RPC service
	 */
	send_notes: function (test, page, task)
	{
		if(evaluation.allow_notes && evaluation.one_click_test == false)
		{
			var notes = [];
	
			// loop through the stored notes
			for(var i = 0; i < evaluation.markers.length; i++)
			{
				// Get the x-y coordinates and get the text from the note
				var value = dojo.trim(evaluation.markers[i].note.getValue());
				if(value.length)
				{
					notes.push([evaluation.markers[i].x, evaluation.markers[i].y, value]);
				}
			}
			
			var callback = function ()
			{
				evaluation.send_datapoints(test, page, task);
			};
	
			// send the notes to the database
			custom.rpc.rate.saveNotes(test, page, task, notes).addCallback(callback);
		}
		else
		{
			evaluation.send_datapoints(test, page, task);
		}
	},

	/**
	 * Place a note or marker on the container
	 */
	place: function (e)
	{
		if(evaluation.started && e.pageX <= evaluation.screenshot_node.width())
		{
			evaluation.place_marker(e);
		}
	},

	/**
	 * Place a marker on the screen
	 */
	place_marker: function (e)
	{
		// add a marker if the evaluation has started and the maximum has not been reached
		if(evaluation.started === true && evaluation.markers.length < evaluation.marker_limit)
		{
			var div = document.createElement('div');
			var handle = document.createElement('div');
			
			$(handle).addClass('evaluation_handle').text(evaluation.markers.length + 1).data('editing', false);

			$(div).addClass("evaluation_dot")
					.css("left", e.pageX - Math.round(evaluation.marker_width / 2) + 'px')
					.css("top", e.pageY - Math.round(evaluation.marker_height / 2) + 'px');
			
			(!$.browser.msie) ? $(div).css('opacity', 0) : $(div).hide();

			// set this div to be a moveable object
			var moveable = new dojo.dnd.Moveable(div, {handle: handle});
			dojo.connect(moveable, "onMoveStart", evaluation.start_marker_move)
			dojo.connect(moveable, 'onMoveStop', evaluation.end_marker_move);
			dojo.connect(moveable, 'onMoved', evaluation.item_moved);

			// prevent creating a new marker when clicking or dragging the marker
			$(div).bind("click", function(e) { e.stopPropagation(); });
						
			// show del icon if not one-click-task
			if (evaluation.one_click_test == false) {
				var del_point = document.createElement('div');
				$(del_point).bind('click', evaluation.remove_node).addClass('evaluation_del_point');
				$(div).append(del_point);
			}

			// place the marker in the dom
			$(div).append(handle);
			$("body").append(div);
			
			// if notes are enabled:
			if(evaluation.allow_notes && evaluation.one_click_test == false)
			{				
				var ta_div = document.createElement('div');
				var ta = document.createElement('textarea');
				var ta_close = document.createElement('div');
				var add_note = document.createElement('div');
				
				$(ta_div).addClass('evaluation_textarea').hide();
				$(ta_close).addClass('evaluation_textarea_close');
				$(add_note).addClass('evaluation_add_note');

				(!$.browser.msie) ? $(ta_div).css('opacity', 0) : $(ta_div).hide();
				
				// focus the textarea on click
				$(add_note).bind('click', evaluation.focus_note);
				
				$(ta_div).append(ta);
				$(ta_div).append(ta_close);
				$(div).append(add_note).append(ta_div);
				
				var textarea = new dijit.form.Textarea({trim: true, maxLength: 400, style: "height:70px;"}, ta);
				textarea.onBlur = evaluation.blur_note;
				textarea.focus();
			}
			
			// place the marker in the marker array
			evaluation.markers.push({
				x: e.pageX,
				y: e.pageY - evaluation.toolbar_node.normal_height,
				node: div,
				note: textarea
			});
			
			// update the marker counter
			evaluation.update_counter();

			var callback = function() {};

			// submit after the point is placed
			if(evaluation.one_click_test) 
			{
				evaluation.started = false;
				callback = function()
				{
					evaluation.submit();
				};
			}
			
			// fade the datapoint
			evaluation.fade_in(div, callback);
		}
	},

	/**
	 * Executed when starting to move a marker
	 */
	start_marker_move: function ()
	{
		// IE has problems with rendering opacity on transparent PNG's, only use transparency if not IE
		if (!$.browser.msie) { $(this.node).css('opacity', 0.4); }
	},

	/**
	 * Executed when a marker has been moved
	 */
	end_marker_move: function ()
	{
		var x = dojo.style(this.node, 'left') + Math.round(evaluation.marker_width / 2);
		var y = (dojo.style(this.node, 'top') + Math.round(evaluation.marker_height / 2)) - evaluation.toolbar_node.normal_height;

		for(var i = 0; i < evaluation.markers.length; i++)
		{
			if(evaluation.markers[i].node == this.node)
			{
				evaluation.markers[i].x = x;
				evaluation.markers[i].y = y;
				break;
			}
		}

		evaluation.fade_in(this.node);
	},

	item_moved: function ()
	{
		var margin = 7;
		var height = (evaluation.screenshot_node.height() + evaluation.toolbar_node.normal_height);

		// top
		if(parseInt($(this.node).css('top')) <= (evaluation.toolbar_node.normal_height - margin))
		{
			$(this.node).css('top', (evaluation.toolbar_node.normal_height - margin) + 'px');
		}

		// left
		if(parseInt($(this.node).css('left')) <= 0 - margin)
		{
			$(this.node).css('left', 0 - margin + 'px');
		}

		// right
		if(parseInt($(this.node).css('left')) >= (evaluation.screenshot_node.width() - margin))
		{
			$(this.node).css('left', (evaluation.screenshot_node.width() - margin) + 'px');
		}

		// bottom
		if(parseInt($(this.node).css('top')) >= (height - margin))
		{
			$(this.node).css('top', (height - margin) + 'px');
		}
	},

	/**
	 * Remove the last added marker or note
	 */
	remove_last: function ()
	{
		var list = evaluation.markers;

		if(list.length)
		{
			var node = list[list.length - 1].node;
			node.parentNode.removeChild(node);
			list.splice(list.length - 1, 1);
			evaluation.update_counter();
		}
	},

	/**
	 * Remove the marker or note that was clicked on
	 */
	remove_node: function (e)
	{
		e.stopPropagation();

		var list = evaluation.markers;
		var node = $(this).parent();
		var i = ($(node).text() - 1);

		$(node).remove();
		list.splice(i, 1);
		evaluation.update_counter();
	},

	/**
	 * Remove all markers or notes
	 */
	remove_all: function (message)
	{
		var list = evaluation.markers;
		var answer = confirm(message);

		if(answer && list.length)
		{
			for(var i = list.length - 1; i >= 0; i--)
			{
				var node = list[i].node;
				list.splice(i, 1);
				node.parentNode.removeChild(node);
			}

			evaluation.update_counter();
		}
	},

	/**
	 * Hide the last created note
	 */
	blur_note: function ()
	{	
		for(var i = 0; i < evaluation.markers.length; i++)
		{
			if(evaluation.markers[i].note == this)
			{
				var node = $(evaluation.markers[i].node);
				node.data('editing', false);
				evaluation.fade_out(node.find('.evaluation_textarea'));
				
				var value = dojo.trim(this.getValue());
				evaluation.markers[i].note.setValue(value);
				// change icon for 'add_note' if note is not empty
				if (value != "") 
				{ 
					node.find('.evaluation_add_note').css('background-position', '0 -85px'); 
				} else {
					node.find('.evaluation_add_note').css('background-position', '0 -45px'); 
				}					
				break;
			}
		}
	},

	/**
	 * Focus the note that was just clicked on
	 */
	focus_note: function (e)
	{	
		for(var i = 0; i < evaluation.markers.length; i++)
		{
			if(evaluation.markers[i].node == this.parentNode)
			{
				var node = $(evaluation.markers[i].node);
				node.data('editing', true);
				evaluation.fade_in(node.find('.evaluation_textarea'));
				evaluation.markers[i].note.focus();
				break;
			}
		}
	},

	/**
	 * Show the overlay
	 */
	show_overlay: function ()
	{
		$(evaluation.background_node).animate({opacity: evaluation.background_opacity});
	},

	/**
	 * Hide the overlay
	 */
	hide_overlay: function ()
	{
		evaluation.fade_out(evaluation.background_node);
	},

	/**
	 * Update the marker counter
	 */
	update_counter: function ()
	{
		var list = evaluation.markers;
		var max = evaluation.marker_limit;

		// Update the numbers for points
		for(var i = 0; i < list.length; i++) {
			$(list[i].node).find('.evaluation_handle').text(i + 1);
		}

		// Show message that max is reached
		if (list.length == max) {
			evaluation.fade_in('#maximum');
		} else {
			evaluation.fade_out('#maximum');
		}
	},

	/**
	 * Update the upper limit of the counter
	 */
	update_counter_limit: function ()
	{
		// show the max number of datapoints in the toolbar
		var counter_max = $("#maximum_max");

		if(counter_max)
		{
			counter_max.text(evaluation.marker_limit);

			$("#maximum_max_name").text("points");
		}
	},

	fade_in: function (node, callback)
	{
		if (typeof callback != 'function') {
			callback = function() {};
		}
		if (!$.browser.msie) 
		{
			$(node).show().animate({
				opacity: 1
			}, "normal", null, callback);
		}
		else 
		{
			$(node).show();
			callback();
		} 
	},

	fade_out: function (node, callback)
	{
		if (typeof callback != 'function') {
			callback = function() {};
		}
		if (!$.browser.msie) 
		{
			$(node).animate({
				opacity: 0
			}, "normal", null, callback).hide();
		}
		else 
		{
			$(node).hide();
			callback();
		}
	}
};

// Add an onload event
$(document).ready(evaluation.init);