//$(document).ready(init_loader());

var gReloadTimer;
var gSProcessStatus = { "init" : false };
var gServerStatus = { "query" : false, "session" : false };
var gTimeOuts = { "polling" : 2000, "status_response" : 20000, "retry" : 15000, "progress" : 70000 } // 2s, 20s, 15s, 70s
var STATUS_TIMEOUT = 1;
var PROGRESS_TIMEOUT = 2;

var gClientStatus = { 
	"length" 	: 	0, 		// { SERVER } total number of feature extractions 
	"progress" 	: 	0, 		// { SERVER } completed feature extractions 
	"started" 	: 	false,  // { SERVER } process started 
	"alive" 	: 	false, 	// { SERVER } precess currently active 
	"completed" : 	false, 	// { SERVER } process complete 
	"previous"  : 	0, 		// { LOCAL  } previous progress status
	"init" 		: 	false, 	// { LOCAL  } process initialised from server data (retreived)
	"visible"	:   false, 	// { LOCAL  } widget visible
	"changed"	:   false, 	// { LOCAL  } set when the progress status changed
	"stalled"	:   false, 	// { LOCAL  } set if no change over 2-3 minutes
	"timeout"	: 	false, 	// { LOCAL  } set if no change over 2-3 minutes
	"hasChanged":   false,	// { LOCAL  } set if the process has changed (for timeout control)
	"firstLoad" :   false,	// { LOCAL  } set once the initial waiting message has been loaded
	"timeoutMsg":   "none",	// { LOCAL  } set to some meaningful message for the timeout
	"timeoutReason": 0,		// { LOCAL  } reson for timeout: 1=get_process_status, 2=no_progress
	"errorCode": 	""		// { LOCAL  } url error_code for main page redirection in case of error
	};


function init_loader()
{
	check_timeouts();
	hide_element('progress_status_field');	
	load_content();
	gClientStatus.init = false;
	gSProcessStatus.init = false;
	$("span#download_all").click(function() { 
		var htmlStr = $(this).html();
		setTimeout(function(){ $("span#download_all").html(htmlStr + "<b> Please wait while retrieving and compressing data...</b>"); },500);
		setTimeout(function(){ $("span#download_all").html(htmlStr); },8000);	
	 });
}


/*
   A ProgressBar() object prototype (i.e. the JS way of defining a class)

	This object encapsulate a jQueryUI ProgressBar class.
	It has features to calculate the proportional value of the progress bar
	given the total number of jobs and the number of completed jobs.
	
	It also tries to estimate progress (quite badly though), to make the 
	movement smoother.
	
	Usage:	
	The first update starts the progress bar, e.g.:
	p = new ProgressBar();
	p.update(0,total);
	if (process.failed) p.stop();
	
	Depends on: jQueryUI.ProgressBar()

*/
	
/// ProgressBar() object prototype (i.e. JS way of class)
function ProgressBar()
{
	this.timer = false;
	this.target = 0;	
	this.value = 0;	
	this.increment = 1;
	this.length = 1;
	this.base_interval = 150;
	this.time_interval = this.base_interval;
	this.interval_change_rate = 1.02;
}

ProgressBar.prototype.timed_update = function()
{
	$("div#progressbar").progressbar({ value: this.value });
	this.value += this.increment;
	if (this.value < this.target-this.increment)
	{
		this.time_interval = parseInt(this.time_interval * this.interval_change_rate);
		this.timer = setTimeout("gProgressBar.timed_update()", this.time_interval);
		// this.timer = setTimeout(self.timed_update(), 300);
	}
}

ProgressBar.prototype.start_update = function(new_value)
{
	section_length = parseInt(100 / this.length);
	if (isNaN(section_length)) { section_length = 100; } 
	if (new_value >= this.value) 
	{
		this.value = new_value;
		this.target = new_value + section_length;
	}
	this.increment = 1;
	this.timed_update();
}

ProgressBar.prototype.update = function (progress, length)
{
	if (length == 0) { return; }	
	progress_value = parseInt( 100 * (progress / length) );
	if (isNaN(progress_value)) { progress_value = 0; }
	this.length = length
	clearTimeout(gProgressBar.timer)
	this.time_interval = this.base_interval + (length * 30);
	this.start_update(progress_value);
	//$("div#progressbar").progressbar({ value: progress_value });
}

ProgressBar.prototype.stop = function ()
{
	clearTimeout(gProgressBar.timer);
	gProgressBar.timer = false;
}

