var msie = false;
if (navigator.userAgent.match ('MSIE') !== null) msie = true;

var DELAY = 100;

// request types
var TYPE_OVERWRITE_NODE = 0;        ///< Overwrite a node
var TYPE_CHECK_LOGIN = 1;           ///< Check login (remove?)
var TYPE_CACHE_TABLE_COLUMNS = 2;   ///< Cached table column lookup (sql.php)

var http_response_code = new Array ();
http_response_code[404] = 'page not found';

var queue = new Queue;


function Queue () {
  this.request_queue = new Array ();
  this.requester_active = false;
  this.created = true;
  this.loading_node = document.getElementById ('loading');
  
  
  this.request = function (method, url, action, post_data, options) {
    this.request_queue.push (new Request (method, url, action, post_data, options));
    this.activate ();
  }
  
  
  this.activate = function () {
    if (this.requester_active != true && this.request_queue.length > 0) {
      this.requester_active = true;
      
      if (this.loading_node != null) {
        this.loading_node.innerHTML = 'Loading...';
      }
      
      this.request_queue[this.request_queue.length - 1].send ();
      
      window.setTimeout ('queue.process ();', DELAY);
      
    } else if (this.request_queue.length == 0) {

      if (this.loading_node != null) {
        this.loading_node.innerHTML = '';
      }
    }
  }
  
  this.process = function () {
    if (this.request_queue.length > 0) {
      
      // process request from FIFO buffer
      var first_request = this.request_queue[0];
      if (first_request.ready_state () == 4) {
        if (first_request.status () == 200) {
          
          // process response
          first_request.process ();
          
        } else if (first_request.status () != 0) {
          var ajax_error = 'AJAX call to ' + first_request.url + ' returned server error:\n' +
            first_request.status ();
          if (http_response_code[first_request.status ()]) {
            ajax_error += ' (' + http_response_code[first_request.status ()] + ')';
          }
          alert (ajax_error);
        }
        
        // remove item from queue
        this.request_queue.shift ();
        
        this.requester_active = false;
        this.activate ();
        
      } else {
        // keep waiting
        window.setTimeout ('queue.process ();', DELAY);
      }
    }
  }
}

