/**
 * Contains methods for reading metadata from the server.  The server can also
 * delegate requests to a third-party server, thereby allowing third-party data
 * to be displayed on the Godiva2 site.
 */

// Converts ISO8601 string to Date object
// From http://delete.me.uk/2005/03/iso8601.html, copied 16th October 2007
function iso8601ToDate(string)
{
    var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" +
        "(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?" +
        "(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
    var d = string.match(new RegExp(regexp));

    var offset = 0;
    var date = new Date(d[1], 0, 1);

    if (d[3]) { date.setMonth(d[3] - 1); }
    if (d[5]) { date.setDate(d[5]); }
    if (d[7]) { date.setHours(d[7]); }
    if (d[8]) { date.setMinutes(d[8]); }
    if (d[10]) { date.setSeconds(d[10]); }
    if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); }
    if (d[14]) {
        offset = (Number(d[16]) * 60) + Number(d[17]);
        offset *= ((d[15] == '-') ? 1 : -1);
    }

    offset -= date.getTimezoneOffset();
    var time = (Number(date) + (offset * 60 * 1000));
    var ret = new Date();
    ret.setTime(Number(time));
    return ret;
}
    
/**
 * Function for making an Ajax request to the server.  This will
 * simply throw an alert if the XMLHttpRequest call fails.
 * @param url URL to the third-party server or '' to read data from the "home" server
 * @param Object containing parameters, which must include:
 *        urlparams Object containing the URL parameters
 *        onSuccess Callback to be called with the JSON object that is
 *                  returned from the server
 *        onServerError Callback to be called when the server reports an error
 *                  (if omitted, a default is provided)
 */
function makeAjaxRequest(url, params) {
    if (typeof params.onServerError == 'undefined') {
        params.onServerError = function(exception) {
            alert("Server exception class: " + exception.className + 
                ", Message: " + exception.message);
        }
    }
    // Add the common elements to the URL parameters
    if (url != null && url != '') {
        params.urlparams.url = url;
    }
    params.urlparams.request = 'GetMetadata';

    new Ajax.Request('wms', {
        method: 'get',
        parameters: params.urlparams,
        onSuccess: function(transport) {
            try {
                var myobj = transport.responseText.evalJSON();
            } catch(err) {
                alert("Problem contacting Model Data Server");
                return;
            }
            if (typeof myobj.exception == 'undefined') {
                params.onSuccess(myobj);
            } else {
                params.onServerError(myobj.exception);
            }
        },
        onFailure: function() {
            alert('Error getting data from server'); // TODO: get the full URL somehow?
        }
    });
}


function makeObsAjaxRequest(url, params) {
    if (typeof params.onServerError == 'undefined') {
        params.onServerError = function(exception) {
            alert("Server exception class: " + exception.className + 
                ", Message: " + exception.message);
        }
    }
    // Add the common elements to the URL parameters
    if (url != null && url != '') {
        params.urlparams.url = url;
    }
    params.urlparams.request = 'GetMetadata';

    //new Ajax.Request('http://localhost:8084/ECOOPObs/ECOOPObsServlet', {
    new Ajax.Request('http://lovejoy.nerc-essc.ac.uk:8080/ECOOPObs/ECOOPObsServlet', {
    //new Ajax.Request('http://lovejoy.nerc-essc.ac.uk:9080/ECOOPObs/ECOOPObsServlet', {
        method: 'get',
        parameters: params.urlparams,
        onSuccess: function(transport) {
            try {
                var myobj = transport.responseText.evalJSON();
            } catch(err) {
                alert("Problem contacting Obs Data Server. There may not be data available for your choice of date, parameter and obs platform. Please try another choice.");
                return;
            }
            if (typeof myobj.exception == 'undefined') {
                params.onSuccess(myobj);
            } else {
                params.onServerError(myobj.exception);
            }
        },
        onFailure: function() {
            alert('Error getting data from obs server'); // TODO: get the full URL somehow?
        }
    });
}

