function doAjaxCall(func, args, callback, options)
{
    if (!Ajax)
    {
        alert('prototype.js is missing');
        return false;
    }

    var location = document.location;
    var queryString = 'ajax_func='+func;

    for (i=0; i < args.length; i++)
    {
        queryString += '&args[]=' + encodeURIComponent(args[i]);
    }

    if (options != null)
    {
        if(options.location != null && options.location != '')
        {
            location = options.location; 
        }
        if(options.append_request != null && options.append_request != '')
        {
            queryString += '&' + options.append_request;
        }
    }

    var req = new Ajax.Request(location, {
        method: 'post',
        parameters: queryString,
        onComplete: function(req){callback(req.responseText)}
    });
}

function doSjaxCall(func, args, options)
{
    if (!Ajax)
    {
        alert('prototype.js is missing');
        return false;
    }
    
    var location = document.location;
    var queryString = 'ajax_func='+func;

    for (i=0; i < args.length; i++)
    {
        queryString += '&args[]=' + encodeURIComponent(args[i]);
    }

    if (options != null)
    {
        if(options.location != null && options.location != '')
        {
            location = options.location; 
        }
        if(options.append_request != null && options.append_request != '')
        {
            queryString += '&' + options.append_request;
        }
    }

    var req = new Ajax.Request(location, {
        method: 'post',
        parameters: queryString,
        asynchronous: false
    });

    return req.transport.responseText;
}

function getWidget(tag, elements, callback, options)
{
    // if elements is a string, or a lone object, then put it inside an array
    // note: a string is an array too
    if (typeof(elements) != 'object' || undefined == elements.length)
    {
        elements = [elements];
    }

    doAjaxCall('GetWidget', [tag], function(responseText)
    {
        response = getJson(responseText);
        for (e = 0; e < elements.length; e++)
        {
            element = elements[e];
            if (typeof(element) == "string")
            {
                element = document.getElementById(element);
            }
            element.innerHTML = response.content;
        }
        
        if(response.javascript != null && response.javascript != '')
        {
            eval(response.javascript);
        }

        if (callback != null)
        {
            callback(response);
        }
    }, options);
}

function getJson(json)
{
    json = json.replace(/^\n/, '');
    json = json.replace(/\n$/, '');
    json = json.replace(/\n/g, '\\n');
    json = json.replace(/\r/g, '\\n');

    // turn this to true to debug for strange characters in the json
    if (false)
    {
        try
        {
            var debug_start = "{content:'" . length;
            for (i = json.length - "',error:false}".length; i > debug_start; i--)
            {
                if (json.charAt(i) == "'") continue;
                if (json.charAt(i) == "\\") continue;
                json_debug = json.substring(0, debug_start) + '(' + json.charAt(i) + '|' + json.charCodeAt(i) + ')' + json.substring(i, json.length);
                // this will break at the location when a strange character will appear
                // the number in parenthesis will tell you what character it is
                eval('var obj = ' + json_debug + ';');
            }
        }
        catch(e)
        {
            prompt('Error while evaluating JSON: ' + e.message, json_debug);
        }
    }
    else
    {
        try
        {
            eval('var obj = ' + json + ';');
        }
        catch(e)
        {
            alert('error while evaluating JSON: ' + e.message + '\n\n' + json);
        }
    }

    return obj;
}


var DELAYGETWIDGET_PARAMS = new Array();


/*
This is similar to getWidget, except it waits a few milliseconds before making 
the ajax call. It waits to see if another request for the same id is called 
within the time frame, usually to see if the same widget is requested again. 
This is mainly used for when we want to update a widget as users click on form 
inputs, but only want to make server requests if there is enough delay in the
clicking.

The default callback function is delayGetWidget_done().   If another callback 
function is passed in, then make sure that custom callback function closes the 
progressbar_default bar.  By default, the progressbar will be displayed after 
the delay.
*/
function delayGetWidget(delay, id, tag, elements, callback, options)
{
    var now = new Date();
    if(DELAYGETWIDGET_PARAMS[id] == null)
    {
        DELAYGETWIDGET_PARAMS[id] = new Array();
    }
    DELAYGETWIDGET_PARAMS[id].clicktime = now.getTime();
    DELAYGETWIDGET_PARAMS[id].tag = tag;
    DELAYGETWIDGET_PARAMS[id].elements = elements;
    DELAYGETWIDGET_PARAMS[id].callback = callback;
    DELAYGETWIDGET_PARAMS[id].options = options;
    DELAYGETWIDGET_PARAMS[id].progressbar = (options.noprogressbar == null || options.noprogressbar == false ? true : false);
    delayGetWidget_test(delay, id);
}

function delayGetWidget_test(delay, id)
{
  if (DELAYGETWIDGET_PARAMS[id] == null)
  {
    alert('ID not defined for delayGetWidget_test():' + id);
    return false;
  }

  // ignore previous calls
  if (DELAYGETWIDGET_PARAMS[id].timerid)
  {
    clearTimeout(DELAYGETWIDGET_PARAMS[id].timerid);
    DELAYGETWIDGET_PARAMS[id].timerid = null;
  }

  var now = new Date();
  
  // if more than delayed milliseconds since last request, then handle request
  if (delay == null || delay == 0 || now.getTime() > DELAYGETWIDGET_PARAMS[id].clicktime + delay)
  {
    delayGetWidget_activate(delay, id);
  }
  // otherwise, wait another delay # of milliseconds to see if another request comes in
  else
  {
    DELAYGETWIDGET_PARAMS[id].timerid = 
        setTimeout("delayGetWidget_test(" + delay + ", '" + id + "')", delay + 100);
  }
}


// @see delayGetWidget() for information about the callback function.
function delayGetWidget_activate(delay, id)
{
    if (DELAYGETWIDGET_PARAMS[id].progressbar == true && progressbar_default != null)
    {
        progressbar_default.setCaption('Loading...');
        progressbar_default.centerFocus();
        progressbar_default.showBar();
        progressbar_default.start();
    }

    if(DELAYGETWIDGET_PARAMS[id].callback == null || DELAYGETWIDGET_PARAMS[id].callback == '')
    {
        DELAYGETWIDGET_PARAMS[id].callback = delayGetWidget_done;
    }

    getWidget(DELAYGETWIDGET_PARAMS[id].tag, DELAYGETWIDGET_PARAMS[id].elements, DELAYGETWIDGET_PARAMS[id].callback, DELAYGETWIDGET_PARAMS[id].options);
}


function delayGetWidget_done(response)
{
    if (progressbar_default != null)
    {
        progressbar_default.stop();
        progressbar_default.hideBar();
    }
}
