function XmlRpc( url ){
	this.url = url;
this.call = function(){
	
	var args = this.call.arguments.length;
	if(args == 0 ){
		throw new Error('No method name given');
		return false;
	}
	var m = arguments[0];
	
	var msg = new XMLRPCMessage( m );
	var i = 1;
	for(i = 1; i< args; i++ )	{
		msg.addParameter( arguments[i] );
	}
	
	var xmlDoc = HttpClient.xml(this.url, msg.xml() );
	
	this.parseXML( xmlDoc );
	
	//alert(this.res);
	if( !this.res ){
		
		if( this.res === false ){
			return false;
		}
		throw new Error( 'Unkonow error' );
	}
	
	
	var e_t = new Error('t', 1);
	
	if( this.isException ){
		e = new Error();
		e.message = this.res.faultString;
		e.number = this.res.faultCode;
		/*
		if( e_t.message === 't' ){
			e =  new Error( this.res.faultString, this.res.faultCode );
		}else{
			e = new Error( this.res.faultCode, this.res.faultString );
			
		}
		*/
		throw e;
	}
	return this.res;
}

this.String = function( node ){
	return new String( node.firstChild.nodeValue );
}

this.Integer = function( node ){
	try{
		return parseInt( node.firstChild.nodeValue );
	}catch(e){
	}
}

this.Date = function( node ){
	dateString = node.firstChild.nodeValue;
	try{
		var re = /(\d\d\d\d)(\d\d)(\d\d)T(\d\d):(\d\d):(\d\d)/
		var result = re.exec (dateString)
		month=new Number(result[2])
		return new Date(result[1],month-1,result[3],result[4],result[5],result[6])
	}catch(e){
	}
}

this.Boolean = function( node ){
	var value = node.firstChild.nodeValue;
	if( value == '1' ){
		return true
	}
	if( value == 'true' ){
		return true;
	}
	return false;
}

this.Array = function( node ){
	var myNode =  node;//node.firstChild;
	var mydata = new Array();
	var children = node.getElementsByTagName('value');
	for(var i=0; i<children.length; i++){
			mydata.push( this.Param( children[i] ) );
	}	
	return mydata;
}

this.Struct = function( node ){
	var myArray = new Array();
	myStruct = new Object();
	var myNode = node;
	var children = node.getElementsByTagName('member');
	for(var i=0; i<children.length; i++){
			 this.StructMember( children[i], myStruct );
	}
	return myStruct;
}

this.StructMember = function( node, Struct ){
	var myNames = node.getElementsByTagName('name');
	var myValues = node.getElementsByTagName('value');
	var myNode = myNames[0].firstChild.nodeValue;
	
	Struct[myNode] = this.Param( myValues[0] ); 
	return Struct;
}

this.Fault = function( node ){
	var firstChild = this.firstChild( node );
	var theTagName =  firstChild.tagName;
	if( theTagName == 'struct' ){
		this.isException = true;
		
		return this.Struct( node ) ;
	}
}

this.firstChild = function( node ){
	if( node.nodeType == 3 ){
		return node;
	}
	
	var len = node.childNodes.length;
	if( len == 0 ){
		return node;
	}
	for(var i=0; i< len; i++){
		if( typeof( node.childNodes ) == 'function' ){
			var mynode = node.childNodes(i) 
		}else{
			var mynode = node.childNodes[i] ;
		}
			
		if( mynode.nodeType == 1 ){
			return mynode;
		}
	}		
	return null;
}


this.Param = function( node ){
	var firstChild = this.firstChild( node );
	var theTagName =  firstChild.tagName;

	if( theTagName == 'string' ){
		return this.String( firstChild );
	}
	
	if( theTagName == 'int' || theTagName == 'i4' ){
		return( this.Integer( node.firstChild ) );
	}
	
	if( theTagName == 'boolean' ){
		return this.Boolean( node.firstChild );
	}
	
	if( theTagName == 'array' ){
		return( this.Array( node.firstChild ) );
	}
	
	if( theTagName == 'struct' ){
		return( this.Struct( node ) );
	}

	if( theTagName == 'dateTime.iso8601' ){
		return( this.Date( firstChild ) );
	}

}

this.parseXML = function( xmlDoc ){
	if( document.all ){
		this.traverse( xmlDoc.documentElement );
	}else{
		this.traverse( xmlDoc.firstChild  );
	}
}

this.traverse = function( tree ) {
	if( tree.hasChildNodes() ) {
		var nodes=tree.childNodes.length;
		for(var i=0; i<tree.childNodes.length; i++){
			if( typeof( tree.childNodes ) == 'function' ){
				var node = tree.childNodes(i) 
			}else{
				var node = tree.childNodes[i] ;
			}
			
			if( tree.tagName == 'fault' ){
				if( node.nodeType == 1) {
					this.res = this.Fault( node );
					return true;
				}
			}
			if( tree.tagName == 'param' ){
				if( node.nodeType == 1) {
					
					this.res = this.Param( node );
					return true;
				}
			}
			this.traverse ( node );
		}	
	}
}


}

	


HttpClient = new function(){};
HttpClient.Response = null;
HttpClient.xml = function( url, content ){
	this.Request( url, content );
	return this.http.responseXML;
}

HttpClient.getJs = function(url, callback){
	var sel1 = null;
	try{
		s1el = document.getElementById(url);
	}catch(e){
	}
	if( s1el ){
		s1el.parentNode.removeChild(s1el);
	}
	
	try{
		var s = document.createElement("SCRIPT");
		s.id = url;
		
		var h = document.getElementsByTagName("head").item(0);
		var cd = new Date().getTime();
		s.src = url+'&callback='+callback+'&t='+cd;
		h.appendChild(s);
	}catch(e){
		alert(e);
	}
};