ProgressBar.prototype.reset = function ()
{
	this.value = 0;
	this.target = 0;
	this.time_interval = this.base_interval
	$("div#progressbar").progressbar({ value: this.value });	
	if (gProgressBar.timer) clearTimeout(gProgressBar.timer);
}


/*
	END: ProgressBar Declaration

*/


var gProgressBar = new ProgressBar;


function hide_element(idstr)
{
	element = document.getElementById('progress_status_field');
	element.style.display = 'none';
}

function show_element(idstr)
{
	element = document.getElementById('progress_status_field');
	element.style.display = '';
}

function write_status(progress,length)
{
	$("div#status").html("Completed " + progress.toString()+" of " + length.toString()+" transforms.");
}

function write_status_txt(txt)
{
	$("div#status").html(txt);
}



/*









								TEST NEW FUNCTIONS













*/

function update_process_status(json_data,textStatus)
{
	gSProcessStatus = json_data.ps;
	gClientStatus.init = true;
	gSProcessStatus.init = true;
}


/// status event loop
function load_content()
{
	
	/// Get the data from the server	
	$.getJSON("get_process_status",update_process_status);
	
	/// 1) setup polling
	if (!gClientStatus.init || (!gClientStatus.timeout && !gSProcessStatus.stopped))
	{
		gReloadTimer = setTimeout("load_content()", gTimeOuts.polling); //2secs
	}
	
	/// 2) initial load: fill the results table container with an ajax loader image/message
	if (!gClientStatus.firstLoad)
	{
		$("div#results_table").load("results_table");
		gClientStatus.firstLoad = true;
		$("div#results_header").show();		
	}	
			
	/// 3) turn on the status field if needed: (if we have a live process thread)
	if (!gClientStatus.visible && gSProcessStatus.alive && !gSProcessStatus.stopped)
	{
		show_element('progress_status_field');		
		gClientStatus.visible = true;
		gClientStatus.hasChanged = true;		
		// write_status( gSProcessStatus.progress, gSProcessStatus.length );
		// if (gSProcessStatus.length == 1) gProgressBar.time_interval = 200;
		// if (gSProcessStatus.started) gProgressBar.update(0,gSProcessStatus.length);
		if (!gSProcessStatus.started) {
			$("div#status_message").html("<b>Status:</b> Please wait while scheduling tasks."); }
	}
	
	/// 4) kickstart the progress bar when the process starts	
	if (gSProcessStatus.started && !gClientStatus.started)
	{
		write_status( gSProcessStatus.progress, gSProcessStatus.length );
		if (gSProcessStatus.length == 1) gProgressBar.time_interval = 200;
		gProgressBar.update(0,gSProcessStatus.length);
		gClientStatus.started = true;
		gClientStatus.hasChanged = true;
		$("div#progress_details").show();
		$("div#current_task").html("<b>Processing:</b> "+gSProcessStatus.current_file+"<br /><b>Plugin:</b> "+gSProcessStatus.current_plugin+"<br /><b>Output:</b> "+gSProcessStatus.current_output+"<br /><b>Transform name:</b> "+gSProcessStatus.current_transform_name+"<br /><b>Task:</b> "+gSProcessStatus.current_task+"<br />");
		$("div#status_message").html("<b>Status:</b> Started scheduled tasks: Extracting features...");
	}
			
	/// 5) update the progress bar and load new results on change
	if (gSProcessStatus.changed || gSProcessStatus.stopped)
	{
		gClientStatus.hasChanged = true;
		gProgressBar.update( gSProcessStatus.progress, gSProcessStatus.length );
		write_status( gSProcessStatus.progress, gSProcessStatus.length );
		$("div#current_task").html("<b>Processing:</b> "+gSProcessStatus.current_file+"<br /><b>Plugin:</b> "+gSProcessStatus.current_plugin+"<br /><b>Output:</b> "+gSProcessStatus.current_output+"<br /><b>Transform name:</b> "+gSProcessStatus.current_transform_name+"<br /><b>Task:</b> "+gSProcessStatus.current_task+"<br />");
		if (gSProcessStatus.new_result || gSProcessStatus.stopped) 
		{
			$("div#status_message").html("<b>Status:</b> Extracting features and loading results...");
			$("div#results_table").load("results_table");
			//$("div#results_header").show();
		}
	}
	
	/// 6) report on completion or error (this must be last)
	if (gClientStatus.visible && gSProcessStatus.stopped)
	{
		gClientStatus.hasChanged = true;
		if (!gSProcessStatus.exception && !gSProcessStatus.failed)
		{
			$("div#current_task").html("");
			$("div#progress_details").hide();
			$("div#status_message").html("<b>Status:</b> Completed scheduled tasks: "+gSProcessStatus.success.toString()+" succeeded, "+gSProcessStatus.failure.toString()+" failed <small style='color:#555;'>("+gSProcessStatus.cached.toString()+" obtained from cache)</small>");
		}
		else
		{   
			gProgressBar.stop();
			$("div#status_message").html("<b>Status:</b> <span style='color:red;'>Can not continue:</span> The process failed due to an exception in the feature extractor thread (completed "+gSProcessStatus.success.toString()+" tasks). ");
			$("div#error_message").html("<b>Error:</b> " + gSProcessStatus.errors);
			$("div#error_message").show()
		}
		
	}
	
	
	/// 7) handle timeouts	
	//if (gClientStatus.hasChanged) { gClientStatus.timeout = false; }
	if (gClientStatus.timeout)
	{
		$("div#status_message").html("<b>Status:</b> Process timed out.");
		gProgressBar.stop();
		clearTimeout(gReloadTimer) ;
		handle_timeouts()
	}

}