function Request (method, url, action, post_data, options) {
  this.url = url;
  this.action = action;
  this.method = method.toUpperCase ();
  this.requester = null;
  this.internet_explorer = false;
  this.node_id = null;
  this.post_data = post_data;
  
  switch (this.action) {
    case TYPE_OVERWRITE_NODE:
      this.node_id = options['node'];
      break;
  }
  
  
  this.ready_state = function () {
    if (this.requester == null) {
      return -1;
    } else {
      return this.requester.readyState;
    }
  }
  
  this.status = function () {
    if (this.requester == null) {
      return -1;
    } else {
      return this.requester.status;
    }
  }
  
  this.send = function () {
    // try Moz/Safari method, then IE
    if (window.XMLHttpRequest) {
      this.requester = new XMLHttpRequest ();
    } else if (this.requester = new ActiveXObject("MSXML2.XMLHTTP.3.0")) {
      this.internet_explorer = true;
    }
    
    if (this.requester != null) {
      this.requester.open(method, url, true);
      if (this.method == 'POST') {
        this.requester.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
      }
      this.requester.send(this.post_data);
    } else {
      alert ('Your browser does not appear to support AJAX');
    }
  }
  
  this.process = function () {
    if (this.requester != null) {
      // check for errors
      var top_node = false;
      
      // skip any comments, whitespace, etc. and find the first real XML node
      var top_children = this.requester.responseXML.childNodes;
      var curr_child_num = 0;
      var curr_child = null;
      while (!top_node) {
        if (top_children.length <= curr_child_num) {
          break;
        }
        curr_child = top_children.item (curr_child_num);
        if (curr_child.nodeType == 1) {
          top_node = curr_child;
        } else {
          curr_child_num++;
        }
      }
      
      if (!top_node) {
        alert ('Invalid XML returned via AJAX, please contact the web site administrator');
        return false;
      }
      
      if (top_node.nodeName.toLowerCase () == 'error') {
        alert (top_node.firstChild.data);
      } else {
        
        // New mechanism -- use handler if provided
        if (typeof (this.action) == 'object') {
          this.action.process (top_node);
          return;
        } else {
          
          /**
          * LEGACY - SHOULD NOT BE HERE
          **/
          switch (this.action) {
            case TYPE_OVERWRITE_NODE:
              //alert ('XML nodes returned:' + top_node.xml);
              var curr_child;
              if (this.internet_explorer) {
                var target_node = document.getElementById (this.node_id);
                
                var span_node = document.createElement ('span');
                span_node.innerHTML = top_node.xml;
                
                //alert ('Span: ' + span_node.innerHTML);
                
                target_node.parentNode.replaceChild (span_node.firstChild, target_node);
                
                                
              } else {
                /*
                This is rubbish, should be able to import from AJAX, i.e.
                var dom_node = document.importNode (top_node, true);
                */
                var dom_node = returned_node_to_dom (top_node, null, null, false);
                
                // alert (view_dom_tree (dom_node));
                var target_node = document.getElementById (this.node_id);
                // target_node.removeAttribute ('id');
                
                target_node.parentNode.replaceChild (dom_node, target_node);
                
                // overcome firefox bug where select list with selected elements are not selected
                if (dom_node.parentNode) {
                  var select_nodes = dom_node.parentNode.getElementsByTagName ('select');
                  var curr_select;
                  var curr_opt;
                  var curr_attr;
                  for (var select_count = 0; select_count < select_nodes.length; select_count++) {
                    curr_select = select_nodes.item (select_count);
                    for (var opt_count = 0; opt_count < curr_select.childNodes.length; opt_count++) {
                      curr_opt = curr_select.childNodes.item (opt_count);
                      if (curr_opt.nodeType == 1 && curr_opt.nodeName == 'OPTION') {
                        for (var attr_count = 0; attr_count < curr_opt.attributes.length; attr_count++) {
                          curr_attr = curr_opt.attributes.item (attr_count);
                          if (curr_attr.name == 'selected') {
                            curr_select.value = curr_opt.value;
                          }
                        }
                      }
                    }
                  }
                }
                
              }
              break;
            // provide processing for other actions here
              
            case TYPE_CHECK_LOGIN:
              var log_in_div = document.getElementById ('logged_in');
              if (log_in_div && log_in_div.firstChild) {
                // mark as logged in or out
                if (top_node.nodeName.toLowerCase () == 'ok') {
                  log_in_div.replaceChild (document.createTextNode (' :)'), log_in_div.firstChild);
                  log_in_div.style.color = '#00FF00';
                } else {
                  log_in_div.replaceChild (document.createTextNode (' :('), log_in_div.firstChild);
                  log_in_div.style.color = '#FF0000';
                  clearTimeout (keep_alive_timer);
                }
              }
              break;
            
            case TYPE_CACHE_TABLE_COLUMNS:
              table = [];
              
              // table name is in position 0
              tablename = top_node.getAttribute('name');
              table.push(tablename);
              
              // columns
              if (top_node.hasChildNodes()) {
                var children = top_node.childNodes;
                for (var i = 0; i < children.length; i++) {
                  item = new Object;
                  item.name = children.item(i).getAttribute('name');
                  item.type = children.item(i).getAttribute('type');
                  item.index = children.item(i).getAttribute('index');
                  table.push(item);
                };
              };
   
              // add to cache
              table_columns.push(table);
              
              // get sql.php to re-read the cache
              table_in_cache();
              break;
              
            default:
              alert ('Invalid AJAX query type: ' + this.action);
          }
          /**
          * END LEGACY STUFF
          **/
        }
        
      }
    } else {
      alert ('Request.function called on null requester');
    }
  }
}

