/* ========================================================================= */
var WS = {
  Version :   '0.1 (beta)',
  Author :    'Gwen Schmitt',
  Revision :  '2008-04-16T09:50:00'
};

WS.Service = function(uri) {
    this.uri = uri;
  }
WS.Service.prototype.createSOAPEnvelope = function(soapVersion, soapAction) {
    if (soapVersion == "1.2") {
      var document = XML.createDocument(SOAP.ENVELOPE_12_NAMESPACE, "Envelope");
      return new SOAP.Envelope(document);
    } else if (soapVersion == "1.1") {
      var document = XML.createDocument(SOAP.ENVELOPE_11_NAMESPACE, "Envelope");
      var soapEnvelope = new SOAP.Envelope(document);
      soapEnvelope.soapAction = soapAction;
      return soapEnvelope;
    }
  }
WS.Service.prototype.invoke = function(soapEnvelope, onResult, onFault, username, password) {
    var xmlHttpRequest = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
    xmlHttpRequest.open("POST", this.uri, true, username, password);
    if (soapEnvelope.namespace.equals(SOAP.ENVELOPE_12_NAMESPACE))
      xmlHttpRequest.setRequestHeader("Content-Type", "application/soap+xml; charset=utf-8");
    else {
      xmlHttpRequest.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
      xmlHttpRequest.setRequestHeader("SOAPAction", soapEnvelope.soapAction);
    }
    xmlHttpRequest.setRequestHeader("X-Requested-With", "XMLHttpRequest");
    xmlHttpRequest.setRequestHeader("Accept", "application/xml, text/xml, */*");
    xmlHttpRequest.onreadystatechange = function(transport) {
      if (xmlHttpRequest.readyState == 4) {
        var xml = xmlHttpRequest.responseXML;
        if (xml) {
          if (!xml.documentElement) {
            try {
                xml = new ActiveXObject("Microsoft.XMLDOM");
                xml.async = "false";
                xml.validateOnParse = "false";
                xml.resolveExternals = "false";
                xml.loadXML(transport.responseText);
            } catch (e) {
                xml = new ActiveXObject("Msxml2.XMLDOM");
                xml.async = "false";
                xml.validateOnParse = "false";
                xml.resolveExternals = "false";
                xml.loadXML(transport.responseText);
            }
          }
          var responseEnvelope = new SOAP.Envelope(xml);
          
          if (onFault && xmlHttpRequest.status == 500) {
            onFault(responseEnvelope);
          } else {
            onResult(responseEnvelope);
          }
        }
      }
    };
    xmlHttpRequest.send(soapEnvelope.document);
  }

$PARAM = function(name, value) {
  return {name:name, value:value};
}

/* ========================================================================= */
var XML = {
  createDocument : function(namespace, localName) {
    try {
      var doc = new ActiveXObject('Msxml2.XMLDOM');
      var root = XML.createElementNS(doc, namespace, localName);
      doc.documentElement = root;
      return doc;
    } catch (e) {
      try {
        var doc = new ActiveXObject('Microsoft.XMLDOM')
        var root = XML.createElementNS(doc, namespace, localName);
        doc.documentElement = root;
        return doc;
      } catch (e) {
        return document.implementation.createDocument(
        namespace.uri,
        $QN(localName, namespace),
        null);
      }
    }
  },
  createElementNS : function(document, namespace, localName) {
    try {
      return document.createNode(1, $QN(localName, namespace), namespace.uri);
    } catch (e) {
      return document.createElementNS(namespace.uri, $QN(localName, namespace));
    }
  },
  createAttributeNS : function(document, namespace, localName) {
    try {
      return document.createNode(2, $QN(localName, namespace), namespace.uri);
    } catch (e) {
      return document.createAttributeNS(namespace.uri, $QN(localName, namespace));
    }
  },
  createText : function(document, value) {
    return document.createTextNode(value);
  },
  createCDATA : function(document, value) {
    return document.createCDATASection(value);
  },
  getElementsByTagNameNS : function(element, namespace, localName) {
    var nodeList = null;
    if(!element.getElementsByTagNameNS) {
      nodeList = new Array();
      var nodes = element.getElementsByTagName($QN(localName, namespace));
      for (var n = 0; n < nodes.length; n++) {
        if (nodes[n].namespaceURI == namespace.uri) {
          nodeList.push(nodes[n]);
        }
      }
    } else {
      nodeList = element.getElementsByTagNameNS(namespace.uri, localName);
    }
    return nodeList;
  },
  setAttributeNS : function(element, namespace, localName, value) {
    var attr = XML.createAttributeNS(element.ownerDocument, namespace, localName);
    attr.nodeValue= value;
    if (element.setAttributeNodeNS) {
      element.setAttributeNodeNS(attr);
    } else {
      element.setAttributeNode(attr);
    }
  },
  getAttributeNS : function(element, namespace, localName) {
    for (var n = 0; n < element.attributes.length; n++) {
      var attr = element.attributes[n];
      if ((localName == attr.baseName || localName == attr.localName) && namespace.uri == attr.namespaceURI) { 
        return attr.nodeValue;
      }
    }
    return null;
  },
  hasAttributeNS : function(element, namespace, localName) {
    for (var n = 0; n < element.attributes.length; n++) {
      var attr = element.attributes[n];
      if ((localName == attr.baseName || localName == attr.localName) && namespace.uri == attr.namespaceURI) { 
        return true;
      }
    }
    return false;
  },
  documentToString : function(document) {
    try {
      return new XMLSerializer().serializeToString(document);
    } catch (e) {
        return document.xml;
    }
  }
};

