/* ****************************************************************************
Copyright 2006,
Todos los derechos Reservados
CM.COM E.U.
cmhenao@epm.met.co

El uso sin solicitud espresa a la compañia de esta libreria es una clara
violación a la propiedad intelectual y los derechos de autor.
**************************************************************************** */

/* ****************************************************************************
Autor: Jhon Alejandro Ramirez Velez
       Desarrollador
       Progress - WebSpeed
**************************************************************************** */

/* ****************************************************************************
Nombre Clase    : cRequest
Funcionalidad   : Provee la funcionalidad basica para el acceso a recursos
                  XML
Propiedades     :
  * xmlhttp     : Componente de conexion a http
  * busy        : Indica si el componente esta siendo usado por otra solicitud

Metodos         :
  * sendRequest :
    * Parametros: sMethod   : Metodo de Conexion a recurso HTTP ej. Post, Get

                : sUrl      : Url de Conexion

                : sData     : Datos a ser transferidos

                : responseHandler : Esta funcion es llamada cuando se acaba
                  de recibir por completo los datos de la solicitud, recibe
                  dos argumentos, un booleano que indica si la operacion fue
                  llevada a cabo y un objeto que contiene la respuesta
                  deserializada, del tipo responseObject

                : responseObject : Objecto que contendra la salida
                  deserializada

Ejemplos        : var r = new Requester();
                  var o = new obj
                  // obj contiene dos propiedades p1 y p2
                  // mensaje '<solicitud><p1/><p2/></solicitud>'
                  var o1 = new cRespuesta();
                  // o1 contiene dos propiedades  codigo y mensaje
                  // '<respuesta><codigo></codigo><mensaje></mensaje></respuesta>'
                  r.sendRequest("POST","/URL",o.serialize('solicitud'), Respuesta, o1);

                  function respuesta(succesfull, object){
                    if(succesfull){
                      alert(object.codigo);
                      alert(object.respuesta);
                    }
                  }
**************************************************************************** */
function _Node_getXML(oDom) {
  var objXMLSerializer = new XMLSerializer();
  var strXML = objXMLSerializer.serializeToString(oDom);
  return strXML;
}

