//    XML-RPC Javascript client v1.0 based on vcXMLRPC 0.91

//    Copyright (C) 2000, 2001, 2002  Virtual Cowboys info@virtualcowboys.nl
//		
//		Author: Ruben Daniels <ruben@virtualcowboys.nl>
//		Version: 0.91
//		Date: 29-08-2001
//		Site: www.vcdn.org/Public/XMLRPC/
//    Modified by Balazs Zajacz <zaji@imind.hu> 12.05.2005. - 27.05.2005.

//
//    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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


//fuggosegek: 
if (typeof BROWSERDETECT == "undefined") {
  alert("(XMLRPC) BROWSERDETECT include missing");
}
if (typeof XMLHTTP == "undefined") {
  alert("(XMLRPC) XMLHTTP include missing");
}
//tobbszoros include:
if (typeof XMLRPC != "undefined") {
  alert("XMLRPC multiple insert!");
}
XMLRPC=true;


/** XML-RPC klienst megvalosito osztaly
  */
function XmlRpc() {
//  this.setDefaults();
//  this.readConfig(cfg); 
}


XmlRpc.prototype=new XmlHttp();          //konkret orokles
XmlRpc.prototype.constructor=XmlRpc;     //konstruktor beallitasa, ennek ellenere MyObject-et is hivja
XmlRpc.superclass=XmlHttp.prototype;     //ososztaly elerese, pl.: Employee.superclass.init.call(this, first, last, id);

/** A konstruktor teljes tartalma ebben a fuggvenyben van, ki kellett venni, hogy orokolt fuggvenyek tudjak hivni
  * @param cfg konfiguracios objektum
  */ 
XmlRpc.prototype.init = function (cfg) {
  //ososztaly init hivasa
  this.functionName=null;
  this.functionParams=null;
  this.userCallback=null;

  XmlRpc.superclass.init.call(this,cfg);  //setdefaults es readconfig fuggvenyeket is hivja


  //ezek os initben lefutnak
//  this.setDefaults();
//  this.readConfig(cfg);
    


  if (this.userCallback == null) {
    this.onError(new Error("callback undefined"),null);
    return null;
  }
  if (this.functionName == null) {
    this.onError(new Error("functionName undefined"),null);
    return null;
  }
  if (this.functionParams == null) {
    this.onError(new Error("functionParams undefined"),null);
    return null;
  } 

                                                  
  this.method="POST";             //postolunk
  this.requestHeaders["User-Agent"]="iMind XML-RPC javascript client v1.0 ("+navigator.userAgent+")";
//  this.requestHeaders["User-Agent"]="iMind XML-RPC javascript client v1.0";
  this.requestHeaders["Content-type"]="text/xml";
  this.callback=this.onComplete;  //ezt hivja meg, ha minden jol lejott



  return true;
}

/** Az alapertelmezett beallitasok felulirasa ervenyes beallitasokkal
  * @param cfg a beallitasok objektuma
  */
XmlRpc.prototype.readConfig = function (cfg) {
  if (cfg.id != null) {
    this.id=cfg.id;
  }
  if (typeof cfg.functionName == 'string' && cfg.functionName != '') {
    this.functionName=cfg.functionName;
  }
  if (typeof cfg.functionParams == 'object') {
    this.functionParams=cfg.functionParams;
  }
  if (typeof cfg.callback == 'function') {
    this.userCallback=cfg.callback;
  }
  
 
  XmlRpc.superclass.readConfig.call(this,cfg);
}

/** Osszerakja az XML-RPC hivas xml-t es meghivja ososztaly send metodusat
  */ 
XmlRpc.prototype.send = function () {
  var data=XmlRpc.encode(this.functionName,this.functionParams);
//  alert("send: "+data);
  XmlRpc.superclass.send.call(this,data);
}

/** Belso callback metodus, ez fut le, ha megerkezett a valasz, ha jo is, akkor hivja a user callback-et
  * @param xmlhttpreq a kapcsolat XmlHttpRequest objektuma
  */