XML.namespaces = new Array();
XML.Namespace = function(uri, prefix) {
    this.uri = uri;
    this.prefix = prefix;
    XML.namespaces[uri] = this;
  }
XML.Namespace.prototype.equals = function(namespace) {
    return (namespace instanceof XML.Namespace) && namespace.uri == this.uri;
  }


$QN = function(localName)  {
    var namespace = arguments[1];
    if (namespace) {
      if (!(namespace instanceof XML.Namespace))
        namespace = XML.namespaces[arguments[1]];
      return namespace.prefix?namespace.prefix+':'+localName:localName;
    }
    return localName;
}

$NAMESPACE = function(uri, prefix)  { 
  return new XML.Namespace(uri, prefix);
}

/* ========================================================================= */
var SOAP = {
  ENVELOPE_11_NAMESPACE : $NAMESPACE("http://schemas.xmlsoap.org/soap/envelope/", "env"),
  ENVELOPE_12_NAMESPACE : $NAMESPACE("http://www.w3.org/2003/05/soap-envelope", "env")
};
SOAP.Element = function () {
    if (arguments[0]) {
      this.element = arguments[0];
      this.localName = (this.element.baseName)?this.element.baseName:this.element.localName,
      this.namespace = $NAMESPACE(this.element.namespaceURI, this.element.prefix);
    }
  }
  SOAP.Element.prototype.setAttribute = function(namespace, localName, value) {
    var attr = XML.setAttributeNS(this.element, namespace, localName, value);
  }
  SOAP.Element.prototype.getAttribute = function(namespace, localName) {
    return XML.getAttributeNS(this.element, namespace, localName);
  }
  SOAP.Element.prototype.hasAttribute = function(namespace, localName) {
    return XML.hasAttributeNS(this.element, namespace, localName);
  }
  SOAP.Element.prototype.setValue = function(value, cdata) {
    var doc = this.element.ownerDocument;
    if (cdata) {
      this.element.appendChild(XML.createCDATA(doc,value));
    } else {
      this.element.appendChild(XML.createText(doc,value));
    }
  }
  SOAP.Element.prototype.getValue = function() {
    return this.element.firstChild.nodeValue;
  }
  SOAP.Element.prototype.createChild = function(namespace, localName) {
    var doc = this.element.ownerDocument;
    var el = XML.createElementNS(doc, namespace, localName);
    this.element.appendChild(el);
    var ret = new SOAP.Element(el);
    return ret;
  }
  SOAP.Element.prototype.getChild = function(namespace, localName) {
    var nodes = XML.getElementsByTagNameNS(this.element, namespace, localName);
    var childnodes = new Array();
    for (var n = 0; n < nodes.length; n++) {
      childnodes.push(new SOAP.Element(nodes[n]));
    }
    return childnodes;
  }
  SOAP.Element.prototype.getChildNodes = function() {
    var nodes = this.element.childNodes;
    var childnodes = new Array();
    for (var n = 0; n < nodes.length; n++) {
      if (nodes[n].nodeType == 1) {
        childnodes.push(new SOAP.Element(nodes[n]));
      }
    }
    return childnodes;
  }


/* ========================================================================= */
SOAP.Envelope = function(document) {
    /*this.__proto__.constructor(document.documentElement);*/
    this.constructor(document.documentElement);
    this.document = document;
    this.soapAction = ""; // to be specify for SOAP version 1.1
  }