function cRequester(){
  this.xmlhttp = null;
  this.state = 0;
  var self = this;
  this.init = init;  
  this.sendRequest = sendRequest;
  this.requestHTMLFragment = requestHTMLFragment;
  this.responseHTMLFragment = responseHTMLFragment;
  this.HTMLFragmentObject = null;
  this.genericHandler = responseHandler;
  this.responseHandler = null;
  this.busy = false;
  this.fault = false;
  this.faultMessage = "";
  this.queue = new Array();
  this.sessionid = "";

  this.init();

  function requestHTMLFragment(sMethod, sUrl, oContainer){
    this.HTMLFragmentObject = oContainer;    
    oTime = new Date();
    this.sendRequest(sMethod, sUrl, "", this.responseHTMLFragment, null);
  }
  
  function responseHTMLFragment(cargado, respuesta){
    try{
      this.HTMLFragmentObject.innerHTML = respuesta;
    }catch(e){
      this.HTMLFragmentObject.innerHTML = "<xmp>No se pudo Cargar " + e.message + respuesta + '</xmp>';
    }
    this.HTMLFragmentObject.loaded = true;
  }

  function init(){
    try{
      if(window.XMLHttpRequest) {
        this.xmlhttp = new XMLHttpRequest();
        return; 
      }      
      var versiones = ["Msxml2.XMLHTTP.7.0", "Msxml2.XMLHTTP.6.0", "Msxml2.XMLHTTP.5.0", "Msxml2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"];
      for(var i = 0; i < versiones.length; i++){
        try{
          this.xmlhttp = new ActiveXObject(versiones[i]);
        }catch(e){}
      }
    }catch(e){
      alert("Ocurrio un error\n" + e.message);
    }
  }

  function sendRequest(sMethod, sUrl, sData, responseHandler, responseObject){
    if (this.busy){
      var oQueue = new cQueueRequest();
      oQueue.sMethod = sMethod;
      oQueue.sUrl = sUrl;
      oQueue.sData = sData;
      oQueue.responseHandler = responseHandler;
      oQueue.responseObject = responseObject;
      this.queue.push(oQueue);
      return;
    }
    try{
      if(this.xmlhttp){
        this.xmlhttp.open(sMethod, sUrl, responseObject == null?false:true);
        if(self.sessionid != ""){
          this.xmlhttp.setRequestHeader("SESSION",self.sessionid);
        }        
        if(sMethod.toLowerCase() == "post" && responseObject != null){          
          this.xmlhttp.setRequestHeader("Content-type","text/xml");
          this.xmlhttp.setRequestHeader("Content-length", sData.length);
          this.xmlhttp.setRequestHeader("Connection","close");
          if (sData.indexOf("<?xml") == -1){
            sData = '<?xml version="1.0" encoding="utf-8" ?>' + sData;
            var xmlDoc = null;
            
            if(window.ActiveXObject)
              xmlDoc = new ActiveXObject("Msxml2.DOMDocument");
            
            try{
              xmlDoc.loadXML(sData);
            }catch(e){
              try{
                var parser = new DOMParser();
                xmlDoc = parser.parseFromString(sData,"text/xml");
                var ser = new XMLSerializer();
                xmlDoc.xml = ser.serializeToString(xmlDoc);
              }catch(e){
                
              }
            }            
          
            if (self.sessionid != "")
              xmlDoc.documentElement.setAttribute('sessionid', self.sessionid);
          }
        }else{
          sData = "";
        }
        this.xmlhttp.onreadystatechange = this.genericHandler;
        this.responseHandler = responseHandler;
        this.responseObject = responseObject;
        this.busy = true;
        if (xmlDoc){
//          alert(xmlDoc.xml);
          this.xmlhttp.send(xmlDoc.xml);
        }else{
//          alert(sData);
          this.xmlhttp.send(sData);
        }
      }else{
        alert("Su navegador no es compatible, por favor utilize la version más reciente");
      }
    }catch(e){
      alert(e.message);
    }
  }

  function responseHandler(){
    var d = new Date();
    try{
      if (self.xmlhttp.readyState == 4) {
        if (self.xmlhttp.status == 200){       
          if (self.xmlhttp.getResponseHeader('Content-Type') == "text/xml"){            
            if(self.xmlhttp.responseXML.xml == undefined && self.xmlhttp.responseXML.documentElement != null){
              self.xmlhttp.responseXML.xml = _Node_getXML(self.xmlhttp.responseXML);              
            }            
            if(self.xmlhttp.responseXML.xml != undefined && self.xmlhttp.responseXML.xml != "" ){
              self.fault = false;              
              if(self.xmlhttp.responseXML.documentElement != null){
                if (self.xmlhttp.responseXML.documentElement.tagName == "fault"){
                  self.fault = true;
                  var oFault = new cFault();
                  oFault.unserialize(self.xmlhttp.responseXML.documentElement);
                  self.responseHandler(false, oFault);
                }else{                                  
                  var s = new Date();
                  self.responseObject.unserialize(self.xmlhttp.responseXML.documentElement.childNodes[0]);
                  var r = new Date();
                  debugMessage("Tiempo Unserialize " + (r - s));                  
                  self.responseHandler(true,self.responseObject);
                  var j = new Date();
                  debugMessage("Tiempo Handler " + (j - r));
                }
              }else{
                self.responseHandler(false,self.xmlhttp.responseText);
            }
            }else{
              self.responseHandler(false,self.xmlhttp.responseText);
            }
          }else{            
            self.responseHandler(false,self.xmlhttp.responseText);
          }
        }else{
          if(self.xmlhttp.status == 404){
            self.responseHandler(false,"La pagina Solicitada no existe");
          }else{
            self.responseHandler(false,self.xmlhttp.responseText);          
          }          
        }
        self.busy = false;
      }
    }catch(e){
      alert(e.message);
      self.responseHandler(false,"Error Inesperado");
      self.busy = false;
    }
    var t = new Date();
    debugMessage("Tiempo Response Handler " + (t - d));
    if (self.queue.length > 0){
      var oQueue = self.queue.shift();
      self.sendRequest(oQueue.sMethod, oQueue.sUrl, oQueue.sData, oQueue.responseHandler, oQueue.responseObject);
    }
  }
}

function cQueueRequest(){
  this.sMethod = "";
  this.sUrl = "";
  this.sData = "";
  this.responseHandler = null;
  this.responseObject = null;
}

window.requester = new cRequester();

