/*
*    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
*/

/**
* Provides global engine features.
* @author Carlos Eduardo Goncalves
*/

/** 
* <p>Engine constructor.</p>
*/
function Engine() {
}

/** <p>ActiveX classes that provide XMLHttpRequest features.</p> */
Engine.ACTIVEX_XHR = ["Microsoft.XMLHTTP", "MSXML2.XMLHTTP"];

/** <p>ActiveX classes that provide DOM features.</p> */
Engine.ACTIVEX_DOM = ["Microsoft.XMLDOM", "MSXML2.DOMDocument", "MSXML.DOMDocument"]

/** <p>HTTP supported methods.</p> */
Engine.HTTP_METHODS = ["GET", "POST"];

/** <p>HTTP status codes.</p> */
Engine.HTTP_STATUS_CODES = ["200 OK", "201 Created", "202 Accepted", "203 Non-Authoritative Information",
							"205 Reset Content", "204 No Content", "206 Partial Content",
							"300 Multiple Choices", "301 Moved Permanently", "302 Found", "303 See Other",
							"304 Not Modified", "305 Use Proxy", "307 Temporary Redirect",
							"400 Bad Request", "401 Unauthorized", "402 Payment Required", 
							"403 Forbidden",  "404 Not Found", "405 Method Not Allowed", "406 Not Acceptable",
							"407 Proxy Authentication Required", "408 Request Timeout", "409 Conflict",
							"410 Gone", "411 Length Required", "412 Precondition Failed", 
							"413 Request Entity Too Large", " 414 Request-URI Too Long", "415 Unsupported Media Type",
							"416 Requested Range Not Satisfiable", "417 Expectation Failed",
							"500 Internal Server Error", "501 Not Implemented", "502 Bad Gateway", 
							"503 Service Unavailable", "504 Gateway Timeout", "505 HTTP Version Not Supported"];

/** <p>Debug mode flag.</p> */	
Engine.debug = null;  

/** <p>Engine global progress bar.</p> */
Engine.progressBar = null;	
	
/** 
* <p>Engine start up.</p>
* @param debug 
*		<code>Boolean</code> flag that turns on/off the engine debug mode.
* @param progress_bar 
*		Progress bar object used by the engine.
*/
Engine.start = function(debug, progress_bar) {
  Engine.debug = debug;
  if(Engine.assertOneOfTypes(progress_bar, [EmbeddedProgressBar, FlyProgressBar]))
	Engine.progressBar = progress_bar;
  if(Engine.debug)
    Console.start();
  Engine.doTimer();
}

/** 
* <p>Define the way how exceptions are reported.</p>
* @param msg_id
*		<code>Message</code> unique identifier on message queue.
* @param exception
*		Exception to be displayed or threw.
* @throws Run time exception.
*/
Engine.reportException = function(msg_id, exception) {
  if(Engine.debug)
    Console.trace(exception, Console.EXCEPTION);
  else {
    var msg = MessageQueue.getMessage(msg_id);
    if((msg == null) || (msg.onError == null))
      throw exception;
    else
      msg.onError(exception);
  }
  MessageQueue.remove(msg_id);
}

/**
* <p>Hook function called automatically by the engine to perform 
* continuous tasks like garbage collection and progress feedback.</p>
*/
Engine.doTimer = function() {
  try {
    if(Engine.progressBar != null)
	  Engine.progressBar.update(MessageQueue.hasActiveMessage());
	MessageQueue.clear();
    setTimeout(Engine.doTimer, 100);
  } 
  catch(e) { 
    setTimeout(Engine.doTimer, 100);
  }    
}

/**
* <p>Set or replace the engine progress bar for a new one.</p>
* @param progress_bar
*		New engine progress bar instance.
* @see EmbeddedProgressBar
* @see FlyProgressBar
*/
Engine.setProgressBar = function(progress_bar) {
  if(!Engine.assertOneOfTypes(progress_bar, [EmbeddedProgressBar, FlyProgressBar]))
    return;
  if(Engine.progressBar != null)
    Engine.progressBar.free();
  Engine.progressBar = progress_bar;
}

/** 
* <p>Try to build an ActiveX object based on a list classes.</p> 
* @param names
*		Array with ActiveX class names that could be created.
* @return
*		Reference to an <code>ActiveXObject</code>.
*/
Engine.buildActiveX = function(names) {
  var obj = null;
  for(var i = 0; i < names.length; i++) {
    try {
      obj = new ActiveXObject(names[i]);
	  break;
     } 
	 catch (e) { /* Ignore the exception and try the next */ }
  }
  return obj;
}

/** 
* <p>Build client side JavaScript objects required to XMLHTTP request.</p>	
* @return
*		Reference to a <code>XMLHttpRequest</code> or <code>ActiveXObject</code> instance.
*/
Engine.buildRequest = function() {
  try {
    var obj = (typeof XMLHttpRequest != "undefined") ? new XMLHttpRequest() : Engine.buildActiveX(Engine.ACTIVEX_XHR);		
	return obj;
  } 
  catch(e) { 
    Engine.reportException(null, e);
  }	
}

/** 
* <p>Load a file based on the provided url.</p>
* @param url
*		Universal resource locator to the file.
* @return
*		Reference to a <code>XMLDocument</code> instance.
*/
Engine.loadFile = function(url) {
  try {
    var req = Engine.buildRequest();
    req.open("GET", url, false);
    req.send('');	
    return req.responseXML;
  } 
  catch(e) { 
    Engine.reportException(null, e); 
  }
}

/** 
* <p>Check if object type is correct.</p>
* @param obj
*		Object to type check.
* @param type
*		Type to be used on check.
* @return
*		<code>Boolean</code> flag that indicates if obtect type match the specified type.
*/
Engine.assertType = function(obj, type) {
  if(obj == null)
    return false;
  var obj_type = typeof obj;
  return (obj_type.toLowerCase() == 'object') && (obj.constructor == type);
}

/** 
* <p>Check if object type match any of the options.</p>
* @param obj
*		Object to type check.
* @param types
*		Array with types to be used on check.
* @return
*		<code>Boolean</code> flag that indicates if obtect type match one of the specified types.
*/
Engine.assertOneOfTypes = function(obj, types) {
  var r = false;
  for(var i = 0; i < types.length; ++i) {
	r = Engine.assertType(obj, types[i]);
	if(r == true)
	  return r;
  }
  return r;
}

/**
* <p>Enable browser security privileges.</p>
*/
Engine.doAsPrivileged = function() {
  try {
    netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); 
  } 
  catch (e) { /* Ignore the exception */ }	
}