/* --------------------------------------------------------------------------------------------------------------
*  API:      JSMX (JavaScript MX) - This is a ColdFusion API for AJAX.  
*  AUTHOR:     Todd Kingham [todd@lalabird.com] - Jan Jannek [jan.jannek@Cetecom.de]
*  CREATED:    8.21.2005
*  VERSION:    2.6.15 - Versão especial para FW
*  DESCRIPTION:  This API uses XMLHttpRequest to post/get data from a ColdFusion interface.
*          The CFC's/CFM's will return a string representation of a JS variable: response_param.
*          The "onreadystatechange event handler" will eval() the string into a JS variable 
*          and pass the value back to the "return function". To Download a full copy of the sample 
*          application visit: http://www.lalabird.com/JSMX/?fa=JSMX.downloads
*
*  HISTORY:2.0.0:  Todd: Scripted Out Original Version
*          2.1.0:  Todd: Modified for Download
*          2.2.0:  Todd: Modified the firstWord() function to be backward compatable with
*                  CF5 and to be more stable all-around.
*          2.3.0:  Todd: Added "wait div" functionality
*          2.4.0:  Todd: XML!!!! Now JSMX will allow you to pass XML Documents to the API in
*                  addition to the original JavaScript method.
*          2.4.1:  Jan:  2006-02-16, XMLHTTP requests can now handle more than one request at once. By placing the onreadystatechange event as a local variable inside the actual http() function.
*              Jan:  Added fix for strange IE bug that returned Header Info.
*              Todd: Added the jsmx object to allow users to override defaults and set custom "async", "wait" and "error" methods
*          2.5.0:  Todd: Added JSON Support! So now you can pass JavaScript, XML, or JSON.
*          2.5.1:  Todd: Version 2.5.0 was premature. Needed to fix an eval() bug when I introduced JSON.
*          2.5.2:  Todd: Fixed a bug in the onreadystatechange. Based on the order you call the event handler... "State Change 1" gets called twice. Added code to only process code inside 'CASE 1:' once
*          2.5.3:  Todd: Fixed a bug in the try/catch of the parser by placing the callback() call within the try/catch statement. This caused errors in the callback function to be "masked" and appear as "parsing errors", even when the parse was successful.
*          2.6.0:   Todd: Added WDDX Parser! Now you can return WDDX Strings as well.
*
*  LICENSE:    THIS IS AN OPEN SOURCE API. YOU ARE FREE TO USE THIS API IN ANY APPLICATION,
*                 TO COPY IT OR MODIFY THE FUNCTIONS FOR YOUR OWN NEEDS, AS LONG THIS HEADER INFORMATION
*                   REMAINS IN TACT AND YOU DON'T CHARGE ANY MONEY FOR IT. USE THIS API AT YOUR OWN
*                 RISK. NO WARRANTY IS EXPRESSED OR IMPLIED, AND NO LIABILITY ASSUMED FOR THE RESULT OF
*                 USING THIS API.
*
*                 THIS API IS LICENSED UNDER THE CREATIVE COMMONS ATTRIBUTION-SHAREALIKE LICENSE.
*                 FOR THE FULL LICENSE TEXT PLEASE VISIT: http://creativecommons.org/licenses/by-sa/2.5/
*
-----------------------------------------------------------------------------------------------------------------*/
// UNCOMMENT THE FOLLOWING LINE IF YOU WILL BE RETURNING QUERY OBJECTS. (note: you may need to point the SRC to an alternate location.
/*document.writeln('<SCRIPT TYPE="text/javascript" LANGUAGE="JavaScript" SRC="/CFIDE/scripts/wddx.js"></SCRIPT >');*/

jsmx = new jsmxConstructor();
function jsmxConstructor(){
  this.async = true;
  this.onError = onError;
  this.onWait = popWait;
  this.onWaitEnd = killWait;
  this.loadingMsg = "Carregando...";
}


