/*
*    Clean AJAX Engine v4.1
*    Copyright (C) 2005-2006 Carlos Eduardo Goncalves (cadu.goncalves@gmail.com)
*
*    This program is free software; you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation; either version 2 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License
*    along with this program; if not, write to the Free Software
*    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

/**
* Class based on adapter design pattern used to adapt 
* messages with objects provided by the browser.
* @author Carlos Eduardo Goncalves
*/

/**
* <p>Message wrapper constructor.</p>
*/
function MessageWrapper() {
  /** <p>Holds a XSL file that will be used to parse the response.</p> */
  MessageWrapper.prototype.style = null; 
  /** <p>Holds message unique id.</p> */  
  MessageWrapper.prototype.id = null;   
  /** <p>Holds message consumer element id.</p> */
  MessageWrapper.prototype.consumer = null; 
  /** <p>Flag that defines if consumer value will be refreshed.</p> */
  MessageWrapper.prototype.refresh = null;
  /** <p>Flag that defines if response will be cached.</p> */    
  MessageWrapper.prototype.cache = null;  
  /** <p><code>Document</code> used to find the message consumer element.</p> */
  MessageWrapper.prototype.doc = null; 
  /** <p>URL to request.</p> */
  MessageWrapper.prototype.address = null;	
  /** <p>Flag that defines if the message will display any progress bar.</p> */
  MessageWrapper.prototype.silent = null;
  /** <p>Holds the progress bar used by the message.</p> */
  MessageWrapper.prototype.progressBar = null;
  /** <p>Holds a <code>RemoteMethod</code> defined as value of the message.</p> */
  MessageWrapper.prototype.remoteMethod = null;
  /** <p>Holds a <code>RemoteMethod</code> parsed to XML.</p> */
  MessageWrapper.prototype.parsedMethod = null;	
  /** <p>Holds the <code>XMLHttpRequest</code> instance used to perform to send the request.</p> */
  MessageWrapper.prototype.request = null;
  /** <p>Event handler called when a exception occurs.</p> */
  MessageWrapper.prototype.onError = null;
  /** <p>Event handler called after response.</p> */
  MessageWrapper.prototype.onComplete = null;  
}

/** 
* <p>Import all AJAX message data to the wrapper.</p>
* @param msg
*		<code>Message</code> value object to be wrapped.	
* @throws Exception that informs if the parameter is not a <code>Message</code> object.
*/
MessageWrapper.prototype.wrap = function(msg) {
  try {	
	if(!Engine.assertType(msg, Message))
	  throw "Invalid parameter";
	if(Engine.HTTP_METHODS.toString().indexOf(msg.method.toUpperCase()) == -1)
	  msg.method = "POST";	
    if(msg.xslt != null)
	  this.style = Engine.loadFile(msg.xslt); 
    this.id = MessageQueue.messages.length;   
	this.consumer = msg.consumer; 
	this.refresh = msg.refresh;
	this.cache = msg.cache;
    this.doc = msg.doc; 
	this.address = msg.address;	
	this.silent = msg.silent;
    this.progressBar = msg.progressBar;
	if(Engine.assertType(msg.value, RemoteMethod)) {
      var stream = this.getStream(msg.value.protocol); 	  
 	  if(stream != null) {
	    this.remoteMethod = msg.value;
        this.parsedMethod = stream.write(this.remoteMethod);	
	  }
	}  
    this.request = Engine.buildRequest();
    this.request.open(msg.method, msg.address);
    this.onError = msg.onError;
    this.onComplete = msg.onComplete;	
    if(msg.onChange != null)
	  this.request.onreadystatechange = msg.onChange;   
    else { 
	  var _this = this;
	  var args = [this];
	  this.request.onreadystatechange = function() {
    		_this.onChange.apply(args[0], args);
  		}
    }
  } 
  catch(e) { 
    Engine.reportException(null, e); 
  }
}

/** 
* <p>Create an appropriate stream to read a XML document.</p>
* @param format
*		<code>XMLDocument</code> format (XMLRPC or SOAP).
* @return
*		Valid stream object or <code>null</code>.
*/
MessageWrapper.prototype.getStream = function(format) { 
  if(format == null)
    return null;
  switch(format.toUpperCase()) {
	case 'SOAP':
	  return new SoapStream();
	case 'XMLRPC':
	  return new XmlRpcStream();
	default: 
	  return null;
  }
}

/** 
* <p>Internal onreadystatechange listener used by <code>Message</code> instances.</p>
*/
MessageWrapper.prototype.onChange = function() { 
  try {
    if(this.request.readyState == 4) {	
	  if(this.remoteMethod != null)
	    Engine.doAsPrivileged();
      var s = this.parseStatus(this.request.status)  + ": " + this.address;
      Console.trace(s, Console.RESPONSE);			  
      if(this.request.status >= 200 && this.request.status <= 299) {	
	    var iterator = new DomIterator(this.doc);
	    if(this.style != null)
	      iterator.applyValue(this.consumer, XsltTool.transform(this.request.responseXML, this.style), this.refresh);
	    else {
	      if(this.remoteMethod != null) {
		    var stream = this.getStream(this.remoteMethod.protocol);
			if(stream != null) {
              Console.trace(this.request.responseText, Console.RPC_DATA);				
			  var rpc_result = stream.read(this.request.responseXML);
			  if(stream.faultValue != null) {
			    if(this.remoteMethod.onError != null)			  
			      this.remoteMethod.onError(rpc_result);
			  }
			  else {
			    if(this.remoteMethod.onResult != null)
			      this.remoteMethod.onResult(rpc_result);
			  }
			}
		  }
		  else
		    iterator.applyValue(this.consumer, this.request.responseText, this.refresh);
		}
		if((this.cache) && (this.remoteMethod == null))
		  History.save(this.doc, this.consumer);
      }  	  
	  if(this.progressBar != null)
  	    this.progressBar.update(false);	  
      if(this.onComplete != null)
	    this.onComplete(this.request); 	
    }
  } 
  catch(e) { 
    Engine.reportException(null, e); 
  }  
}  	  

/**
* <p>Return user friendly HTTP status code.</p>
* @param status
*		Status code.
* @return
*		<code>String</code> with the request status and its definition.
*/
MessageWrapper.prototype.parseStatus = function(status) { 
  try {
    var str = "HTTP status " + status;
    for(var i = 0; i < Engine.HTTP_STATUS_CODES.length; ++i) {
      if(Engine.HTTP_STATUS_CODES[i].indexOf(status) != -1) {
	    str = Engine.HTTP_STATUS_CODES[i];	
	    break;
	  }
    }
    return str;
  } 
  catch(e) { 
    Engine.reportException(null, e); 
  }    
}
