/*****
 ** Baseado em phpajax.js, de www.phpajax.org
 ** Profundamente alterado por Marcelo Saldanha
 **
 ** Requer json.js para suporte aos métodos *.toJSONString
 **/

/*****
 * Envia uma requisição assíncrona para o servidor, tratando todos os detalhes
 * String url: script destino (deverá responder à solicitação)
 * String operation: nome da operação requisitada
 * Array params: Registro com os parâmetros da operação
 * String callback: nome da função JavaScript a ser chamada ao terminar
 * String failureCallback: nome da função JavaScript a ser chamada ao falhar
 */
function phpAjax_execute(url, operation, params, callback, failureCallback) {
  
  // A requisição assíncrona é enviada para o script destino via POST, usando dois
  // parâmetros: 'phpAjax_operation' e 'phpAjax_params'. O primeiro é o nome da operação
  // e o segundo é uma versão codificada (com JSON) do array params.
  // Após o processamento, o servidor deve responder com um registro também codificado
  // com JSON, contendo as informações. Vide phpAjax_process() para mais detalhes.
  
  // Tratamento de operações realizadas com sucesso (Event handler)
  var success = function(t) {
    try {
      // Comunicação teve sucesso, mas a operação em si pode ter falhado.
      var ErrorRegex = new RegExp("^!!!error --");
      if (ErrorRegex.test(t.responseText)) {
        if (callback != '') {
          // Chama o callback assincronamente, apos 0.1 segundo.
          setTimeout(callback + "()", 100);
        }
        alert(t.responseText);
      }
      else {
        //alert(t.responseText);
        if (t.responseText.length > 0) {
          var elem = t.responseText.parseJSON();
          if (callback != '') {
            // Chama o callback assincronamente, apos 0.1 segundo.
            setTimeout(callback + "()", 100);
          }
          phpAjax_process(elem);
        }
      }
    } catch(e) {
      alert(e);
      alert(t.responseText);
    }
  }
  
  // Tratamento de operações sem sucesso (Event handler)
  var failure = function(t) {
    if (callback != '') {
      // Chama o callback assincronamente, apos 0.1 segundo.
      setTimeout(callback + "()", 100);
    }
    alert(t.responseText);
  }
  
  // Envia a requisição assíncrona
  var myAjax = new Ajax.Request(url,
    {
      method:'post',
      onSuccess:success,
      onFailure:failure,
      parameters: "phpAjax_operation="+operation+"&phpAjax_params=" + params.toJSONString()
    }
  );
}

/*****
 * Envia uma requisição síncrona para o servidor, retornando a resposta
 */
function phpAjax_query(url, operation, params, callback, failureCallback) {
  
  // A requisição síncrona é enviada para o script destino via POST, usando dois
  // parâmetros: 'phpAjax_operation' e 'phpAjax_params'. O primeiro é o nome da operação
  // e o segundo é uma versão codificada (com JSON) do array params.
  // Após o processamento, o servidor deve responder com um registro também codificado
  // com JSON, contendo as informações. Este registro é retornado na função. O cliente
  // fica responsável por interpretá-lo corretamente.
  
  // Tratamento de operações realizadas com sucesso (Event handler)
  var success = function(t) {
    try {
      // Comunicação teve sucesso, mas a operação em si pode ter falhado.
      var ErrorRegex = new RegExp("^!!!error --");
      if (ErrorRegex.test(t.responseText)) {
        if (callback != '') {
          // Chama o callback sincronamente.
          failureCallback();
        }
        alert(t.responseText);
      }
      else {
        //alert(t.responseText);
        var elem = t.responseText.parseJSON();
        if (callback != '') {
          // Chama o callback sincronamente
          callback();
        }
        return elem;
      }
    } catch(e) {
      alert(e);
      alert(t.responseText);
    }
  }
  
  // Tratamento de operações sem sucesso (Event handler)
  var failure = function(t) {
    if (callback != '') {
      // Chama o callback sincronamente
      failureCallback();
    }
    alert(t.responseText);
  }
  
  // Envia a requisição síncrona
  var myAjax = new Ajax.Request(url,
    {
      method:'post',
      asynchronous: false,
      onSuccess:success,
      onFailure:failure,
      parameters: "phpAjax_operation="+operation+"&phpAjax_params=" + params.toJSONString()
    }
  );
}