XmlRpc.prototype.onComplete = function (xmlhttpreq) {
//  var t1=new Date().getTime();
  var data=XmlRpc.decode(xmlhttpreq.responseXML);
//  var t2=new Date().getTime();
//  alert((t2-t1)+" ms");

//  alert(varDump(data,false,true));
//  alert(xmlhttpreq.responseText);
//  alert(xmlhttpreq.getAllResponseHeaders());
//  ttt=document.createElement("textarea");
//  ttt.appendChild(document.createTextNode(xmlhttpreq.responseText));
//  document.body.appendChild(ttt);
  if (data == null) {
    //XML-RPC hiba volt   
    this.onError(new Error("XML-RPC protocol error"),this);
  } else if (xmlhttpreq.responseXML.getElementsByTagName("fault").length > 0) {
    //ha hibas volt a hivas: onError
    this.onError(new Error("XML-RPC error: ("+data["faultCode"]+") "+data["faultString"]),this);
  } else {
    //ha jo volt
    this.userCallback(data);
  }

  //kifuzes
  XmlRpc.remove(this.id);
}

/** Ososztaly metodusanak feluldefinialasa, meghivja az eredetit, majd kifuzi a hivasi objektumot a statikus tarolobol
  */
XmlRpc.prototype.transferTimeout = function () {
  XmlRpc.superclass.transferTimeout.call(this);

  //kifuzes
  XmlRpc.remove(this.id);
}


/** Ezzel a statikus fuggvennyel lehet hivni egy tavoli fuggvenyt XML-RPC segitsegevel, peldanyosit egy XmlRpc objektumot, inicializalja, majd elkuldi a kerest
  * @param cfg a konfiguracios objektum
  * @return ha jo volt minden, akkor a hivas egyedi azonositojat adaj vissza, ha nem akkor, null-t
  */
XmlRpc.call = function (cfg) {
  if (typeof this.calls == 'undefined') {
    this.calls=new Array();
  }
  if (XmlHttp.isSupported()) {
    var id=this.calls.length;
    cfg.id=id;
    var xmlrpc=new XmlRpc();
    if (xmlrpc.init(cfg)) {
      this.calls[this.calls.length]=xmlrpc;
    
      //xml-rpc kuldese          
      xmlrpc.send();
      
      return id;
    }
  }
  return null;
}

/** Le lehet allitani egy kerest, ennek sok ertelme talan nincsen, hiszen timeout-ot beallitva is le lehet allni
  * @param id a hivasi objektum id-ja
  */
XmlRpc.abort = function (id) {
  if (id && this.calls[id]) {
    this.calls[id].abort();
    XmlRpc.remove(id);
  }
}

/** Egy hivasi objektum (XmlRpc peldany) kifuzese a statikus tarolobol
  * @param id a hivasi objektum id-ja
  */
XmlRpc.remove = function (id) {
//  alert("remove "+id);
  if (this.calls[id]) {
    this.calls[id]=null;
  }
}



/////////////////////////////////////////vcXmlRpc-bol fuggvenyek*******************************************
/** Osszerakja az XML-RPC hivasi xml-t
  * @param functionName a tavoli fuggveny neve
  * @param functionParams a tavoli fuggveny parametereinek tombje
  * @return a hivasi xml string-je
  */
XmlRpc.encode = function (functionName,functionParams) {
  var str='<?xml version="1.0" encoding="UTF-8"?>\n<methodCall><methodName>'+functionName+'</methodName>\n<params>\n';
  for(var i=0 ; i < functionParams.length ; ++i){
    str+='<param><value>'+this.getXml(functionParams[i])+'</value></param>\n';
  }
  str+='</params></methodCall>';
                          
  return str;
}

/** Egy valtozot konvertal at javascriptbol XML-RPC stringe
  * @param obj a valtozo
  * @return a valtozot reprezentalo XML-RPC xml reszlet
  */