/**
 * Gets the skeleton hierarchy of layers that are offered by this server
 * @param node Root node to which this hierarchy will be added
 * @param params Object containing a callback that will be called when the result
 * is returned from the server and an optional menu argument that can be used to
 * load a specific menu structure.
 */
function getMenu(node, params) {
    makeAjaxRequest(node.data.server, {
        urlparams: {
            item: 'menu',
            menu: typeof params.menu == 'undefined' ? '' : params.menu
        },
        onSuccess: function(layers) { 
            params.callback(node, layers);
        }
    });
}

/**
 * Gets the details for the given displayable layer
 * @param Object containing parameters, which must include:
 *        callback the function to be called with the object that is returned
 *            from the call to the server
 *        layerName The unique ID for the displayable layer
 *        time The time that we're currently displaying on the web interface
 *            (the server calculates the nearest point on the t axis to this time).
 */
function getLayerDetails(url, params) {
    this.makeAjaxRequest(url, {
        urlparams: {
            item: 'layerDetails',
            layerName : params.layerName,
            time: params.time
        },
        onSuccess: function(layerDetails) {
            // Convert the nearest-time ISO string to a Javascript date object
            if (typeof layerDetails.nearestTimeIso != 'undefined') {
                layerDetails.nearestTime = iso8601ToDate(layerDetails.nearestTimeIso);
            }
            layerDetails.server = url;
            layerDetails.id = params.layerName;
            params.callback(layerDetails);
        }
    });
}

/**
 * Gets the timesteps for the given displayable layer and the given day
 * @param Object containing parameters, which must include:
 *        callback the function to be called with the object that is returned
 *            from the call to the server (an array of times as strings)
 *        layerName The unique ID for the displayable layer
 *        day The day for which we will request the timesteps, in "yyyy-mm-dd"
 *            format
 */
function getTimesteps(url, params) {
    this.makeAjaxRequest(url, {
        urlparams: {
            item: 'timesteps',
            layerName: params.layerName,
            day: params.day
        },
        onSuccess: function(timesteps) {
            params.callback(timesteps.timesteps);
        }
    });
}

/**
 * Gets the min and max values of the layer for the given time, depth and
 * spatial extent (used by the auto-scale function).  ncWMS layers only.
 * @param Object containing parameters, which must include:
 *        callback the function to be called with the object that is returned
 *            from the call to the server (simple object with properties "min" and "max")
 *        layerName The unique ID for the displayable layer
 *        bbox Bounding box *string* (e.g. "-180,-90,180,90")
 *        elevation Elevation value
 *        time Time value
 */
function getMinMax(url, params) {
    this.makeAjaxRequest(url, {
        urlparams: {
            item: 'minmax',
            layers: params.layerName,
            bbox: params.bbox,
            elevation: params.elevation,
            time: params.time,
            crs: 'CRS:84', // TODO: should this be fixed like this?
            width: 50, // Request only a small box to save extracting lots of data
            height: 50
        },
        onSuccess: params.callback
    });
}

function getObsDetails(url, params)
{   
    this.makeObsAjaxRequest(url, {
        urlparams: {
            item: 'obsDetails',
            layers: params.layerName,
            bbox: params.bbox,
            crs: 'CRS:84',
            width: params.width,
            height: params.height,
            day: params.day
        },
        onSuccess: params.callback
    });
}

function getObsList(url, params)
{   
    this.makeObsAjaxRequest(url, {
        urlparams: {
            item: 'obsList',
            layers: params.layerName,
            bbox: params.bbox,
            crs: 'CRS:84',
            width: params.width,
            height: params.height,
            day: params.day,
            ndays: params.ndays
        },
        onSuccess: params.callback
    });
}
    
    function getObsValues(url, params)
{   
    this.makeObsAjaxRequest(url, {
        urlparams: {
            item: 'obsValues',
            layers: params.layerName,
            bbox: params.bbox,
            crs: 'CRS:84',
            width: params.width,
            height: params.height,
            day: params.day,
            id: params.id,
            ndays: params.ndays
        },
        onSuccess: params.callback
    });
}