// O resultado da solicitação assync é um array codificado com JSON, que será iterado
// a procura de comandos phpAjax. Cada comando possui um certo número de parâmetros, que
// devem ter sido colocados após o comando:
//  'avalue': Primeiro param é o nome de um objeto destino, Segundo é o novo valor para este objeto.
//  'ahtml': Primeiro param é o nome de um objeto destino, Segundo é o novo conteúdo HTML para este objeto.
//  'ahtmlinc': Primeiro param é o nome de um objeto destino, Segundo é o conteúdo HTML a ser adicionado no final.
//  'ahide':  Param é o nome de um objeto a ser ocultado
//  'achangeclass':  Primeiro param é o nome do objeto, Segundo é a nova classe CSS a ser atribuída
//  'ashow':  Param é o nome de um objeto a ser exibido
//  'amceon':  Param é o nome do editor TinyMCE a ser habilitado
//  'amceoff':  Param é o nome do editor TinyMCE a ser desabilitado
//  'amcetoggle':  Param é o nome do editor TinyMCE a ser alternado (on/off)
//  'afunc':  Param é o nome de uma função JS a ser chamada
//  'acode':  Param é um código JavaScript a ser executado
//  'afocus': Param é o nome de um elemento a ser focalizado
//  'aalert':  Param é uma mensagem a ser exibida num diálogo
//  'asubst':  Primeiro param é o nome de um objeto destino, Segundo é a nova definição HTML em seu lugar
//  'aselect':  Primeiro param é o nome de uma lista destino, Segundo é o índice da opção selecionada
function phpAjax_process(data) {
  var di = 0;
  var cmd = null;
  var r = 0;
  while (di < data.length) {
    cmd = data[di];
    r = data.length - di - 1;
    // avalue
    if (cmd == 'avalue') {
      if (r < 2) throw "!!!error -- avalue misconfiguration!!!";
      var obj = data[++di];
      var value = data[++di];
      phpAjax_setContent(obj, value, false);
    }
    // ahtml
    else if (cmd == 'ahtml') {
      if (r < 2) throw "!!!error -- ahtml misconfiguration!!!";
      var obj = data[++di];
      var html = data[++di];
      phpAjax_setContent(obj, html, true);
    }
    // achangeclass
    else if (cmd == 'achangeclass') {
      if (r < 2) throw "!!!error -- achangeclass misconfiguration!!!";
      var obj = data[++di];
      var cls = data[++di];
      var oo = phpAjax_find(obj);
      if (oo) oo.className = cls;
    }
    // ahtmlinc
    else if (cmd == 'ahtmlinc') {
      if (r < 2) throw "!!!error -- ahtmlinc misconfiguration!!!";
      var obj = data[++di];
      var html = data[++di];
      phpAjax_addContent(obj, html, true);
    }
    // ahide
    else if (cmd == 'ahide') {
      if (r < 1) throw "!!!error -- ahide misconfiguration!!!";
      phpAjax_hide(data[++di]);
    }
    // ashow
    else if (cmd == 'ashow') {
      if (r < 1) throw "!!!error -- ashow misconfiguration!!!";
      phpAjax_show(data[++di]);
    }
    // amceon
    else if (cmd == 'amceon') {
      if (r < 1) throw "!!!error -- amceon misconfiguration!!!";
      phpAjax_mceEnable(data[++di]);
    }
    // amceoff
    else if (cmd == 'amceoff') {
      if (r < 1) throw "!!!error -- amceoff misconfiguration!!!";
      phpAjax_mceDisable(data[++di]);
    }
    // amcetoggle
    else if (cmd == 'amcetoggle') {
      if (r < 1) throw "!!!error -- amcetoggle misconfiguration!!!";
      phpAjax_mceToggle(data[++di]);
    }
    // avaluemce
    else if (cmd == 'avaluemce') {
      if (r < 2) throw "!!!error -- avaluemce misconfiguration!!!";
      var obj = data[++di];
      var value = data[++di];
      phpAjax_setMceContent(obj, value);
    }
    // afunc
    else if (cmd == 'afunc') {
      if (r < 1) throw "!!!error -- afunc misconfiguration!!!";
      eval(data[++di] + "();");
    }
    // acode
    else if (cmd == 'acode') {
      if (r < 1) throw "!!!error -- acode misconfiguration!!!";
      eval(data[++di]);
    }
    // afocus
    else if (cmd == 'afocus') {
      if (r < 1) throw "!!!error -- afocus misconfiguration!!!";
      var obj = phpAjax_find(data[++di]);
      if (obj) obj.focus();
    }
    // aalert
    else if (cmd == 'aalert') {
      if (r < 1) throw "!!!error -- aalert misconfiguration!!!";
      alert(data[++di]);
    }
    // asubst
    else if (cmd == 'asubst') {
      if (r < 2) throw "!!!error -- asubst misconfiguration!!!";
      var obj = data[++di];
      var html = data[++di];
      phpAjax_subst(obj, html);
    }
    // aselect
    else if (cmd == 'aselect') {
      if (r < 2) throw "!!!error -- aselect misconfiguration!!!";
      var obj = phpAjax_find(data[++di]);
      var index = data[++di];
      if (obj) obj.selectedIndex = index;
    }
    di++;
  }
}