/* ****************************************************************************
Nombre Metodo   : _ArraySerialize
Funcionalidad   : Provee la funcionalidad basica para la serializacion XML
                  de un Array (Solo Para uso interno)
Argumentos      :
  * sElement    : Etiqueta xml que contendra todo el array
  * sChildElement: Etiqueta xml que contendra cada elemento en el array

Ejemplos        : var a = new Array();
                  // obj1 and obj2 descendant of obj: properties p1, p2
                  a.push(obj1);
                  a.push(obj2);
                  var xml = a.serialize('array','elemento');
                  // xml contains
                  // '<array><elemento><p1></p1><p2></p2></elemento><elemento><p1></p1><p2></p2></elemento></array>'
**************************************************************************** */
function _ArraySerialize(sElement, sChildElement){
  var xml = "<" + sElement + ">\n";
  for(var i = 0; i < this.length; i++){
    xml += this[i].serialize(sChildElement == undefined ? (this.childName == undefined ? "child" : this.childName) : sChildElement);
  }
  xml += "</" + sElement + ">\n";
  return xml;
}
Array.prototype.serialize = _ArraySerialize;

/* ****************************************************************************
Nombre Metodo   : _ObjectSerialize
Funcionalidad   : Provee la funcionalidad basica para la serializacion XML
                  de un objecto
Argumentos      :
  * sElement    : Etiqueta xml que contendra todo el objecto

Ejemplos        : function obj(){
                    this.p1 = "";
                    this.p2 = "";
                    this.a = new Array();
                    this.a.baseClass = obj;
                    this.a.tagName = 'hijos';
                  }

                  var obj1 = new obj();
                  var obj2 = new obj();
                  obj1.p1 = 'a';
                  obj1.p2 = 'b';
                  obj2.p1 = 'c';
                  obj2.p2 = 'd';
                  obj1.push(obj2);
                  var xml = obj1.serialize('objeto');
                  // xml contains
                  // '<objeto><p1>a</p1><p2>b</p2><a><hijos><p1>c</p1><p2>d</p2></hijos></a></objeto>'
**************************************************************************** */
function _ObjectSerialize(sElement){
  var xml = "<" + sElement + ">\n";
  for(var i in this){
    if (typeof(this[i]) == "function")
      continue;
    if (this[i] instanceof Array){
      xml += this[i].serialize(i,(this[i].tagName == undefined? "child" + i:this[i].tagName));
      continue;
    }
    if (this[i] instanceof Object){
      xml += '<' + i + '>\n';
      xml += this[i].serialize((this[i].childName == undefined? "child" + i:this[i].childName));
      xml += '</' + i + '>\n';      
      continue;
    }
    if(this[i] == undefined || this[i] == null) continue;
    xml += "<" + i + ">" + this[i].toString().xml_encode() + "</" + i + ">\n";
  }
  xml += "</" + sElement + ">\n";
  return xml;
}
Object.prototype.serialize = _ObjectSerialize;


/* ****************************************************************************
Nombre Metodo   : _UnSerializeArray
Funcionalidad   : Provee la funcionalidad basica para recomponer un Array
                  a partir de un Nodo Xml (Solo Para uso interno)
Argumentos      :
  * oNode       : Nodo XML

Ejemplos        : oNode // contiene '<array><elemento><p1>a</p1><p2>b</p2></elemento><elemento><p1>c</p1><p2>d</p2></elemento></array>'
                  function obj(){
                    this.p1 = "";
                    this.p2 = "";
                  }
                  var a = new Array();
                  a.baseClass = obj;
                  a.unserialize(oNode);
                  // a contiene dos elementos tipo obj con los valores
                  // a[0].p1 -> 'a'
                  // a[0].p2 -> 'b'
                  // a[1].p1 -> 'c'
                  // a[1].p2 -> 'd'
**************************************************************************** */
function _UnSerializeArray(oNode){
  for(var i = 0; i < oNode.childNodes.length; i++){
    if(this.baseClass == null || this.baseClass == undefined)
      var oObj = new Object();      
    else
      var oObj = new this.baseClass();
    oObj.unserialize(oNode.childNodes[i]);
    this.push(oObj);
  }
}
Array.prototype.unserialize = _UnSerializeArray;

/* ****************************************************************************
Nombre Metodo   : _UnSerializeObject
Funcionalidad   : Provee la funcionalidad basica para recomponer un objeto
                  a partir de un Nodo Xml (Solo Para uso interno)
Argumentos      :
  * oNode       : Nodo XML

Ejemplos        : oNode // contiene '<elemento><p1>a</p1><p2>b</p2></elemento>'
                  function obj(){
                    this.p1 = "";
                    this.p2 = "";
                  }
                  var o = new obj();
                  o.unserialize(oNode);
                  // o contiene
                  // o.p1 -> 'a'
                  // o.p2 -> 'b'
**************************************************************************** */
function _UnSerializeObject(oNode){
  for(var i = 0; i < oNode.childNodes.length; i++){
    if (this[oNode.childNodes[i].tagName] instanceof Array){
      this[oNode.childNodes[i].tagName].unserialize(oNode.childNodes[i]);
      continue;
    }
    if (this[oNode.childNodes[i].tagName] instanceof Object){
      this[oNode.childNodes[i].tagName].unserialize(oNode.childNodes[i].childNodes[0]);
      continue;
    }    
    this[oNode.childNodes[i].tagName] = oNode.childNodes[i].text;
//    alert(oNode.childNodes[i].tagName + ":" + this[oNode.childNodes[i].tagName]);
  }
}
Object.prototype.unserialize = _UnSerializeObject;