XmlRpc.getXml = function(obj){
  if (typeof obj == "function") {
    return false.toXmlRpc();
  } else if(obj == null || obj == undefined || (typeof obj == "number" && !isFinite(obj))) {
    return false.toXmlRpc();
  } else {
    return obj.toXmlRpc();
  }
}
                                                       


/** Az XML-RPC valasz xml-t visszaalakitja javascript valtozora
  * @param xml a valasz xml
  * @return az atalakitott ertek
  */
XmlRpc.decode = function (xml) {
  var ret=null;
  if(xml) {
//    alert(getDomTree(xml,0));

    //Check for XMLRPC Errors
    var rpcErr=xml.getElementsByTagName("fault");
    if(rpcErr.length > 0){
      ret=this.toObject(this.getNode(rpcErr[0], [0],0)); // rpcErr[0].firstChild);
    } else {    
      //handle method result
      var main=xml.getElementsByTagName("param");
      if (main.length > 0) {
        var ret=this.toObject(this.getNode(main[0], [0],0));
      }
    }
  }
  return ret;
}

/** A kapott xml reszfaban megkeresi a parameterkent index-el meghatarozott elementet (vagyis nem textnode-ot es tarsait)
  * @param data az xml reszfa
  * @param tree az indexek tombje, pl.: [0,1] jelenti azt, hogy az elso szinten az elso element kell, majd ennek gyerekei kozul a masodik element kell
  * @return a megtalalt element
  */
XmlRpc.getNode = function(data, tree, index) {
  var nc = 0;//nodeCount
  //node = 1
  if (data != null) {

    //ez csak akkor megy, ha nincsen formazva az XML!!!
    data=data.childNodes[tree[index]];
    if (index < tree.length - 1){
      data=this.getNode(data, tree, index+1);
    }
    return data;
/*    
    for (var i=0 ; i < data.childNodes.length ; ++i) {
      if (data.childNodes[i].nodeType == 1) {
        if (nc == tree[index]){
          data=data.childNodes[i];
          if (index < tree.length - 1){
            data=this.getNode(data, tree, index+1);
          }
          return data;
        }
        ++nc;
      }
    }
*/
    
  }
  return false;
};


/** Az XML-RPC valasz xml-ben szereplo value tagek tartalmat atalakitja megfelelo javascript valtozova
  * @param data xml reszfa (value tag gyereke)
  * @return a konvertalt javascript ertek
  */
XmlRpc.toObject=function(data) {
  var ret, i;
  switch(data.tagName){
    case "string":
//      return (data.firstChild) ? new String(data.firstChild.nodeValue) : "";
      return (data.firstChild) ? data.firstChild.nodeValue : "";
    break;
    case "int":
    case "i4":    
      return (data.firstChild) ? parseInt(data.firstChild.nodeValue) : 0;
    case "double":
//      return (data.firstChild) ? new Number(data.firstChild.nodeValue) : 0;
      return (data.firstChild) ? parseFloat(data.firstChild.nodeValue) : 0;
    break;
    case "dateTime.iso8601":
      /*
         Have to read the spec to be able to completely 
         parse all the possibilities in iso8601
         07-17-1998 14:08:55
         19980717T14:08:55
       */

      var sn = (isIE) ? "-" : "/";

    if(/^(\d{4})(\d{2})(\d{2})T(\d{2}):(\d{2}):(\d{2})/.test(data.firstChild.nodeValue)){;//data.text))
      return new Date(RegExp.$2 + sn + RegExp.$3 + sn + 
          RegExp.$1 + " " + RegExp.$4 + ":" + 
          RegExp.$5 + ":" + RegExp.$6);
    } else {
      return new Date();
    }

    break;
    case "array":
      data = this.getNode(data, [0], 0);

    if(data && data.tagName == "data"){
      ret = new Array();

      var i = 0;
      while(child = this.getNode(data, [i], 0)){
        //        ret.push(this.toObject(child));
        ret[i]=this.toObject(child);
        ++i;
      }

      return ret;
    } else {
      //      this.handleError(new Error("Malformed XMLRPC Message1"));
      return false;
    }
    break;
    case "struct":
      ret = {};

    var i = 0;
    while(child = this.getNode(data, [i++])){
      if(child.tagName == "member"){
        ret[this.getNode(child, [0], 0).firstChild.nodeValue] = this.toObject(this.getNode(child, [1], 0));
      } else {
//        this.handleError(new Error("Malformed XMLRPC Message2"));
        return false;
      }
    }

    return ret;
    break;
    case "boolean":
//      return Boolean(isNaN(parseInt(data.firstChild.nodeValue)) ? (data.firstChild.nodeValue == "true") : parseInt(data.firstChild.nodeValue));
      return (isNaN(parseInt(data.firstChild.nodeValue)) ? (data.firstChild.nodeValue.tolowerCase() == "true") : parseInt(data.firstChild.nodeValue) != 0);

                                                                                                          break;
    case "base64":
//      return this.decodeBase64(data.firstChild.nodeValue);
      return "";
    break;
    case "value":
      child = this.getNode(data, [0],0);
//    return (!child) ? ((data.firstChild) ? new String(data.firstChild.nodeValue) : "") : this.toObject(child);
    return (!child) ? ((data.firstChild) ? data.firstChild.nodeValue : "") : this.toObject(child);

    break;
    default:
    //				this.handleError(new Error("Malformed XMLRPC Message: " + data.tagName));
    //				return false;
    return "";
    break;		
  }
}