// Torna um objeto invisível
function phpAjax_hide(obj_name) {
  phpAjax_visibility(obj_name, 'hidden');
}

// Torna um objeto visível
function phpAjax_show(obj_name) {
  phpAjax_visibility(obj_name, 'visible');
}

// Habilita o editor TinyMCE para um textarea indicado
function phpAjax_mceEnable(obj_name) {
  if (!tinyMCE.get(obj_name)) {
    tinyMCE.execCommand("mceAddControl", false, obj_name);
  }
}
// Desabilita o editor TinyMCE para um textarea indicado
function phpAjax_mceDisable(obj_name) {
  if (tinyMCE.get(obj_name))
    tinyMCE.execCommand("mceRemoveControl", false, obj_name);
}
// Alterna o editor TinyMCE para um textarea indicado
function phpAjax_mceToggle(obj_name) {
  if (!tinyMCE.get(obj_name))
    tinyMCE.execCommand("mceAddControl", false, obj_name);
  else
    tinyMCE.execCommand("mceRemoveControl", false, obj_name);
}


/*****
 * Comuta a visibilidade de um objeto qualquer
 */
function phpAjax_visibility(obj_name, cssVisibility) {
  // Isso é feito via CSS, operador Visibility (aceita 'visible' e 'hidden')
  var obj = phpAjax_find(obj_name);
  if (obj) {
    if (obj.style.visibility) {
      obj.style.visibility = cssVisibility;
    }
    else if (obj.visibility) {
      obj.visibility = cssVisibility;
    }
  }
}
function phpAjax_toggleVisibility(obj_name) {
  // Isso é feito via CSS, operador Visibility (aceita 'visible' e 'hidden')
  var obj = phpAjax_find(obj_name);
  var visible = false;
  if (obj) {
    if (obj.style.visibility) {
      if (obj.style.visibility == 'hidden') {
        obj.style.visibility = 'visible';
        visible = true;
      }
      else {
        obj.style.visibility = 'hidden';
        visible = false;
      }
    }
    else if (obj.visibility) {
      if (obj.visibility == 'hidden') {
        obj.visibility = 'visible';
        visible = true;
      }
      else {
        obj.visibility = 'hidden';
        visible = false;
      }
    }
  }
  return visible;
}

/*****
 * Imprime um novo conteúdo para um objeto qualquer
 */
function phpAjax_setContent(obj_name, html, inner) {
  var obj = phpAjax_find(obj_name);
  if ( !obj ) return;
  // Alguns objetos, como INPUTs, possuem uma propriedade 'value' que deve ser
  // utilizada para definição dinâmica de conteúdo. Outros, como DIVs, possuem
  // uma propriedade 'innerHTML' para o mesmo fim.
  // O problema é que alguns possuem AMBAS! A decisão depende do tipo de objeto
  // Nota: Para SELECT, no IE a atribuição de opções não funciona. É melhor usar
  // um código JavaScript para preencher, o que é compatível com todos browsers.
  if ((obj.innerHTML !== undefined) && inner) {
    obj.innerHTML = html;
    //if (obj.value !== undefined) { obj.value = null; }
  }
  if ((obj.value !== undefined) && !inner) {
    if (obj.selectedIndex !== undefined) {
      var ntx = -1;
      for (var k = 0; k < obj.options.length; k++) {
        if (obj.options[k].value == html) {
          ntx = k;
          break;
        }
      }
      obj.selectedIndex = ntx;
    }
    else {
      obj.value = html;
    }
  }
}
function phpAjax_addContent(obj_name, html, inner) {
  var obj = phpAjax_find(obj_name);
  if ( !obj ) return;
  if ((obj.innerHTML !== undefined) && inner) {
    obj.innerHTML += html;
  }
  if ((obj.value !== undefined) && !inner) {
    obj.value += html;
  }
}
function phpAjax_setMceContent(obj_name, html) {
  var obj = phpAjax_find(obj_name);
  if ( !obj ) return;
  // Para editores TinyMCE, não adianta alterar o value das TextAreas.
  // É precisa acessar o Editor e definir seu conteúdo diretamente.
  var editor = tinyMCE.get(obj.id);
  if (!editor) return;
  editor.setContent(html);
}