// perform the XMLHttpRequest();
function http(verb,url,rm,qry) {
    //reference our arguments
  var callback = rm;
  var qryStr = (!qry) ? '' : toQueryString(qry);
  var calledOnce = false; //this is to prevent a bug in onreadystatechange... "state 1" gets called twice.
  try{//this should work for most modern browsers excluding: IE Mac
    var req = ( window.XMLHttpRequest ) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP") ;
      req.onreadystatechange = function(){
      switch(req.readyState){
        case 1: 
          if(!calledOnce){
            jsmx.onWait();
            calledOnce = true;
          }
          break;
        case 2: break;
        case 3: break;
        case 4:
          jsmx.onWaitEnd();
          if ( req.status == 200 ){// only if "OK"
            try{
              rObj = parseResponse( req ) ;
              success = true;
            }catch(e){ 
              jsmx.onError('Erro: O valor retornado não pode ser avaliado.');
              success = false;
            }
            if(success) callback( rObj );
          }else{ 
            jsmx.onError("Houve um problema ao retornar os dados:\n" + req.statusText);
          }
          break;
        }
      }
      req.open( verb , noCache(url) , jsmx.async );
      if(verb.toLowerCase() == 'post')  
      req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
      req.send(qryStr);
  }catch(e){//a browser not equiped to handle XMLHttp
    //jsmx.onError("There was a problem retrieving the data:");
  }
}

/*--- BEGIN: RESPONSE PARSING FUNCTIONS ---*/
  function parseResponse(rO){
    //FIRST TRY IT AS XML
    if(rO.getResponseHeader("Content-Type").split(';')[0] == 'text/xml'){  
      return rO.responseXML;
    }  
    
    var str = rO.responseText;
    // jan.jannek@cetecom.de, 2006-02-16, weird error: some IEs show the responseText followed by the complete response (header and body again) 
    var i = str.indexOf("HTTP/1");
    if (i > -1) {
      str = str.substring(i, str.length);
      i = str.indexOf(String.fromCharCode(13, 10, 13, 10));
      if (i > -1) {
        str = str.substring(i + 2, str.length);
      }
    }    
    
    //NEXT TRY IT AS WDDX
    if(str.indexOf("<wddxPacket") > -1){
      return parseWDDX(str);  
    }
    
    
    //DO THE STRING EVAL
    try{//next try JSON eval();
      return parseJSON(str);
    }catch(e){//then try Classic eval();
      return parseJS(str);
    }
  }  
  function parseJS(str){ 
    eval(str);
    var r = eval(str.split('=')[0].replace(/\s/g,''));
    return r;
  }
  function parseJSON(str){
    return  eval('('+str+')');
  }

function parseWDDX(str){ var wddx = xmlStr2Doc(str); var data = wddx.getElementsByTagName("data"); return __parseWDDXnode(data[0].firstChild); } function xmlStr2Doc(str){ var xml; if(typeof(DOMParser) == 'undefined'){ xml=new ActiveXObject("Microsoft.XMLDOM"); xml.async="false"; xml.loadXML(str); }else{ var domParser = new DOMParser(); xml = domParser.parseFromString(str, 'application/xml'); } return xml; } function __parseWDDXnode(n){ var val; switch(n.tagName){ case 'string': val = __parseWDDXstring(n); break; case 'number': val = parseInt(n.firstChild.data); break; case 'boolean': val = n.getAttribute('value'); break; case 'dateTime': val = Date(n.firstChild.data); break; case 'array': val = __parseWDDXarray(n); break; case 'struct': val = __parseWDDXstruct(n); break; case 'recordset': val = __parseWDDXrecordset(n); break; case 'binary': val = n.firstChild.data; break; case 'char': val = __parseWDDXchar(n);; break; case 'null': val = ''; break; default: val = n.tagName; break; } return val; } function __parseWDDXstring(node){ var items = node.childNodes; var str = ''; for(var x=0;x < items.length;x++){ if(typeof(items[x].data) != 'undefined') str += items[x].data; else str += __parseWDDXnode(items[x]); } return str; } function __parseWDDXchar(node){ switch(node.getAttribute('code')){ case '0d': return '\r'; case '0c': return '\f'; case '0a': return '\n'; case '09': return '\t'; } } function __parseWDDXarray(node){ var items = node.childNodes; var arr = new Array(); for(var i=0;i < items.length;i++){ arr[i] = __parseWDDXnode(items[i]); } return arr; } function __parseWDDXstruct(node){ var items = node.childNodes; var obj = new Object(); for(var i=0;i < items.length;i++){ obj[items[i].getAttribute('name').toLowerCase()] = __parseWDDXnode(items[i].childNodes[0]); } return obj; } function __parseWDDXrecordset(node){ var qry = new Object(); var fields = node.getElementsByTagName("field"); var items; var dataType; var values; for(var x = 0; x < fields.length; x++){ items = fields[x].childNodes; values = new Array(); for(var i = 0; i < items.length; i++){ values[values.length] = __parseWDDXnode(items[i]); } qry[fields[x].getAttribute('name').toLowerCase()] = values; } return qry; }
//END: WDDX deserializer functions

