// 07/11/04 13:33
//**************************
// Interface of AJAXobject:
// if response hasn't 'Content-Type' in header there must be set 'onready' function, FALSE returned will stop polling
// if response has 'Content-Type: text/xml' in header there must be set 'xmlhandler' function
// if response has 'Content-Type: text/javascript' in header there must be javascript in text, FALSE returned will stop polling
//
// Properties:
//  url        - URL to binding; default 'AJAX.php'
//  method     - request method; default 'GET' for scalar, 'POST' for arrays
//  pid        - process identifier; default 'AJAX'
//  timeout    - poll timeout (milliseconds); default 0 - no poll
//  polling    - poll string; default - ''
//  trylimit   - resend tries on errors numbers GE 600; default - 3
//  indicator  - object Indicator; default - none
//  onready    - function to any answer processing; default - none; parameter = AJAXobject
//  xmlhandler - function to XML answer processing; default - none; parameter = responseXML
//  error      - can be redefined for error processing; default - popup confirmation; parameters = errorCode, Content-Type \n responseText
// Methods:
//  send(obj)    - send request with 'obj' to defined url. If 'obj' is array then the method will be 'POST' else as defined in the 'method' property.
//  poll([ping]) - activate the polling process (send empty request). If 'ping' not omitted/empty then the 'timeout' property will be set to 'ping'.
//
//**************************
function AJAXobject(url,pid) {
  var me = this;
  try { this.xmlHttp=new XMLHttpRequest(); }
  catch (e) { 
    try { this.xmlHttp=new ActiveXObject("Msxml2.XMLHTTP"); }
    catch (e) { 
      try { this.xmlHttp=new ActiveXObject("Microsoft.XMLHTTP"); }
      catch (e){ this.xmlHttp=null;}
    }
  }
  this.url = url || "AJAX.php";
  this.method = "GET";
  this.pid = pid || "AJAX";
  this.timeout = 0;
  this.polling = '';
  this.trylimit = 3;
  this._trycnt = 0;
  this._queue = new Array();
  this._waiting = false;

 this.onanswer = function() {
   if(me._timer) {
    clearTimeout(me._timer);
   }
   var run, stat, text, rdy, hdr, xml;
   run = true;

   rdy=me.xmlHttp.readyState;
   if(me.indicator) {
     me.indicator.answer(me._trycnt,rdy);
   }
   if(rdy!=4) {
     return false;
   }

   stat = me.xmlHttp.status;
   text = me.xmlHttp.responseText;
   if(stat<200) {
     if(me.indicator) {
       me.indicator.strange(stat,text);
     }
     return true;
   }
   me._waiting = false;
   if(stat>400 && stat<600) {
     run = me.error(stat,text);
   }
   if(stat==200) {
     if(me.indicator) {
       me.indicator.done(text);
     }
     me._trycnt = 0;
     run = true;
     if( me.onready != null ) {
       run=me.onready(me);
     } else {
       hdr = me.xmlHttp.getResponseHeader("Content-Type");
       if( hdr.search(/text\/javascript/i) >= 0 ) {
        try { run=eval(text); }
        catch(e) {
         run = me.error(200,hdr+"\nCan't eval "+'"'+text+'"\n'+e);
        }
       } else if( me.xmlhandler && (hdr.search(/text\/xml/i) >= 0) ) {
        try { run=me.xmlhandler(me.responseXML);  }
        catch(e) {
         run = me.error(200,hdr+"\nCan't xml "+text+'"');
        }
       } else {
        run = me.error(200,hdr+'\nBad html "'+text+'"');
       }
     }
   } else {
     switch(stat) {
       case 12002: // Server timeout
       case 12029:
       case 12030:
       case 12031: // 12029 to 12031 correspond to dropped connections.
       case 12152: // Connection closed by server.
       case 13030: //
         me._retry();
         run = true;
         if(me.indicator) {
          me.indicator.error(stat,text);
         }
         break;
       default:
         if(me.indicator) {
           me.indicator.strange(stat,text);
         }
     }
   }
   if( me._queue.length>0 ) {
     me._send();
     return true;
   }
   if( run && me.timeout && me.poll ) {
     me._timer=setTimeout(me.poll,me.timeout);
   }
 }
}
AJAXobject.prototype = {
 url: null,
 method: null,
 pid: null,
 timeout: null,
 polling: null,
 trylimit: null,
 indicator: null,
 onready: null,
 xmlhandler: null,

 _trycnt: null,
 _timer: null,
 _queue: null,
 _last: null,
 _waiting: null,
 
 _retry: function() {
   this._trycnt++;
   if(this._trycnt<this.trylimit)
     this._queue.unshift(this._last);
 },

 _send: function() {
   var content = '';
   if(this._queue.length>0) {
     content = this._queue.shift();
     this._last = content;
   }
   var uri = this.url;
   var params = "";
   var tosend = null;
   var method;

   if( content instanceof Array ) {
     method = "POST";
     for(var i in content) {
       params += i + "=" + encodeURIComponent(content[i]) + "&";
     }
   } else {
     method = this.method;
     if( content!=null) params = content;
   }
   uri += "?rnd=" + Math.random() + "&pid=" + encodeURIComponent(this.pid) + "&" + this.polling;

   this._waiting = true;
   if( method.toUpperCase() == "POST" ) {
     this.xmlHttp.open(method,uri,true);
     this.xmlHttp.setRequestHeader('Content-Type','application/x-www-form-urlencoded; charset=utf-8');
     tosend = params;
   } else {
     uri += params;
     this.xmlHttp.open(method,uri,true);
   }
   this.xmlHttp.onreadystatechange=this.onanswer;
   this.xmlHttp.send(tosend);
   if(this.indicator) {
     this.indicator.send(this.url,this.pid,this.polling,content);
   }
   return true;
 },

 send: function(content) {
   if( this._timer ) {
    clearTimeout(this._timer);
   }
   this._queue.push(content);
   if(!this._waiting) this._send();
   return true;
 },

 poll: function(ping) {
   this.timeout = ping || this.timeout;
   if( !this._waiting && this._queue.length==0 ) {
     this.send('');
   }
   return true;
 },

 error: function(status, text) {
   return confirm( "AJAX status = " + status +"\n" + text + "\nContinue AJAX?" );
 }
}

// Set elements .innerHTML from array: [[id,HTML],[id,HTML]...]
function setElementsInnerById(what) {
  for(i=0;i<what.length;i++) {
    id = what[i][0];
    txt= what[i][1];
    if( x=document.getElementById(id) ) {
      x.innerHTML=txt;
    } else {
      if(x=document.getElementById('debug'))
       x.innerHTML += "<p>inner '"+id+"'='"+txt+"'";
    }
  }
  return true;
}