/*  HANDLE TIMEOUT PROBLEMS */

// reload the main page with an error message
function redirect_with_error()
{
	url = "/sawa/?error_code=" + gClientStatus.errorCode;
	window.location = url;
}

function redirect_if_not_started()
{
	// once a timeout happened, we retry one more time:
	// if the process has not started by the time this is called, redirect to the main page	
	if (!gSProcessStatus.started)
	{
		clearTimeout(gReloadTimer);
		redirect_with_error();
	}
}

function redirect_if_not_changed()
{
	// once a timeout happened, we retry one more time:
	// if the process has not changed by the time this is called, redirect to the main page	
	if (!gClientStatus.hasChanged && gClientStatus.timeout)
	{
		clearTimeout(gReloadTimer);
		redirect_with_error();
	}
}


function display_timeout_message()
{
	show_element('progress_status_field');
	$("div#status_message").html("<b>Status:</b> " + gClientStatus.timeoutMsg);
}

function handle_timeouts()
{
	// NOTE: we may retry once more, so clear this
	gClientStatus.timeout = false;	
	if (gClientStatus.timeoutReason == STATUS_TIMEOUT)
	{
		display_timeout_message();
		gClientStatus.errorCode="process_timeout"; //this is for the server side handler
		/// start polling again, but if nothing happens within 10s, redirect with error
		gReloadTimer = setTimeout("load_content()", gTimeOuts.polling); //2secs
		setTimeout('redirect_if_not_started()',gTimeOuts.retry);
	}

	if (gClientStatus.timeoutReason == PROGRESS_TIMEOUT)
	{
		display_timeout_message();
		gClientStatus.errorCode="process_timeout"; //this is for the server side handler
		/// start polling again, but if nothing happens within 10s, redirect with error
		gReloadTimer = setTimeout("load_content()", gTimeOuts.polling); //2secs
		setTimeout('redirect_if_not_changed()',gTimeOuts.retry);
	}	
}

function status_response_timeout()
{
	// set a timeout if status response was not obtained or the process
	// hasn't been started by the time this function is called
	if (!gSProcessStatus.init || !gSProcessStatus.started)
	{
		gClientStatus.timeoutReason = STATUS_TIMEOUT;
		gClientStatus.timeoutMsg = "Process did not start in a timely manner. <a href='/sawa/results'>Please try again later.</a>";
		gClientStatus.timeout = true;
		display_timeout_message();		
	}
	// only needs to check it once, hence no recursion
}

function progress_timeout()
{
	// we require a change in status at least by this time
	// (this timeout should be cleared at every change)
	if (!gSProcessStatus.stopped && !gClientStatus.hasChanged)
	{
		gClientStatus.timeoutReason = PROGRESS_TIMEOUT;
		gClientStatus.timeoutMsg = "A task did not progress in a timely manner. The server may have become unresponsive or overloaded. <a href='/sawa/results'>Please try again later.</a>";
		gClientStatus.timeout = true;
		display_timeout_message();		
	}
	gClientStatus.hasChanged = false;
	setTimeout("progress_timeout()",gTimeOuts.progress);
}


function check_timeouts()
{
	/// kickstart the timeout checking process
	if (!gClientStatus.timeout)
	{
		/// check the responsiveness of th "get_status_response()" handler on the seerver side
		setTimeout("status_response_timeout()",gTimeOuts.status_response);
		/// check if the process in not stalled on the server side		
		setTimeout("progress_timeout()",gTimeOuts.progress);
	}
}






















