/******* AJAX CLASS *******/
if (typeof Node == 'undefined') { //IE hack
  Node = function() {};
  Node.ELEMENT_NODE = 1;
  Node.ATTRIBUTE_NODE = 2;
  Node.TEXT_NODE = 3;
  Node.CDATA_SECTION_NODE = 4;
  Node.ENTITY_REFERENCE_NODE = 5;
  Node.ENTITY_NODE = 6;
  Node.PROCESSING_INSTRUCTION_NODE = 7;
  Node.COMMENT_NODE = 8;
  Node.DOCUMENT_NODE = 9;
  Node.DOCUMENT_TYPE_NODE = 10;
  Node.DOCUMENT_FRAGMENT_NODE = 11;
  Node.NOTATION_NODE = 12;
}

  var Ajax = function (args) {
  //this.args_default = function(arg, def) { eval('this.'+arg) = typeof args[arg]=='undefined' ? def : args[arg]; };
  function args_default(arg,def) { /*alert(arg+'|'+args[arg]);*/ return typeof args!='undefined' && typeof args[arg]!='undefined' ? args[arg] : def; };
  //function from_args(arg) { if (typeof args!='undefined' && typeof args[arg]!='undefined') eval('this.'+arg) = args[arg]; };

  /* member variables: */
  this.xmlhttp	       = args_default('xmlhttp',null);
  this.xmlparser       = args_default('xmlparser',null);
  this.xmlparser_bw    = args_default('xmlparser_bw',0);
  this.request_uri     = args_default('request_uri','');
  this.request_method  = args_default('request_method',Ajax.GET);
  this.response_format = args_default('response_format',Ajax.XML);
  this.custom_callback = args_default('custom_callback',null);
  this.notify_sucess   = args_default('notify_sucess',Ajax.NOTIFY_HLFI);
  this.notify_error    = args_default('notify_error',Ajax.NOTIFY_HTML_ALERT);

  this.startElement    = args_default('startElement',function (node) {});
  this.endElement      = args_default('endElement',function (node) {});
  this.documentStart   = args_default('documentStart',function () {});
  this.documentEnd     = args_default('documentEnd',function () {});
  this.textElement     = args_default('textElement',function (txt) {});

  this._init();
}

/* CONSTANTS: */
Ajax.GET  = "GET";
Ajax.POST = "POST";

Ajax.TEXT = 1;
Ajax.XML  = 2;

Ajax.STATE_UNINITIALIZED = 0;
Ajax.STATE_LOADING	 = 1;
Ajax.STATE_LOADED	 = 2;
Ajax.STATE_INTERACTIVE	 = 3;
Ajax.STATE_COMPLETE	 = 4;

Ajax.NOTIFY_JS_ALERT   = 1; //alert boks in js
Ajax.NOTIFY_HTML_ALERT = 2; //alert boks in html
Ajax.NOTIFY_HLFI       = 3; //highlight + fade + icon
Ajax.NOTIFY_HLF        = 4; //highlight + fade
Ajax.NOTIFY_HL         = 5; //highlight

Ajax.BROWSER_IE  = 1;
Ajax.BROWSER_MOZ = 2;

/* STATIC FUNCTIONS: */
Ajax.get_left_pos = function (elem) {
  var x = 0;
  do {
    x += elem.offsetLeft;
  } while ((elem = elem.offsetParent));
  return x;
}

Ajax.get_top_pos = function (elem) {
  var y = 0;
  do {
    y += elem.offsetTop;
  } while ((elem = elem.offsetParent));
  return y;
}


