/*                              AJAX LIB                                   *
 ***************************************************************************
 *   Copyright (C) 2006  Igor Garcia <boo@php.net>                         *
 *                                                                         *
 *  Este programa é software livre; você pode redistribuí-lo e/ou          *
 *  modificá-lo sob os termos da Licença Pública Geral GNU, conforme       *
 *  publicada pela Free Software Foundation; tanto a versão 2 da           *
 *  Licença como (a seu critério) qualquer versão mais nova.               *
 *                                                                         *
 *  Este programa é distribuído na expectativa de ser útil, mas SEM        *
 *  QUALQUER GARANTIA; sem mesmo a garantia implícita de                   *
 *  COMERCIALIZAÇÃO ou de ADEQUAÇÃO A QUALQUER PROPÓSITO EM                *
 *  PARTICULAR. Consulte a Licença Pública Geral GNU para obter mais       *
 *  detalhes.                                                              *
 *                                                                         *
 *  Você deve ter recebido uma cópia da Licença Pública Geral GNU          *
 *  junto com este programa; se não, escreva para a Free Software          *
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA               *
 *  02111-1307, USA ou acesse o endereço abaixo:                           *
 *  http://www.magnux.org/doc/GPL-pt_BR.txt                                *
 *                                                                         *
 ***************************************************************************
   $Id: ajaxlib.js,v 1.3 2006/05/16 14:07:54 boo Exp $
 ***************************************************************************/

/** Classe Ajax
  * Esta classe abstrai os conceitos fundamentais da tecnologia AJAX com a qual
  * é possível estabelecer uma conexão entre o navegador e o servidor.
  * Assim, é possível atualizar de forma dinâmica o conteúdo da página exibida
  * no navegador, sem ter a necessidade de atualizar a página para que as
  * informações estejam disponíveis.
  */