/* ****************************************************************************
Nombre Metodo   : messagebox
Funcionalidad   : Abre un area de mensajes al usuario con cualquier presentacion
                  La estructura del area de mensajes debe ser definida
                  con el id messageBox y en su interior un area etiquetada
                  con el id messageArea
Argumentos      :
  * sMessage    : Mensaje a mostrarse
  * bVisible    : Indica si el cuadro se muestra o se oculta

Ejemplos        : En el Archivo HTML '<div id="messageBox"><div id="messageArea"></div></div>'
                : message("Espere por favor...",true);
                : message("",false);
**************************************************************************** */
function messageBox(sMessage, bDisplay){
  oMsgBox = document.getElementById('messageBox');
  if (bDisplay){
    if (oMsgBox){
      var oMsg = document.getElementById('messageArea');
      oMsgBox.style.position = "absolute";
      oMsgBox.style.left = parseInt((document.body.offsetWidth) / 4);
      oMsgBox.style.top = parseInt((document.body.offsetHeight) / 3) + parseInt(document.body.scrollTop);
      oMsgBox.style.width = parseInt((document.body.offsetWidth) / 2);
      oMsg.innerText = sMessage;
      oMsgBox.style.display = "";
    }else{
      alert("Espere un momento por favor...\nEstamos realizando la solicitud");
    }
  }else{
    if (oMsgBox){
      oMsgBox.style.display = "none";
    }
  }
}


/* ****************************************************************************
Nombre Metodo   : _FormSerialize
Funcionalidad   : Provee la funcionalidad basica para serializar un
                  formulario (Solo Para uso interno)
Argumentos      :
  * sElemens    : Etiqueta XML

Ejemplos        : // Debe Inicializarse antes de hacer el llamado, solo una vez
                  document.form['forma'].serialize = _FormSerialize;

                  var xml = document.form['forma'].serialize('solicitud');
**************************************************************************** */
function _FormSerialize(sElement){
  if (sElement == null) {sElement = this.name};
  if (sElement == "") {sElement = this.name};
  if (sElement == "") {return ""};
  var xml = "<" + sElement + ">";
  for(var i = 0; i < this.elements.length; i++){
    if (this.elements[i].name == "") continue;
    switch(this.elements[i].type){
      case "select-multiple":
        var aSelected = new Array();
        for(var j = 0; j < this.elements[i].options.length; j++){
          if (this.elements[i].options[j].selected){
            aSelected.push(this.elements[i].options[j].value);
          }
        }
        xml += "<" + this.elements[i].name.toLowerCase() + ">" + escape(aSelected.join(',')) + "</" + this.elements[i].name.toLowerCase() + ">\n";
      break;
      default:
        xml += "<" + this.elements[i].name.toLowerCase() + ">" + escape(this.elements[i].value) + "</" + this.elements[i].name.toLowerCase() + ">\n";
      break;
    }
  }
  xml += "</" + sElement + ">";
  return xml;
}

/* ****************************************************************************
Nombre Metodo   : _FormUnSerialize
Funcionalidad   : Provee la funcionalidad basica para recomponer
                  formulario a partir de un nodo XML(Solo Para uso interno)
Argumentos      :
  * oNodo       : Nodo XML

Ejemplos        : // Debe Inicializarse antes de hacer el llamado, solo una vez
                  document.form['forma'].unserialize = _FormUnSerialize;

                  var xml = document.form['forma'].unserialize(oNode);
**************************************************************************** */
/*  function _FormUnSerialize(oNode){
    for(var i = 0; i < oNode.childNodes.length; i++){
      if (oNode.childNodes[i].childNodes.length > 0){
        continue;
      }
      this.elements.[oNode.childNodes[i].tagName] = oNode.childNodes[i].text;
    }
  }*/


function cFault(){
  this.code = 0;
  this.message = "";
}

function _xml_encode(){
  var sString = this.toString();
  sString = sString.replace(/&/g, "&amp;");
  sString = sString.replace(/</g, "&lt;");
  sString = sString.replace(/>/g, "&gt;");
  return sString;
}

String.prototype.xml_encode = _xml_encode; 