/* OBJECT FUNCTIONS: */
Ajax.prototype._init = function() {
  if (this.xmlhttp) return;
  this.xmlhttp = null;
  // branch for IE/Windows ActiveX version
  /*@cc_on
  @if (@_jscript_version >= 5)
    try {
      this.xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {
      try {
	this.xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
      } catch (e2) {
	this.xmlhttp = false;
      }
    }
  @else
    this.xmlhttp = false;
  @end @*/
  // branch for native XMLHttpRequest object
  if (!this.xmlhttp && typeof XMLHttpRequest != 'undefined') {
    try {
      this.xmlhttp = new XMLHttpRequest();
      if (typeof this.xmlhttp.overrideMimeType == 'function')
	this.xmlhttp.overrideMimeType("text/xml");
    } catch (e) {
      this.xmlhttp = false;
    }
  }
}

Ajax.prototype.send_request = function(action,count,args) {
  if (this.xmlhttp && this.request_uri) {
    if (!this.validate()) return false; //FIX: error handling
    var me = this;
    var post = null;
    var arg = this.prepare_arg(action,count,args);
    var uri = this.prepare_uri(arg);
    //alert(uri + '|'+this.request_method);
    this.xmlhttp.open(this.request_method, uri, true);
    //this.xmlhttp.onreadystatechange = this.request_callback;
    this.xmlhttp.onreadystatechange = function() {
      switch (me.xmlhttp.readyState) {
	case Ajax.STATE_UNINITIALIZED:
	case Ajax.STATE_LOADING:
	case Ajax.STATE_LOADED:
	case Ajax.STATE_INTERACTIVE:
	//xmlhttp.readyState;
	break;
	case Ajax.STATE_COMPLETE:
	if (me.xmlhttp.status == 200) {
	  var res = '';
	  switch (me.response_format) {
	  case Ajax.TEXT:
	    res = me.xmlhttp.responseText;
	    break;
	  case Ajax.XML:
	    if (me.xmlhttp.getResponseHeader('Content-Type').indexOf('text/xml')==-1) {
	      alert('Server did not return data in XML format, using text');
	      res = me.xmlhttp.responseText;
	    } else
	      res = me.xmlhttp.responseXML;
	    break;
	  default:
	    alert("Error: invalid response_format " + me.response_format);
	    return false;
	  }
	  if (typeof me.custom_callback == 'function')
	    me.custom_callback(res);
	} else {
	  alert("There was a problem retrieving the XML data:\n" +
		me.xmlhttp.status + ": " + me.xmlhttp.statusText);
	}
	break;
	default:
	alert("Error: invalid readyState " + me.xmlhttp.readyState);
	return false;
      }
      return true;
    };
    //alert(this.request_method + '|' + this.prepare_post(arg));
    this.xmlhttp.send(this.prepare_post(arg));
  }
  return true;
}

Ajax.prototype.validate = function() {
  if (this.request_method == Ajax.POST &&
      typeof this.xmlhttp.setRequestHeader == 'undefined') {
    this.request_method = Ajax.GET;
  }
  return true;
}

Ajax.prototype.prepare_arg = function(action,count,args) {
  var arg_str = '';
  if (this.request_method == Ajax.GET) arg_str += '?';
  arg_str += 'action_performed='+action+'&action_count='+count+'&rnd='+new Date().getTime();
  if (args)
    for (var i=0; i<args.length; i++)
      arg_str += '&'+args[i]['key']+'='+args[i]['val'];//FIX
  return arg_str;
}

Ajax.prototype.prepare_uri = function(arg_str) {
  var uri = this.request_uri;
  if (this.request_method == Ajax.GET) uri += arg_str;
  return uri;
}

Ajax.prototype.prepare_post = function(arg_str) {
  var post = null;
  if (this.request_method == Ajax.POST) {
    this.xmlhttp.setRequestHeader("Method", "POST " + this.request_uri + " HTTP/1.1");
    this.xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    post = arg_str;
  }
  return post;
}

