function RemoteResponse( oRemote ) {
  this.connection = oRemote;

  this.xml = this.connection.targetElement.responseXML;
  this.text = this.connection.targetElement.responseText;

  this.toString = function() { return '[object RemoteResponse]'; }
}

function RemoteManager() {
  this.constructor.call( this );
  this.pending = new Array();
  this.timeout = null;

  this.toString = function() { return '[object RemoteManager]'; }

  this.send = function( txtUrl, callback, methodName ) {
    var tmp = new Remote();
    tmp.uri = txtUrl;
    tmp.method = methodName;
    tmp.addListener( 'onLoad', callback );
    this.pending[ this.pending.length ] = tmp;
    return this.pending[ this.pending.length - 1 ];
  }

  this.execute = function() {
    if ( 0 == this.pending.length )
      clearTimeout( this.timeout );
    var tmp = this.pending.shift();
    tmp.send( tmp.method, tmp.uri );
  }

  this.get = function( txtUrl, callback ) {
    var oRemote = this.send( txtUrl, callback, 'GET' );
    if ( arguments.length > 2 )
      for( var i=2; i<arguments.length; i+=2 )
        oRemote.appendData( arguments[ i ], arguments[ i + 1 ] );
    this.timeout = setTimeout( this.callback( this, 'execute' ), 500 );
    return oRemote;
  }
  this.post = function( txtUrl, callback ) {
    var oRemote = this.send( txtUrl, callback, 'POST' );
    if ( arguments.length > 2 )
      for( var i=2; i<arguments.length; i+=2 )
        oRemote.appendData( arguments[ i ], arguments[ i + 1 ] );
    this.timeout = setTimeout( this.callback( this, 'execute' ), 500 );
    return oRemote;
  }
}

RemoteManager.extend( Listenable );

function Remote() {
  this.constructor.call( this );

  if ( window.XMLHttpRequest )
    this.targetElement = new XMLHttpRequest();
  else {
    try {
      this.targetElement = new ActiveXObject( 'Microsoft.XMLHTTP' );
    } catch( err ) {
      this.targetElement = new ActiveXObject( 'Msxml2.XMLHTTP' );
    }
  }

  this.uri = null;
  this.datas = '';
  this.pending = new Array();
  this.params = new Array();

	this.appendData = function( field, value ) {
    var data = field + '=' + escape( value );
		this.datas += ( 0 == this.datas.length )
		  ? data : '&' + data;
	};

  this.toString = function() { return '[object Remote]'; }

  this.abort = function() {
    this.targetElement.abort();
  }
  this.send = function( httpMode ) {
		if ( !this.targetElement ) return false;
		httpMode = httpMode.toUpperCase().trim();

    var tmp = this;
		this.targetElement.onreadystatechange = function() {
			if ( tmp.targetElement.readyState == 4 )
        tmp.fireEvent( 'onLoad', new RemoteResponse( tmp ) );
		};
		switch( httpMode ) {
			case 'GET':
//				try {
					txtUrl = ( this.datas.length > 0 )
            ? this.uri + '?' + this.datas : this.uri;
					this.targetElement.open( 'GET', txtUrl );
					this.targetElement.setRequestHeader( 'X-Requester', 'JFCRemote' );
					this.targetElement.send( null );
/*
				}
				catch( error ) {
					if ( debug ) { alert('Echec lors de la transaction avec ' + txtUrl + ' via la méthode GET'); }
					return false;
				}					
*/
			break;
			case 'POST':
//				try {
					this.targetElement.open( 'POST', this.uri );
					this.targetElement.setRequestHeader( 'X-Requester', 'JFCRemote' );
					this.targetElement.setRequestHeader( 'Method', 'POST ' + this.uri + ' HTTP/1.0' ); // ??? 1.1 ou 1.0 mais pas 1.01
					this.targetElement.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded; charset=iso-8859-1' );
					this.targetElement.send( this.datas );
/*
				}
				catch( error ) {
					if ( debug ) { alert('Echec lors de la transaction avec ' + this.uri + ' via la méthode POST'); }
					return false;
				}
*/
			break;
			default:
				return false;
			break;
		}
		return true;
  }
}

Remote.extend( Listenable );