var next_ajax_obj_index = 0;
var ajax_obj_registry = new Array();

function getAJAXObject() {
  var xmlhttp;
  /*@cc_on
  @if (@_jscript_version >= 5)
    try {
      xmlhttp = new ActiveXObject('Msxml2.XMLHTTP');
    } catch (e) {
      try {
        xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');
      } catch (E) {
        xmlhttp = false;
      }
    }
  @else
    xmlhttp = false;
  @end @*/
 
  if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
    try {
      xmlhttp = new XMLHttpRequest();
    } catch (e) {
      xmlhttp = false;
    }
  }
  
  return xmlhttp;
}

// creates a new ajax object, puts it in the registry, and returns the index to get it back out
function new_ajax_obj() {
  var ajax_obj_index = next_ajax_obj_index++;

  var ajax_obj = getAJAXObject();

  ajax_obj_registry[ajax_obj_index] = {
    'callback'      : null,
    'response_obj'  : null,
    'ajax_obj'      : ajax_obj
  }

  // to handle responses from each ajax object uniquely, each must have a custom handler
  // this custom handler in turn calls the global handler with the correct index
  eval('ajax_handler_router_' + ajax_obj_index + ' = function() { ajax_global_response_handler(' + ajax_obj_index + ') }');

  return ajax_obj_index;
}

// all responses eventually end up here
function ajax_global_response_handler(ajax_obj_index) {
    // retrieve the ajax object that initiated the call
    var ajax_obj = ajax_obj_registry[ajax_obj_index]['ajax_obj'];

    // continue only if we're ready
    if (ajax_obj.readyState == 4) {
        // get the name of the function stub initially used to start the call to the server
        var callback = ajax_obj_registry[ajax_obj_index]['callback'];

        // get the string id of the object we will write the response text to
        if(ajax_obj_registry[ajax_obj_index]['response_obj']) {
            var response_obj = document.getElementById(ajax_obj_registry[ajax_obj_index]['response_obj']);
            if (response_obj && response_obj.innerHTML) {
                response_obj.innerHTML = ajax_obj.responseText;
            }
        }

        // if there is a custom response handler defined, call it
        // we need to eval the callback variable
        if (typeof(eval(callback)) == 'function') {
            eval(callback + '(ajax_obj.responseText);');
        }
    }
}

// creates a url containing all info needed for the server to make the desired call
function ajax_get_url() {
    var ajax_params = new ParamString('?');
  
    ajax_params.ajax = arguments[0];
  
    ajax_params.ajax_args = new Array();
    for (var i = 1; i < arguments.length; i++) {
        ajax_params.ajax_args[i - 1] = arguments[i];
    }

    return ajax_params.toString();
}

// parses the server response into smaller pieces
function ajax_parse_response(response) {
    var first_char, last_char;
    var returnval = new Array();

    first_char = 0;
    last_char = response.indexOf('\n', first_char);
    returnval['status'] = response.substring(first_char, last_char);

    first_char = last_char + 1;
    last_char = response.indexOf('\n', first_char);
    returnval['message'] = response.substring(first_char, last_char);

    first_char = last_char + 1;
    returnval['content'] = response.substring(first_char);

    return returnval;
}

// ajax_call parameters:
// DEPRECATED!! Use call_ajax
// 1 - ajax function name
// 2 - callback_function, 'return', null
// 3+ - parameters to 1
function ajax_call() {
    var parameter_list = '';

    for (var i = 2; i < arguments.length; i++) {
        parameter_list += ', arguments[' + i + ']';
    }
  
    eval('var data = ajax_get_url(arguments[0]' + parameter_list + ');');
    
    var response = ajax_send(location.pathname, 'POST', data, arguments[1]);

    if (response) {
        var response = ajax_parse_response(response);
        eval('var response = ' + response['content'] + ';');
    }

    return response;
}