//Ajax.prototype.request_callback = function() {
//  switch (this.xmlhttp.readyState) {
//    case Ajax.STATE_UNINITIALIZED:
//    case Ajax.STATE_LOADING:
//    case Ajax.STATE_LOADED:
//    case Ajax.STATE_INTERACTIVE:
//    //xmlhttp.readyState;
//    break;
//    case Ajax.STATE_COMPLETE:
//    if (this.xmlhttp.status == 200) {
//      var res = '';
//      switch (this.response_format) {
//      case Ajax.TEXT:
//	res = this.xmlhttp.responseText;
//	break;
//      case Ajax.XML:
//	res = this.xmlhttp.responseXml;
//	break;
//      default:
//	alert("Error: invalid response_format " + this.response_format);
//	return;
//      }
//      if (typeof this.custom_callback == 'function')// or object??
//	this.custom_callback(res);
//    } else {
//      alert("There was a problem retrieving the XML data:\n" +
//	    this.xmlhttp.status + ": " + this.xmlhttp.statusText);
//    }
//    break;
//    default:
//    alert("Error: invalid readyState " + this.xmlhttp.readyState);
//    return;
//  }
//}

Ajax.prototype.register_callback = function(func) {
  if (typeof func == 'function')
    this.custom_callback = func;
}

Ajax.prototype.unregister_callback = function() {
  this.custom_callback = null;
}


Ajax.prototype._initXML = function() {
  if (this.xmlparser) return;
  this.xmlparser = null;
  this.xmlparser_bw = 0;
  // branch for IE/Windows ActiveX version
  /*@cc_on
  @if (@_jscript_version >= 5)
    try {
      this.xmlparser = new ActiveXObject("Msxml2.XMLDOM");
      this.xmlparser_bw = Ajax.BROWSER_IE;
    } catch (e) {
      try {
	this.xmlparser = new ActiveXObject("Microsoft.XMLDOM");
	this.xmlparser_bw = Ajax.BROWSER_IE;
      } catch (e2) {
	this.xmlparser = false;
      }
    }
  @else
    this.xmlparser = false;
  @end @*/
  // branch for native XML Parser object
  if (!this.xmlparser && typeof document.implementation != 'undefined') {
    try {
      this.xmlparser = document.implementation.createDocument("ns","root",null);//FIX
      this.xmlparser_bw = Ajax.BROWSER_MOZ;
    } catch (e) {
      this.xmlparser = false;
    }
  }
}

Ajax.prototype.parseXML = function(node) {
  //this._initXML();
  //switch (this.xmlparser_bw) {
  //case Ajax.BROWSER_IE:
  //  this.xmlparser.async="false";
  //  while(this.xmlparser.readyState!=4) document.write('Loading...');
  //  this.xmlparser.loadXML(xml);
  //  break;
  //case Ajax.BROWSER_MOZ:
  //  this.xmlparser.load(xml);
  //  break;
  //default:
  //}
  //
  //var items = this.xmlparser.documentElement;
  //for (node in items) { //this.xmlparser.documentElement.childNodes
  //  //alert(node);//FIX
  //  document.write(node+'<br>');
  //}

  var i = 0;
  //document.getElementById('debug').innerHTML += 'node='+node+'<br/>';
  if (node) {
    switch (node.nodeType) {
    case Node.ELEMENT_NODE:
      if (typeof this.startElement == 'function')
	this.startElement(node);
      if (node.childNodes && node.childNodes.length) {
	for (i=0; i<node.childNodes.length; i++) {
	  this.parseXML(node.childNodes[i]);
	}
      }
      if (typeof this.endElement == 'function')
	this.endElement(node);
      break;
    case Node.TEXT_NODE:
      if (typeof this.textElement == 'function')
	this.textElement(node.data);
      break;
    case Node.ATTRIBUTE_NODE:
      break;
    case Node.DOCUMENT_NODE:
      if (typeof this.documentStart == 'function')
	this.documentStart();
      if (node.childNodes && node.childNodes.length) {
	for (i=0; i<node.childNodes.length; i++) {
	  this.parseXML(node.childNodes[i]);
	}
      }
      if (typeof this.documentEnd == 'function')
	this.documentEnd();
      break;
    }
  }
}