/*****
 * Substitui um objeto HTML por outro 
 */
function phpAjax_subst(obj_name, html) {
  // Baseada em http://www.htmlstaff.org/ver.php?id=22531
  // Parece ser falha. Funcionando, pode ser interessante em alguns contextos,
  // por isso não foi apagada
  var obj = phpAjax_find(obj_name);
  if (obj && obj.parentNode) {
    var div = document.createElement('div');
    div.innerHTML = html;
    obj.parentNode.replaceChild(div.firstChild, obj);
  }
}

/****
 * Resolve um String no objeto identificado, se possível
 */
function phpAjax_find(name) {
  if (typeof(name) == 'object') return name;
  if (typeof(name) == 'undefined') return null;
  var obj = null;
  var str = new String(name);
  // 1) Nome pode ser um campo de formulário
  var n = str.indexOf(".");
  if (n >= 0) {
    var form = str.substr(0, n);
    var field = str.substr(n+1, str.length - n-1);
    var all = document.getElementsByName(field);
    for (i = 0; i < all.length; i++) {
      if (all[i].form.name == form) {
        obj = all[i];
        break;
      }
    }
  }
  if (!obj) {
    // 2) Nome é um ID de um objeto qualquer
    var e = document.getElementById(name);
    if (e) {
      obj = e;
    }
    else {
      // Aí começar a apelar...
      if (document.all) {
        e = document.all[name];
        if (e) obj = e;
      }
    }
  }
  return obj;
}

function phpAjax_getObjectClass(obj) {
  // Esta rotina ainda é falha com o IE.
  if (obj && obj.constructor && obj.constructor.toString) {
    var arr = obj.constructor.toString().match(/object\s(\w+)/);
    if (arr && arr.length == 2) return arr[1];
    arr = obj.constructor.toString().match(/function\s*(\w+)/);
    if (arr && arr.length == 2) {
      return arr[1];
    }
  }
  return undefined;
}

function phpAjax_loadingList(list, text) {
  // O mundo seria um lugar melhor se o IE seguisse padrões. Ao inves de uma atribuição
  // trivial via innerHTML, é preciso fazer tudo isso para ficar compatível com todos browsers.
  var obj = phpAjax_find(list);
  obj.options.length = 0;
  var opt = document.createElement('option');
  opt.text = text;
  opt.value = '';
  try {
    obj.add(opt, null); // standards compliant
  }
  catch (ex) {
    obj.add(opt); // IE only
  }
  return true;
}


// Atalho para carregamento de listas (SELECT) quando o innerHTML está disponível
// diretamente em alguma URL, evitando o overhead do tratamento genérico do phpAjax.
function phpAjax_directFillList(url, args, list) {
  // Tratamento de operações realizadas com sucesso (Event handler)
  var lst = phpAjax_find(list);
  phpAjax_loadingList(lst, "Aguarde...");
  var success = function(t) {
    try {
      // Comunicação teve sucesso, mas a operação em si pode ter falhado.
      var ErrorRegex = new RegExp("^!!!error --");
      if (ErrorRegex.test(t.responseText)) {
        lst.innerHTML = "<Option value=''>Falha no carregamento</Option>";
      }
      else {
        if (t.responseText.length > 0) {
          lst.innerHTML = t.responseText;
        }
      }
    } catch(e) {
      alert(e);
      alert(t.responseText);
    }
  }
  
  // Tratamento de operações sem sucesso (Event handler)
  var failure = function(t) {
    alert(t.responseText);
  }
  
  // Envia a requisição assíncrona
  var myAjax = new Ajax.Request(url,
    {
      method:'get',
      onSuccess:success,
      onFailure:failure,
      parameters: args
    }
  );
}

function padZero(number, length) {
  var str = '' + number;
  while (str.length < length) {
    str = '0' + str;
  }
  return str;
}