function update_select_lists (top_node) {
  var select_nodes = top_node.getElementsByTagName ('select');
  var select_node;
  var option_nodes;
  var option_node;
  
  for (var i = 0; i < select_nodes.length; i++) {
    select_node = select_nodes.item (i);
    option_nodes = select_node.childNodes;
    for (var j = 0; j < option_nodes.length; j++) {
      option_node = option_nodes.item (j);
      if (option_node.nodeName && option_node.nodeName.toUpperCase () == 'OPTION') {
        if (option_node.getAttribute ('selected') != null) {
          select_node.value = option_node.value;
          break;
        }
      }
    }
  }
}

function determine_radio_value (radio_el) {
  
  for (var i in radio_el) {
    if (radio_el[i].checked == true) {
      return radio_el[i].value;
    }
  }
  
  return false;
}


function create_el (name, attrs) {
  
  var node;
  
  if (!msie) {
    node = document.createElement (name);
    if (node && typeof (attrs) == 'object') {
      for (var attr in attrs) {
        node.setAttribute (attr, attrs[attr]);
      }
    }
  } else {
    var attrs_str = '';
    if (typeof (attrs) == 'object') {
      for (var attr in attrs) {
        attrs_str += ' ' + attr + '="' + String (attrs[attr]).replace ('"', '\\"') + '"';
      }
    }
    node = document.createElement ('<' + name + ' ' + attrs_str + '>');
  }
  
  return node;
}

/* makes labels (and corresponding inputs) highlight when you rollover them */
function nice_label (current_label, input_parent) {
  current_label.className = 'label_plain';
  current_label.onmouseover = function () {
    current_label.className = 'label_highlight';
    if (input_parent) {
      input_parent.className = 'label_highlight';
    }
  }
  current_label.onmouseout = function () {
    current_label.className = 'label_plain';
    if (input_parent) {
      input_parent.className = 'label_plain';
    }
  }
  
  if (input_parent) {
    input_parent.onmouseover = function () {
      current_label.className = 'label_highlight';
      input_parent.className = 'label_highlight';
    }
    input_parent.onmouseout = function () {
      current_label.className = 'label_plain';
      input_parent.className = 'label_plain';
    }
  }
}

function var_dump (operand, is_sub) {
  
  var alert_text = '';
  var op_type = typeof (operand)
  alert_text += op_type + ':' + (is_sub? ' ': '\n');
  
  if (op_type == 'object') {
    for (var id in operand) {
      if (typeof (operand[id]) == 'function') {
        alert_text += id + ' = function...\n';
      } else {
        alert_text += id + ' = ' + operand[id] + "\n";
      }
    }
  } else {
    alert_text += String (operand);
  }
  
  window.alert (alert_text);
  
}

function returned_node_to_dom (node, so_far, current_node, is_ie) {
  var attr;
  var new_node;
  if (node.tagName) {
    // trace ('Creating node ' + node.tagName);
    new_node = document.createElement (node.tagName);
    if (so_far == null) {
      so_far = new_node;
      current_node = new_node;
    } else {
      current_node.appendChild (new_node);
    }
    
    // attributes
    for (var i = 0; i < node.attributes.length; i++) {
      attr = node.attributes.item (i);
      // trace ('new_node.setAttribute ('+attr.name+', '+attr.value+');');
      if (attr.name == 'class') {
        set_class (new_node, attr.value);
      } else {
        new_node.setAttribute (attr.name, attr.value);
      }
    }
    
    // children (recursive) and further text nodes
    //if (!is_ie) {
      for (var i = 0; i < node.childNodes.length; i++) {
        attr = node.childNodes.item (i);
        if (attr.nodeType == 3) {
          new_node.appendChild (document.createTextNode (attr.data));
        } else {
          so_far = returned_node_to_dom (attr, so_far, new_node, is_ie);
        }
      }
    //}
  }
  return so_far;
}