//Ajax.prototype.setDocumentHandler = function(fun) {
//  this.documentHandler = fun;
//}
//
//Ajax.prototype.setLexicalHandler = function(fun) {
//  this.lexicalHandler = fun;
//}
//
//Ajax.prototype.setAttributeHandler = function(fun) {
//  this.attributeHandler = fun;
//}


Ajax.prototype.set_startElementHandler = function(fun) {
  this.startElement = fun;
}
Ajax.prototype.set_endElementHandler = function(fun) {
  this.endElement = fun;
}
Ajax.prototype.set_documentStartHandler = function(fun) {
  this.documentStart = fun;
}
Ajax.prototype.set_documentEndHandler = function(fun) {
  this.documentEnd = fun;
}
Ajax.prototype.set_textElementHandler = function(fun) {
  this.textElement = fun;
}






/******* HACK for old Opera browser *******/

if (window.opera && !window.XMLHttpRequest) {

/*

Cross-Browser XMLHttpRequest v1.2
=================================

Emulate Gecko 'XMLHttpRequest()' functionality in IE and Opera. Opera requires
the Sun Java Runtime Environment <http://www.java.com/>.

by Andrew Gregory
http://www.scss.com.au/family/andrew/webdesign/xmlhttprequest/

This work is licensed under the Creative Commons Attribution License. To view a
copy of this license, visit http://creativecommons.org/licenses/by/1.0/ or send
a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305,
USA.

Not Supported in Opera
----------------------
* user/password authentication
* responseXML data member

Not Fully Supported in Opera
----------------------------
* async requests
* abort()
* getAllResponseHeaders(), getAllResponseHeader(header)

*/

// Opera support
window.XMLHttpRequest = function() {
    this.readyState = 0; // 0=uninitialized,1=loading,2=loaded,3=interactive,4=complete
    this.status = 0; // HTTP status codes
    this.statusText = '';
    this._headers = [];
    this._aborted = false;
    this._async = true;
    this._defaultCharset = 'ISO-8859-1';
    this._getCharset = function() {
      var charset = this._defaultCharset;
      var contentType = this.getResponseHeader('Content-type').toUpperCase();
      val = contentType.indexOf('CHARSET=');
      if (val != -1) {
	charset = contentType.substring(val);
      }
      val = charset.indexOf(';');
      if (val != -1) {
	charset = charset.substring(0, val);
      }
      val = charset.indexOf(',');
      if (val != -1) {
	charset = charset.substring(0, val);
      }
      return charset;
    };
    this.abort = function() {
      this._aborted = true;
    };
    this.getAllResponseHeaders = function() {
      return this.getAllResponseHeader('*');
    };
    this.getAllResponseHeader = function(header) {
      var ret = '';
      for (var i = 0; i < this._headers.length; i++) {
	if (header == '*' || this._headers[i].h == header) {
	  ret += this._headers[i].h + ': ' + this._headers[i].v + '\n';
	}
      }
      return ret;
    };
    this.getResponseHeader = function(header) {
      var ret = this.getAllResponseHeader(header);
      var i = ret.indexOf('\n');
      if (i != -1) {
	ret = ret.substring(0, i);
      }
      return ret;
    };
    this.setRequestHeader = function(header, value) {
      this._headers[this._headers.length] = {h:header, v:value};
    };
    this.open = function(method, url, async, user, password) {
      this.method = method;
      this.url = url;
      this._async = true;
      this._aborted = false;
      this._headers = [];
      if (arguments.length >= 3) {
	this._async = async;
      }
      if (arguments.length > 3) {
	opera.postError('XMLHttpRequest.open() - user/password not supported');
      }
      this.readyState = 1;
      if (this.onreadystatechange) {
	this.onreadystatechange();
      }
    };
    this.send = function(data) {
      if (!navigator.javaEnabled()) {
	alert("XMLHttpRequest.send() - Java must be installed and enabled.");
	return;
      }
      if (this._async) {
	setTimeout(this._sendasync, 0, this, data);
	// this is not really asynchronous and won't execute until the current
	// execution context ends
      } else {
	this._sendsync(data);
      }
    }
    this._sendasync = function(req, data) {
      if (!req._aborted) {
	req._sendsync(data);
      }
    };
    this._sendsync = function(data) {
      this.readyState = 2;
      if (this.onreadystatechange) {
	this.onreadystatechange();
      }
      // open connection
      var url = new java.net.URL(new java.net.URL(window.location.href), this.url);
      var conn = url.openConnection();
      for (var i = 0; i < this._headers.length; i++) {
	conn.setRequestProperty(this._headers[i].h, this._headers[i].v);
      }
      this._headers = [];
      if (this.method == 'POST') {
	// POST data
	conn.setDoOutput(true);
	var wr = new java.io.OutputStreamWriter(conn.getOutputStream(), this._getCharset());
	wr.write(data);
	wr.flush();
	wr.close();
      }
      // read response headers
      // NOTE: the getHeaderField() methods always return nulls for me :(
      var gotContentEncoding = false;
      var gotContentLength = false;
      var gotContentType = false;
      var gotDate = false;
      var gotExpiration = false;
      var gotLastModified = false;
      for (var k = 0; ; k++) {
	var hdrName = conn.getHeaderFieldKey(k);
	var hdrValue = conn.getHeaderField(k);
	if (hdrName == null && hdrValue == null) {
	  break;
	}
	if (hdrName != null) {
	  this._headers[this._headers.length] = {h:hdrName, v:hdrValue};
	  switch (hdrName.toLowerCase()) {
	    case 'content-encoding': gotContentEncoding = true; break;
	    case 'content-length'  : gotContentLength   = true; break;
	    case 'content-type'    : gotContentType     = true; break;
	    case 'date'            : gotDate            = true; break;
	    case 'expires'         : gotExpiration      = true; break;
	    case 'last-modified'   : gotLastModified    = true; break;
	  }
	}
      }
      // try to fill in any missing header information
      var val;
      val = conn.getContentEncoding();
      if (val != null && !gotContentEncoding) this._headers[this._headers.length] = {h:'Content-encoding', v:val};
      val = conn.getContentLength();
      if (val != -1 && !gotContentLength) this._headers[this._headers.length] = {h:'Content-length', v:val};
      val = conn.getContentType();
      if (val != null && !gotContentType) this._headers[this._headers.length] = {h:'Content-type', v:val};
      val = conn.getDate();
      if (val != 0 && !gotDate) this._headers[this._headers.length] = {h:'Date', v:(new Date(val)).toUTCString()};
      val = conn.getExpiration();
      if (val != 0 && !gotExpiration) this._headers[this._headers.length] = {h:'Expires', v:(new Date(val)).toUTCString()};
      val = conn.getLastModified();
      if (val != 0 && !gotLastModified) this._headers[this._headers.length] = {h:'Last-modified', v:(new Date(val)).toUTCString()};
      // read response data
      var reqdata = '';
      var stream = conn.getInputStream();
      java.lang.System.err.println(stream);
      if (stream) {
	var reader = new java.io.BufferedReader(new java.io.InputStreamReader(stream, this._getCharset()));
	var line;
	while ((line = reader.readLine()) != null) {
	  if (this.readyState == 2) {
	    this.readyState = 3;
	    if (this.onreadystatechange) {
	      this.onreadystatechange();
	    }
	  }
	  reqdata += line + '\n';
	}
	reader.close();
	this.status = 200;
	this.statusText = 'OK';
	this.responseText = reqdata;
	this.readyState = 4;
	if (this.onreadystatechange) {
	  this.onreadystatechange();
	}
	if (this.onload) {
	  this.onload();
	}
      } else {
	// error
	this.status = 404;
	this.statusText = 'Not Found';
	this.responseText = '';
	this.readyState = 4;
	if (this.onreadystatechange) {
	  this.onreadystatechange();
	}
	if (this.onerror) {
	  this.onerror();
	}
      }
    };
  };
}

