// $Id: async.js,v 1.62 2008/10/16 04:03:46 daniel Exp $

/**
 * Functions used to perform asynchronous update of the user interface.
 */

/**
 * Gets the current theme.
 */
function getTheme() {
    return $('theme').value;
}

/**
 * Sets the current theme.
 */
function setTheme(theme) {
    $('theme').value = theme;
}

/**
 * Gets the currently selected indicator.
 */
function getIndicator() {
    return getSelectedOptionValue('indicator-select');
}

/**
 * Gets the currently selected domain.
 */
function getDomain() {
    return getSelectedOptionValue('domain-select');
}

/**
 * Function to get a timestamp.
 */
function getTimestamp() {
    var day = new Date();
    return day.getTime();
}

// Global to keep track of how many asynchronous requests are currently
// being serviced.
var numLoading = 0;

var updatingTab = false;

/**
 * Disables the three buttons at the bottm of the form.
 */
function disableButtons() {
    $('spreadsheetButton').disabled = true;
    $('graphButton').disabled = true;
    $('pdfButton').disabled = true;
}

/**
 * Enables the three buttons at the bottom of the form.
 */
function enableButtons() {
    $('spreadsheetButton').disabled = null;
    $('graphButton').disabled = null;
    $('pdfButton').disabled = null;
}

// register global handlers
var myGlobalHandlers = {
		onCreate: function(){
			$('loading').style.display = 'block';
            disableButtons();
		},

		onComplete: function() {
			if(Ajax.activeRequestCount <= 0){
			    Ajax.activeRequestCount = 0; // sanity check
				$('loading').style.display = 'none';
                enableButtons();
			}
		}
	};

Ajax.Responders.register(myGlobalHandlers);

/**
 * Checks to see if there is something loading.
 */
function isLoading() {
    return Ajax.activeRequestCount > 0;
}

// updatesInProgress allows us to track the actual Ajax.Updater objects that are currently active
var updatesInProgress = {};
var AjaxObjects = {};

var maxTimeTaken = 2500;

function asyncRequest(params, oncomplete) {
    asyncUpdate(null, params, oncomplete, null);
}

/**
 * Performs an asynchronous update of the div with the given id.
 *
 * @param destId the id of the div to be updated
 * @param params any query parameters to pass in the request
 * @param oncomplete the function to call on the async completion (may be null)
 */
function asyncUpdate(destId, params, oncomplete, timeout) {
    var url = '/index.php';
	var uniqId = getTimestamp();
	updatesInProgress[uniqId] = true;

	// default timeout is the maximum time taken for any previous successful request
	if (timeout == null) {
		//alert('setting timeout to the maxtimetaken so far: ' + maxTimeTaken);
	    timeout = maxTimeTaken;
	}

	var func = 'kill("' + uniqId + '", "' + destId + '", "' + params + '", ' + oncomplete + ', ' + timeout + ')';
	//setTimeout(func, timeout);

	var options = {
                method: 'post',
                parameters: params,
                asynchronous: true,
                onSuccess: function(originalRequest) {
					updatesInProgress[uniqId] = false;
					// if we have a desination element id, update it
					if (destId != null) {
					    Element.update(destId, originalRequest.responseText);
					}
                    if (oncomplete != null) {
                        oncomplete.call(this, originalRequest);
                    }
					var t = getTimestamp() - uniqId;
					if (t > maxTimeTaken) {
					    maxTimeTaken = t;
					}
                },
                onFailure: function(originalRequest) {
					restoreBrowser(uniqId, destId, params, oncomplete, timeout);
					updatesInProgress[uniqId] = false;
                }
            };

    AjaxObjects[uniqId] = new Ajax.Request(url, options);	
    /*
     *	if (AjaxObjects[uniqId].transport.readyState != 1) {
     *    alert("Hi " + AjaxObjects[uniqId].transport.readyState);
     *	}
	 */
}

function kill(uniqId, destId, params, oncomplete, timeout) {
    if (updatesInProgress[uniqId] != false) {
	    // OMG that thing has still not come back
	    restoreBrowser(uniqId, destId, params, oncomplete, timeout);
	}
}

function restoreBrowser(uniqId, destId, params, oncomplete, timeout) {
	var transport = AjaxObjects[uniqId].transport;
	// if the request hasn't completed, or if it completed but failed
	if (transport.readyState < 2 || (transport.readyState == 4 && transport.status != 200)) {
//	    alert('restoring');
        // increase the timeout so we aren't so keen to call this again
		timeout += timeout;
		//alert("Increasing timeout to " + timeout);

		// I guess if timeout gets to 1 minute we have serious issues
		if (timeout > 60000) {
		    alert("Something is obviously wrong.  Give up and contact pisa@acer.edu.au");
			exit();
		}

    	if (transport.readyState < 2) {
    	    // request has somehow been reset
    	    AjaxObjects[uniqId].transport.abort();

            // decrease our count, which is gonna be out of sync
    	    Ajax.activeRequestCount--;
    	}

	    // try again
	    asyncUpdate(destId, params, oncomplete, timeout);
	}
}