function Ajax()  {
  var http                  =     null; // Instância para o obj. XMLHttpRequest
  var timeout               =     null; // Ponteiro para o contador de timeout
  this.ajax_timeout         =  11*1000; // Timeout padrão (30 segundos)
  this.ajax_timeout_handler =     null; // Função de callback para timeout
  this.ajax_receive_handler =     null; // Função de callback para receber dados
  this.ajax_method          =    'GET'; // Método de envio padrão
  this.ajax_async           =     true; // Tratamento de resposta assincrono
  this.ajax_auth_user       =     null; // Usuário para autenticação
  this.ajax_auth_passwd     =     null; // Senha para autenticação
  this.ajax_input           =       ''; // Dados a serem enviados para o server
  this.ajax_output          =       ''; // Dados recebidos do servidor
  this.ajax_response_type   =   'TEXT'; // Formato das respostas (text ou xml)
  this.ajax_do_cache        =    false; // Define se o cache será permitido
  this.ajax_last_errn       =        0; // Ultimo número de erro ocorrido
  this.ajax_last_err        =       ''; // Ultima descrição de erro ocorrido

  /** Esta rotina é responsável por criar uma instância do objeto XMLHttpRequest
    * @return Uma instância do objeto XMLHttpRequest ou NULL, em caso de erro ou
    *         falta de suporte do navegador.
    */
  this.create = function() {
    try { return new XMLHttpRequest();                   } catch (e) {}
    try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {}
    try { return new ActiveXObject("Msxml2.XMLHTTP");    } catch (e) {}
    return null;
  }

  this.get_output = function ()
  {
    return this.ajax_output;
  }

  this.get_input = function ()
  {
    return this.ajax_input;
  }

  this.add_input = function(param, val)
  {
    if (!param || param == '') return false;
    this.ajax_input += (this.ajax_input == '') ? '' : '&';
    this.ajax_input += (param+'='+encodeURIComponent(val));
    return this.ajax_input;
  }

  /**  Esta rotina retorna um ponteiro para a instância do objeto XMLHttpRequest
    *  utilizado por esta classe. Especialmente útil quando queremos montar 
    *  próprio método para tratar a mudança de status (onreadystatechange).
    *
    *  @return Um ponteiro para a instância do objeto XMLHttpRequest
    */
  this.get_ajax = function() {
    return http;
  }

  /** Este método é responsável por fazer a requisição ao servidor.
    * Vários aspectos desta requisição podem ser configurados e visualizados
    * através dos métodos set_* e get_* presentes nesta classe.
    * Tipicamente, este método será chamado após a chamada do método 'add_input'
    * quando a propriedade ajax_method for 'POST'.
    * Quando a propriedade ajax_method for 'GET', é util fazer uma chamada
    * síncrona e esperar o resultado direto deste método.
    * @param url - URL do script que irá processar a requisição no servidor
    * @return TRUE, caso a requisição sejá feita com sucesso através do método
    *         'POST' ou FALSE caso não haja uma função de callback definida e 
    *          erros forem detectados. Por fim, caso nao tenha uma função de 
    *          callback definida para tratar as respostas do servidor e 
    */
  this.send = function(url)
  {
    // Abre a conexão com o servidor
    http.open(this.ajax_method, url, this.ajax_async,
                   this.ajax_auth_user, this.ajax_auth_passwd);

    http.setRequestHeader("Accept-Charset","iso-8859-1;q=1");

    // Define se usaremos cache ou não...
    if (!this.ajax_do_cache && this.ajax_method.toUpperCase() == 'GET')
    {
      http.setRequestHeader("If-Modified-Since","Thu, 5 Feb 1981 20:00:00 GMT");
    }

    // Define o tipo de conteúdo a ser enviado para o servidor
    if (this.ajax_method.toUpperCase() == 'POST')
    {
      http.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
    }

    // Define o que fazer em caso de timeout
    if (this.ajax_timeout_handler != null)
    {
      timeout = setTimeout(this.ajax_timeout_handler, this.ajax_timeout);
    }
    else
    {
      timeout = setTimeout(function(){ http.abort(); },this.ajax_timeout );
    }

    // Faz a chamada de forma síncrona
    if (!this.ajax_async)
    {
       http.send(this.ajax_input);
       this.ajax_output = (this.ajax_response_type.toUpperCase() == 'XML') ?
                            http.responseXML :
                            http.responseText;
       clearTimeout(timeout);
       return this.ajax_output;
    }

    //Se chegou aqui é porque a chamada é assíncrona

    // Define quem chamar quando os dados estiverem prontos
    var restype = this.ajax_response_type;
    var rechandler = this.ajax_receive_handler;
    http.onreadystatechange = function() {
      if (http.readyState != 4) { return; }

      if (http.status != 200)
      {
        this.ajax_last_errn = http.status;
        this.ajax_last_err  = http.statusText;
        http.abort();
        return false;
      }
      else 
      {
        this.ajax_last_errn = 0; 
        this.ajax_last_err  = ''; 
        this.ajax_output    = (restype.toUpperCase() == 'XML') ?  http.responseXML : http.responseText;
        clearTimeout(timeout);
        if (rechandler != null) rechandler(this.ajax_output);
      }
    }

    if (this.ajax_input != '') 
    {
      http.send(this.ajax_input);
    }
    else 
    {
      http.send(null);
    }

    return true;
  }

  /** Esta rotina retorna o tipo de resposta esperada do servidor (TEXT | XML).
    * @return Retorna o tipo de resposta esperada do servidor.
    */
  this.get_cache = function() {
    return this.ajax_do_cache;
  }

  /** Este método permite definir se o mecanismo de comunicação de dados fará
    * uso de cache ou não (o padrão é NÃO).
    * @param c - Booleano que indica se será utilizado cache ou não (true|false)
    * @return Retorna TRUE se o cache for utilizado ou FALSE, caso o cache não
    *         seja utilizado nesta conexão
    */
  this.set_cache = function(c) {
    return (this.ajax_do_cache = c);
  }

  /** Esta rotina retorna o tipo de resposta esperada do servidor (TEXT | XML).
    * @return Retorna o tipo de resposta esperada do servidor.
    */
  this.get_response_type = function() {
    return this.ajax_response_type;
  }

  /** Este método permite definir o tipo de resposta esperada pelo servidor, no 
    * caso, define como a resposta será interpretada (texto puro ou XML).
    *
    * @param t - Tipo de resposta (text | xml)
    * @return Retorna o tipo de resposta esperada (text | xml)
    */
  this.set_response_type = function(t) {
    if (t.toUpperCase() != 'TEXT' && t.toUpperCase() != 'XML') 
    {
      return this.ajax_response_type;
    }
    return (this.ajax_response_type = t);
  }


  /** Esta rotina retorna a senha utilizada na autenticação.
    * @return Retorna a senha definida
    */
  this.get_auth_pass = function() {
    return this.ajax_auth_passwd;
  }

  /** Este método permite definir a senha para autenticação, quando
    * a mesma for requerida pelo servidor.
    * @param p - Senha para autenticação
    * @return Retorna a senha recém definida
    */
  this.set_auth_pass = function(p) {
    if (!p) return this.ajax_auth_passwd;
    return (this.ajax_auth_passwd = p);
  }

  /** Esta rotina retorna o nome de usuário utilizado na autenticação.
    * @return Retorna o usuário definido
    */
  this.get_auth_user = function() {
    return this.ajax_auth_user;
  }

  /** Este método permite definir o nome de usuário para autenticação, quando
    * o mesmo for requerido pelo servidor.
    * @param u - Nome de usuário
    * @return Retorna o usuário recém definido
    */
  this.set_auth_user = function(u) {
    if (!m) return this.ajax_auth_user;
    return (this.ajax_auth_user = u);
  }

  /** Esta rotina retorna a forma de acesso ao servidor (síncrona ou assincrona) 
    * @return Retorna a forma de acesso definida
    */
  this.get_async = function() {
    return this.ajax_async;
  }

  /** Este método permite definir a forma como as respostas serão esperadas
    * que podem ser de forma assíncrona ou sincrona.
    * @param a - Um booleano que indica se a forma de acesso será assincrona ou
    *            não. (TRUE | FALSE, padrão TRUE)
    * @return Retorna a forma de acesso recém definida
    */
  this.set_async = function(a) {
    return (this.ajax_async = a);
  }

  /** Esta rotina retorna o método de acesso ao servidor atual (POST ou GET) 
    * @return Retorna o método definido
    */
  this.get_method = function() {
    return this.ajax_method;
  }

  /** Este método permite definir o método de acesso ao servidor (POST ou GET) 
    * @param m - String que indica o método de acesso (aceitos: POST | GET)
    * @return Retorna o método recém definido
    */
  this.set_method = function(m) {
    if (!m) return this.ajax_method;
    return (this.ajax_method = m.toUpperCase());
  }

  /** Este método permite definir o tempo que o navegador esperará pela resposta
    * do servidor e após este tempo irá abortar a requisição.
    * @param t - Tempo, em segundos, para o timeout.
    * @return O número de segundos recém definido em caso de sucesso ou null,
    *         caso contrário.
    */
  this.set_timeout = function(t) {
    return ((!isNaN(t)) ? (this.ajax_timeout = t * 1000) : null);
  }

  /** Esta rotina retorna o número de segundos que o navegador irá aguardar antes
    * de considerar o tempo esgotado (timeout) para a requisição XMLHttpRequest.
    * @return Um inteiro representando o número de segundos que o navegador deverá
    *         aguardar por uma resposta.
    */
  this.get_timeout = function() {
    return this.ajax_timeout;
  }

  /** Esta rotina retorna o nome da função de callback que será chamada quando a

    * resposta do servidor chegar.
    * @return Uma string ou um array com o nome da função de callback e seu 
    *         parâmetros
    */
  this.get_receive_handler = function() {
    return this.ajax_receive_handler;
  }

  /** Esta rotina define o nome da função de callback que será chamada quando 
    * chegar a resposta do servidor
    * @param c - Uma string com o nome da função de callback ou um array com 
    *            o nome da função e seus parâmetros adicionais.
    * @return Uma string ou um array com o nome da função de callback
    */
  this.set_receive_handler = function(c) {
    if (!c) c = null;
    return (this.ajax_receive_handler = c);
  }

  /** Esta rotina retorna o nome da função de callback que será chamada quando o
    * tempo de espera (timeout) de uma requisição for esgotado.
    * @return Uma string com o nome da função de callbak
    */
  this.get_timeout_handler = function() {
    return this.ajax_timeout_handler;
  }

  /** Esta rotina retorna o nome da função de callback que será chamada quando o
    * tempo de espera (timeout) de uma requisição for esgotado.
    * @return Uma string com o nome da função de callback
    */
  this.set_timeout_handler = function(c) {
    return (this.ajax_timeout_handler = c);
  }

  /** Esta rotina retorna um ponteiro para o contador de timeout.
    * @return Um ponteiro para o contador de timeout.
    */
  this.get_timeout_obj = function() {
    return timeout;
  }

  //===========================================================================

  // Cria uma instância do objeto XMLHttpRequest para uso interno
  http = this.create(); // Instância do objeto XMLHttpRequest

  // Caso a tentativa acima falhar é porque o navegador não suporta AJAX :P
  if (http == null) alert('Seu navegador não suporta AJAX !');
}