/*--- END: RESPONSE PARSING FUNCTIONS ---*/


/*--- BEGIN: REQUEST PARAMETER FUNCTIONS ---*/
  function toQueryString(obj){
    //determine the variable type
    if(typeof(obj) == 'string')
      return obj;
    if(typeof(obj) == 'object'){
      if(typeof(obj.elements) == 'undefined')//It's an Object()!
        return object2queryString(obj);
      else //It's a form!
        return form2queryString(obj);
    }  
  }
  
  function object2queryString(obj, parent){
    // Modified by Patrick (patrick [dot] depalma [at] gmail [dot] com) to scan an object recursivelly
    if (typeof parent == "undefined") parent = "";
    var ar = new Array();
    for(var x in obj) {
      if (typeof obj[x] == "object")
        ar[ar.length] = object2queryString(obj[x], x);
      else
        ar[ar.length] = ((parent)?parent+"["+x+"]":x)+'='+obj[x];
    }
    return ar.join('&');
  }
  
  function form2queryString(form){
    var obj = new Object();
    var ar = new Array();
    for(var i=0;i<form.elements.length;i++){
      try {
        elm = form.elements[i];
        nm = elm.name;
        if(nm != ''){
          switch(elm.type.split('-')[0]){
            case "select":
              for(var s=0;s<elm.options.length;s++){
                if(elm.options[s].selected){
                  if(typeof(obj[nm]) == 'undefined') obj[nm] = new Array();
                  obj[nm][obj[nm].length] = escape(elm.options[s].value);
                }  
              }
              break;
            
            case "radio":
              if(elm.checked){
                if(typeof(obj[nm]) == 'undefined') obj[nm] = new Array();
                obj[nm][obj[nm].length] = escape(elm.value);
              }  
              break;
            
            case "checkbox":
              if(elm.checked){
                if(typeof(obj[nm]) == 'undefined') obj[nm] = new Array();
                obj[nm][obj[nm].length] = escape(elm.value);
              }  
              break;
            
            default:
              if(typeof(obj[nm]) == 'undefined') obj[nm] = new Array();
              obj[nm][obj[nm].length] = escape(elm.value);
              break;
          }
        }
      }catch(e){}
    }
    for(x in obj) ar[ar.length] = x+'='+obj[x].join(',');
  return ar.join('&');
  }
/*--- END: REQUEST PARAMETER FUNCTIONS ---*/


//IE likes to cache so we will fix it's wagon!
function noCache(url){
  var qs = new Array();
  var arr = url.split('?');
  var scr = arr[0];
  if(arr[1]) qs = arr[1].split('&');
  //qs[qs.length]='nocache='+new Date().getTime();
return scr+'?'+qs.join('/&');
}

function popWait() {
  // Function extended by Patrick S. de Palma
  var proc = $("JSMX_loading");
  if( proc == null ) {
    // Cria DIV
    var p = document.createElement("div");
    p.id = "JSMX_loading";
    p = document.body.appendChild(p);
    
    // Imagem
    var im    = new Image();
    im        = popWait.preload_image;
    im.hspace = 0;
    im.align  = "left";
    p.appendChild(im);

    // Inclui texto
    p.innerHTML += "&nbsp;&nbsp;" + jsmx.loadingMsg;
  } else {
    proc.innerHTML = proc.innerHTML.replace(/(&nbsp;&nbsp;).*/, '$1' + jsmx.loadingMsg);
    proc.style.display = 'block';
  }
}

// Preload image
popWait.img = "/fw/img/indicator.gif";
popWait.preload_image = new Image();
popWait.preload_image.src = popWait.img; 

function killWait(){
  var proc = $("JSMX_loading");
  if( proc != null ) proc.style.display = 'none';
}

function onError(str) { alert(str); }
function $(id){ return document.getElementById(id); }