/**
 * Updates the domain select box.  Called when the indicator selection is
 * changed.
 */
function updateDomainSelect() {
    var indicator = getIndicator();

    var params = 'cmd=updateDomainSelect' + '&indicator=' + getIndicator() + '&domain=' + getDomain();

//    var url = '/index.php';
//
//	var options = {
//                method: 'post',
//                parameters: params,
//                asynchronous: true,
//                onComplete: function(originalRequest) {
//					onDomainChange();
//                },
//                onFailure: function(originalRequest) {
//					alert('failed');
//                }
//            };
//    new Ajax.Updater('domain-select-container', url, options);


    asyncUpdate('domain-select-container', params,
            function(originalRequest) {
                onDomainChange();
            });
}

/**
 * Updates the indicator options.  Called when the indicator selection is
 * changed.
 */
function updateIndicatorOptions() {
    var indicator = getIndicator();
	var themeId = document.forms[0][getTheme()].value;
    var params = 'cmd=updateIndicatorOptions' + '&indicator=' + indicator + '&domain=' + getDomain() + '&theme=' + themeId;
    asyncUpdate('indicator-options-container', params);
}

function updateIndicator() {
    var indicator = getIndicator();
    $('indicator-msg').innerHTML = getIndicatorDataAvailability(indicator);
}

/**
 * Called when the indicator selection changes.  Updates the domain select box.
 */
function onIndicatorChange() {
    updateIndicator();
    updateDomainSelect();
}

/**
 * Called when the domain selection changes.  Updates the indicator options
 * section, which may be different for different domains.
 */
function onDomainChange() {
    updateDomainDescription();
    updateIndicatorOptions();
}

/**
 * Updates the domain description.
 */
function updateDomainDescription() {
    $('domain-description').innerHTML = domains[getDomain()];
}

/**
 * Changes the theme.
 *
 * @param themeId the xml id of the theme to change to
 */
function changeTheme(themeId) {
    // if we're already loading something, don't do anything
    if (isLoading()) {
        return;
    }
    $('tab-' + getTheme()).className = 'tab';
    $('tab-' + themeId).className = 'current-tab';
    updateThemeTabContent(themeId);
}

/**
 * Called when a theme tab catches a mouseover event.  Displays a tooltip
 * with a description of the theme if the theme tab isn't currently selected.
 *
 * @param element the theme tab div
 * @param themeId the id of the theme
 */ 
function themeTabMouseover(event, themeId) {		
    if (themeId != getTheme()) {
    	tooltip(event, themes[themeId].description, null);
    }
}

/**
 * Cached fragments of HTML for the theme tab contents.
 */
var cachedThemeTabContents = {};

/**
 * Updates the content of the theme tab.
 */
function updateThemeTabContent(themeId) {
    while (updatingTab === true) {
	  // do nothing
	}
	updatingTab = true;
    var theme = getTheme();

    var element = $('theme-tab-content');

    // cache the current contents of the theme tab div
    //cachedThemeTabContents[theme] = element.firstChild;

    setTheme(themeId);

    // check to see if the theme is cached, if it is, simply replace the current
    // node with the cached one and return
    /*if (cachedThemeTabContents[themeId] != null) {
        var children = element.childNodes;
        element.replaceChild(cachedThemeTabContents[themeId], children.item(0));

        //alert(cachedThemeTabContents[themeId].toString());
        return;
    }*/

    // otherwise update it via ajax
        
    var params = 'cmd=updateThemeTabContent' + '&theme=' + themeId + '&domain=' + getDomain();

    asyncUpdate('theme-tab-content', params,
            function(originalRequest) {
                updateIndicator();                
            }, null);
	updatingTab = false;
}

/**
 * Gets a reference to the form object.
 */
function getForm() {
    return $('pisaform');
}

/**
 * Submits the form.
 */
function submitForm() {
    selectAll();
    getForm().submit();
    selectNone();
}

/**
 * Sets the value of the hidden command field.
 *
 * @param command the new command
 */
function setCommand(command) {
    $('cmd').value = command;
}

/**
 * Function called when the 'produce graph' button is pressed.
 */