/** Kulonbozo tipusok konverzios fuggvenyei, javascript erteket konvertalnak XML-RPC xml stringre
  */
Object.prototype.toXmlRpc = function(){
  var wo=this.valueOf();  
  if(wo.toXmlRpc == this.toXmlRpc){
    retstr="<struct>";    
    for(prop in this){
      if(typeof wo[prop] != "function") {
        retstr+="<member><name>" + prop + "</name><value>" + XmlRpc.getXml(wo[prop]) + "</value></member>";
      }
    }
    retstr+="</struct>";    
    return retstr;
  } else {
    return wo.toXmlRpc();
  }
}

String.prototype.toXmlRpc = function(){
  //<![CDATA[***your text here***]]>
  return "<string><![CDATA["+this.replace(/\]\]/g,"] ]")+"]]></string>";
  //.replace(/</g, "&lt;").replace(/&/g, "&amp;")
}

Number.prototype.toXmlRpc = function(){
  if(this == parseInt(this)){
    return "<int>" + this + "</int>";
  } else if(this == parseFloat(this)){
    return "<double>" + this + "</double>";
  } else {
    return false.toXmlRpc();
  }
}

Boolean.prototype.toXmlRpc = function(){
  if (this) return "<boolean>1</boolean>";
  else return "<boolean>0</boolean>";
}

Date.prototype.toXmlRpc = function(){
  //Could build in possibilities to express dates 
  //in weeks or other iso8601 possibillities
  //hmmmm ????
  //19980717T14:08:55
  return "<dateTime.iso8601>"+doYear(this.getUTCYear())+doZero(this.getMonth())+doZero(this.getUTCDate())+"T"
    +doZero(this.getHours())+":"+doZero(this.getMinutes())+":"+doZero(this.getSeconds())+"</dateTime.iso8601>";
  
  function doZero(nr) {
    nr=String("0" + nr);
    return nr.substr(nr.length-2, 2);
  }
  
  function doYear(year) {
    if(year > 9999 || year < 0) 
      XMLRPC.handleError(new Error("Unsupported year: " + year));
    
    year=String("0000" + year);
    return year.substr(year.length-4, 4);
  }
}

/** Ez csak a tiszta tombre mukodik, azaz szam indexekkel van feltoltve
  * ha asszociativ a tomb, akkor nem lesz jo :(, akkor object-et kene alkalmazni
  */
Array.prototype.toXmlRpc = function(){
  var retstr="<array><data>";
  for(var i=0 ; i < this.length ; ++i){
    retstr+="<value>"+XmlRpc.getXml(this[i])+"</value>\n";
  }
  return retstr+"</data></array>";
}