SOAP.Envelope.prototype = new SOAP.Element;
SOAP.Envelope.prototype.setValue = null;
SOAP.Envelope.prototype.getValue = null;
SOAP.Envelope.prototype.createChild = null;
SOAP.Envelope.prototype.createHeader = function() {
    if (!this.hasHeader()) {
      var doc = this.element.ownerDocument;
      var el = XML.createElementNS(doc, SOAP.ENV_NAMESPACE, "Header");
      if (this.element.firstChild) {
        this.element.insertBefore(el, this.element.firstChild);
      } else {
        this.element.appendChild(el);
      }
      return new SOAP.Header(el);
    } else {
      return this.getHeader();
    }
  }
SOAP.Envelope.prototype.getHeader = function() {
    for (var n = 0; n < this.element.childNodes.length; n++) {
      if (this.element.childNodes[n].nodeType == 1) {
        var el = this.element.childNodes[n];
        if (("Header" == el.baseName || "Header" == el.localName) && this.namespace.uri == el.namespaceURI) { 
          return new SOAP.Header(el);
        }
      }
    }
    return null;
  },
SOAP.Envelope.prototype.hasHeader = function() {
    for (var n = 0; n < this.element.childNodes.length; n++) {
      if (this.element.childNodes[n].nodeType == 1) {
        var el = this.element.childNodes[n];
        if (("Header" == el.baseName || "Header" == el.localName) && this.namespace.uri == el.namespaceURI) { 
          return true;
        }
      }
    }
    return false;
  }
SOAP.Envelope.prototype.createBody = function() {
    if (!this.hasBody()) {
      var doc = this.element.ownerDocument;
      var el = XML.createElementNS(doc, this.namespace, "Body");
      this.element.appendChild(el);
      return new SOAP.Body(el);
    } else {
      return this.get_body();
    }
  }
SOAP.Envelope.prototype.getBody = function() {
    for (var n = 0; n < this.element.childNodes.length; n++) {
      if (this.element.childNodes[n].nodeType == 1) {
        var el = this.element.childNodes[n];
        if (("Body" == el.baseName || "Body" == el.localName) && this.namespace.uri == el.namespaceURI) { 
          return new SOAP.Body(el);
        }
      }
    }
    return null;
  }
SOAP.Envelope.prototype.hasBody = function() {
    for (var n = 0; n < this.element.childNodes.length; n++) {
      if (this.element.childNodes[n].nodeType == 1) {
        var el = this.element.childNodes[n];
        if (("Body" == el.baseName || "Body" == el.localName) && this.namespace.uri == el.namespaceURI) { 
          return true;
        }
      }
    }
    return false;
  }


/* ========================================================================= */
SOAP.Header = function(element) {
    this.element = element;
  }
SOAP.Header.prototype = new SOAP.Element;
SOAP.Header.prototype.setValue = function() {};
SOAP.Header.prototype.getValue = function() {};

/* ========================================================================= */
SOAP.Body = function(element) {
    this.element = element;
  }
SOAP.Body.prototype = new SOAP.Element;
SOAP.Body.prototype.setValue = function() {}
SOAP.Body.prototype.getValue = function() {}
SOAP.Body.prototype.getFault = function() {
    for (var n = 0; n < this.element.childNodes.length; n++) {
      if (this.element.childNodes[n].nodeType == 1) {
        var el = this.element.childNodes[n];
        if (("Fault" == el.baseName || "Fault" == el.localName) && this.namespace.uri == el.namespaceURI) { 
          return new SOAP.Element(el);
        }
      }
    }
    return null;
  }
SOAP.Body.prototype.setRPC = function(method, params, encodingstyle) {
    var child = this.create_child(method);
    if (encodingstyle) {
      child.set_encoding_style(encodingstyle);
    }
    for (var n = 0; n < params.length; n++) {
      var param = params[n];
      var pchild = null;
      if (param.name instanceof WS.QName) {
        pchild = child.create_child(param.name);
      } else {
        pchild = 
          child.create_child(
            new WS.QName(param.name,method.namespace,method.prefix)
          );
      }
      if (param.value) {
        pchild.set_value(param.value);
      } else {
        pchild.set_attribute(SOAP.XSINIL,'true');
      }
      if (param.xsitype) {
        pchild.set_attribute(SOAP.XSIQNAME,param.xsitype.value_of());
      }
      if (param.encodingstyle) {
        pchild.set_encoding_style(param.encodingstyle);
      }
    }
  }