function produceGraph(type) {

    var params = '';

    /**
     * check the parameter passed in, if it is a number
     * then the requestid should not be re-generated
     * else, generate a unique request id
     * form values only need to be submitted if this is a new request
     * history requests can get historic options from the session
     * using the request id that is passed in as a parameter
     */
    if ($F('requestid') == '') {
        var id = getTimestamp();
        setRequestId(id);
        setCommand('storeGraphRequest');
        var elements = getForm().elements;

        // get the values of the form elements

        var element;
        for (var i = 0; i < elements.length; i++) {
            element = elements[i];
            // we need to do something special for the comparison countries
            // select, so treat it differently
            if (element.name == 'compCountries[]') {
                var options = element.options;
                for (var j = 0; j < options.length; j++) {
                    var option = options[j];
                    params += 'cc[' + j + ']=' + option.value + '&';
                }
            // we also treat checkboxes differently, we only put the variable in
            // the query string if the box is checked
            } else if (element.type == 'checkbox') {
                if (element.checked) {
                    params += element.name + '=on&';
                }
            // all other elements we can just use the name and value
            } else if (element.type == 'radio') {
                if (element.checked) {
                    params += element.name + '=' + element.value + '&';
                }
            } else if (element.type == 'button') {
                // do nothing
            // all other elements we can just use the name and value
            } else {
                params += element.name + '=' + element.value + '&';
            }
        }

        // clear the command
        setCommand('');
    }
    else {
        id = $F('requestid');
        params += 'requestid=' + id;
    }

    // clear the request id (we have it in the params string)
    setRequestId('');

    var url;
    if (type == 'html') {
        url = "/displayGraph.php";
    } else if (type == 'pdf') {
        url = "/displayPdf.php";
    } else {
        alert('Unknown graph type: ' + type);
        exit();
    }
		
    spawnWindow(url + "?" + params);
}

/**
 * Function called when the 'produce spreadsheet' button is pressed.
 * Sets a hidden field to set the command, then submits the form.
 */
function produceSpreadsheet() {
    var refreshHistory = false;
    setCommand('produceSpreadsheet');
    /**
     * check if the  hidden field storing the request id is empty or not
     * if it is empty, then this is a new request
     * else, this is an history log request
     */
    if ($F('requestid') == '') {
        var id = getTimestamp();
        setRequestId(id);
        refreshHistory = true;
    }
    // this will cause a spreadsheet download
    submitForm();
    // clear the request id field
    setRequestId('');
    if (refreshHistory === true) {
        getHistory();
    }
}

/**
 * Function called when the 'produce pdf' button is pressed.
 * Sets a hidden field to set the command, then submits the form.
 */
function producePDF() {
    // create the graph to be attached to the pdf
    produceGraph('pdf');
}

/**
 * Spawns a graph window for the graph request with the given id.
 */
function spawnWindow(url)
{
    var id = getTimestamp();
    var graphWindow = window.open(url, "page" + id, 'toolbar=0,scrollbars=1,location=1,statusbar=1,menubar=0,resizable=1,width=900,height=800,left=30,top=30');
    if (graphWindow === null) {
        alert('A popup blocker is preventing the graph from being displayed.\nTry disabling the popup blocker, or add this site to your list of allowed sites in order to view the graph.');
    }
    return graphWindow;
}

/**
 * Displays a tooltip with (optional) caption.
 *
 * @param element the HTML element to connect the tooltip to
 * @param text the text for the tooltip
 * @param captionText the (optional) caption text
 */
function tooltip(event, text, captionText) {
  	showCursorNote(event, text, captionText);
}

function tooltipVauto(event, text, title) {
	showCursorNote(event, text, title);
}


/**
 * Displays a popup.  Popups include body text, caption text and a 'close' link
 * to close them.
 *
 * @param text the text for the popup
 * @param captionText the text for the caption
 */
function popup(text, captionText) {
    
}

function removeHistoryItem(index, key) {
    var params = '';
    params = 'requestid=' + key;
    params += '&cmd=removeHistoryItem';
    $('item' + index).style.display = 'none';
    document.body.style.cursor = 'wait';
    // disable all other delete options until the history has been re-loaded
    var items = $F('items');
    for (var i = 0; i < items; i++) {
        if (i != index) {
            $('trash' + i).onclick = null;
            $('trash' + i).style.cursor = 'default';
        }
    }

    // perform a request to store the data on the server
    asyncUpdate('historySection', params, function(response) {
                    document.body.style.cursor = 'default';
                });
}

function getHistory() {
    // perform a request to get the latest info from the server
    asyncUpdate('historySection', 'cmd=getLatestHistory');
}

// create a function in this window so we can refresh the history from another
// (e.g. the graph popup)
window.refreshHistory = getHistory;

function setRequestId(id) {
    $('requestid').value = id;
}

/**
 * close the current window
 * and focus on the window that opened me
 */
function closeFocus() {
    window.close(0);
    window.opener.focus();
}