// ajax_send parameters:
// 1 - url. in the case of 'GET' calls, may include query string or data can be separate
// 2 - method ('POST' or 'GET')
// 3 - data, formatted as a query string (with or without leading '?'), to be passed to given url
// 4 - callback_function, 'return', or null (default null)
// 5 - response_obj (string id) - unless null, response will be written to response_obj.innerHTML
function ajax_send(url, method, data, callback, response_obj) {
    method = typeof(method) == 'undefined' ? 'GET' : method.toUpperCase();
    data = typeof(data) == 'undefined' ? '' : data;
    callback = typeof(callback) == 'undefined' ? null : callback;
    response_obj = typeof(response_obj) == 'undefined' ? null : response_obj;
  
    // create a new ajax object for handling request/response
    var ajax_obj_index = new_ajax_obj();
    var ajax_obj = ajax_obj_registry[ajax_obj_index]['ajax_obj'];
  
    // if we successfully created the object
    if (ajax_obj) {
        if (callback && callback != 'return') {
            // store the function to eventually handle the response
            ajax_obj_registry[ajax_obj_index]['callback'] = callback;
        }

        if (response_obj) {
            // store the string id of the object to eventually write the response text to
            ajax_obj_registry[ajax_obj_index]['response_obj'] = response_obj;
        }

        // determine which unique handler will be used
        eval('ajax_obj.onreadystatechange = ajax_handler_router_' + ajax_obj_index + ';');

        // make sure the data string does not begin with a question mark
        if (data.charAt(0) == '?') {
            data = data.slice(1);
        }

        // do the call to the server, using the correct method
        if (method == 'POST') {
            ajax_obj.open('POST', url, callback != 'return');
            ajax_obj.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
            ajax_obj.setRequestHeader('Content-length', data.length);
            ajax_obj.setRequestHeader('Connection', 'close');
            ajax_obj.send(data);
        }
        else{
            // if there is no query string but there is passed data, append the data to the url
            if (url.indexOf('?') == -1 && data.length) {
                url += '?' + data;
            }

            ajax_obj.open('GET', url, callback != 'return');
            ajax_obj.send(null);
        }

        // return the response directly if the callback function is the string literal 'return'
        if (callback == 'return') {
            return ajax_obj.responseText;
        }
    }
}

// CodeBase specific wrapper for ajax_send
// url - a url or the name of a registered codebase command. if all alphanumerics and underscores,
//    it's assumed to be a codebase command, otherwise it's treated as a url.
// data - a keyed hash of parameters to be sent or a url query string
// options (optional) - a keyed hash with any/all of the following:
// options may also be a string, in which case it is interpreted as the below callback option
//    url - url to be called (defaults to current location.pathname)
//    method - GET or POST (defaults to get)
//    callback - either the name of a javascript function the name of an object in the DOM preceded with a '#'
//    response_obj -  the name of an object in the DOM
function call_ajax(url, data, options) {

  if (typeof(data) == 'undefined') { data = []; }

  if (url.search(/^[0-9a-zA-Z_]+$/) == 0) {
    data['command'] = url;
    url = location.pathname;
  }
  
  if (typeof(data) != 'string') {
    var query_string = new ParamString('?');
    for (var i in data) { query_string[i] = data[i]; }
    data = query_string.toString();
  }

  if(typeof(options) == 'string') { options = { 'callback': options }; }
  if(typeof(options) == 'undefined') { options = []; }

  // default options
  default_options = {
    'method': 'GET',
    'callback': null,
    'response_obj': null
  };

  method = options['method'] == 'POST' ? 'POST' : default_options['method'];

  if(typeof(options['callback']) != 'undefined') {
    if(typeof(options['response_obj']) == 'undefined' && options['callback'].indexOf('#') == 0) {
      options['response_obj'] = options['callback'].substr(1);
      callback = null;
    }
    else {
      callback = options['callback'] ? options['callback'] : default_options['callback'];
    }
  }
  else {
    callback = default_options['callback'];
  }

  response_obj = typeof(options['response_obj']) == 'undefined' ? null : options['response_obj'];

/*
  alert(
    'url: ' + url + '\n' +
    'method: ' + method + '\n' +
    'data: ' + data + '\n' +
    'callback: ' + callback + '\n' +
    'response_obj: ' + response_obj
  );
//*/
  var response = ajax_send(url, method, data, callback, response_obj);

  if (response) {
      var response = ajax_parse_response(response);
      eval('var response = ' + response['content'] + ';');
  }

  return response;
}