HttpClient.Request = function( url, content ){
	if( !content ){
		content = null;
	}
	
	this.http = HttpClient.Http();	
	//alert(this.http);
	var done = false;
	var hc = this;
	var checkState = function(){
		
		if( hc.http.readyState != 4 ){
			return;
		}
	
		done = HttpClient.checkResponse();
		if( done ){
			return;
		}
	}
	
    this.http.onreadystatechange = checkState;
    this.http.open('POST', url, false);
    
    this.http.send(content);
}

HttpClient.checkResponse = function(){
	 
	  if ( this.http.status == 200 ){
	  	this.Response = HttpClient.http.responseXML;
		return true;
	  }
	  return false;
}

HttpClient.Http = function(){
	req = false;
    // branch for native XMLHttpRequest object
    if(window.XMLHttpRequest) {
    	try {
			req = new XMLHttpRequest();
        } catch(e) {
			req = false;
        }
    // branch for IE/Windows ActiveX version
    } else if(window.ActiveXObject) {
       	try {
        	req = new ActiveXObject("Msxml2.XMLHTTP");
      	} catch(e) {
        	try {
          		req = new ActiveXObject("Microsoft.XMLHTTP");
        	} catch(e) {
          		req = false;
        	}
		}
    }
	if(req) {
		return req;
	}
}


/*

xmlrpc.js beta version 1
Tool for creating XML-RPC formatted requests in JavaScript

Copyright 2001 Scott Andrew LePera
scott@scottandrew.com
http://www.scottandrew.com/xml-rpc

License: 
You are granted the right to use and/or redistribute this 
code only if this license and the copyright notice are included 
and you accept that no warranty of any kind is made or implied 
by the author.

*/

function XMLRPCMessage(methodname){
  this.method = methodname||"system.listMethods";
  this.params = [];
  return this;
}

XMLRPCMessage.prototype.setMethod = function(methodName){
  if (!methodName) return;
  this.method = methodName;
}

XMLRPCMessage.prototype.addParameter = function(data){
  if (arguments.length==0) return;
  this.params[this.params.length] = data;
}

XMLRPCMessage.prototype.xml = function(){

  var method = this.method;
  
  // assemble the XML message header
  var xml = "";
  
  xml += "<?xml version=\"1.0\"?>\n";
  xml += "<methodCall>\n";
  xml += "<methodName>" + method+ "</methodName>\n";
  xml += "<params>\n";
  
  // do individual parameters
  for (var i = 0; i < this.params.length; i++){
    var data = this.params[i];
    xml += "<param>\n";

    xml += "<value>" + XMLRPCMessage.getParamXML(XMLRPCMessage.dataTypeOf(data),data) + "</value>\n";
    
    xml += "</param>\n";
  }
  
  xml += "</params>\n";
  xml += "</methodCall>";
  
  return xml; // for now
}

XMLRPCMessage.dataTypeOf = function (o){
  // identifies the data type
  var type = typeof(o);
  type = type.toLowerCase();
  switch(type){
    case "number":
      if (Math.round(o) == o) type = "i4";
      else type = "double";
      break;
    case "object":
      var con = o.constructor;
      if (con == Date) type = "date";
      else if (con == Array) type = "array";
      else type = "struct";
      break;
  }
  return type;
}

XMLRPCMessage.doValueXML = function(type,data){
  var xml = "<" + type + ">" + data + "</" + type + ">";
  return xml;
}

XMLRPCMessage.doBooleanXML = function(data){
  var value = (data==true)?1:0;
  var xml = "<boolean>" + value + "</boolean>";
  return xml;
}

XMLRPCMessage.doDateXML = function(data){
  var xml = "<dateTime.iso8601>";
  xml += dateToISO8601(data);
  xml += "</dateTime.iso8601>";
  return xml;
}

XMLRPCMessage.doArrayXML = function(data){
  var xml = "<array><data>\n";
  for (var i = 0; i < data.length; i++){
    xml += "<value>" + XMLRPCMessage.getParamXML(XMLRPCMessage.dataTypeOf(data[i]),data[i]) + "</value>\n";
  }
  xml += "</data></array>\n";
  return xml;
}

XMLRPCMessage.doStructXML = function(data){
  var xml = "<struct>\n";
  for (var i in data){
    xml += "<member>\n";
    xml += "<name>" + i + "</name>\n";
    xml += "<value>" + XMLRPCMessage.getParamXML(XMLRPCMessage.dataTypeOf(data[i]),data[i]) + "</value>\n";
    xml += "</member>\n";
  }
  xml += "</struct>\n";
  return xml;
}

XMLRPCMessage.getParamXML = function(type,data){
  var xml;
  switch (type){
    case "date":
      xml = XMLRPCMessage.doDateXML(data);
      break;
    case "array":
      xml = XMLRPCMessage.doArrayXML(data);
      break;
    case "struct":
      xml = XMLRPCMessage.doStructXML(data);
      break;
	  case "boolean":
      xml = XMLRPCMessage.doBooleanXML(data);
      break;
    default:
      xml = XMLRPCMessage.doValueXML(type,data);
      break;
  }
  return xml;
}

function dateToISO8601(date){
  // wow I hate working with the Date object
  var year = new String(date.getYear());
  var month = leadingZero(new String(date.getMonth()));
  var day = leadingZero(new String(date.getDate()));
  var time = leadingZero(new String(date.getHours())) + ":" + leadingZero(new String(date.getMinutes())) + ":" + leadingZero(new String(date.getSeconds()));

  var converted = year+month+day+"T"+time;
  return converted;
} 
  
function leadingZero(n){
  // pads a single number with a leading zero. Heh.
  if (n.length==1) n = "0" + n;
  return n;
}

