1 include(bbq.ajax.AJAXRequest);
  2 include(bbq.gui.error.ServerError);
  3 
  4 bbq.ajax.SoapRequest = Class.create(bbq.ajax.AJAXRequest, /** @lends bbq.ajax.SoapRequest.prototype **/ {
  5 	/**
  6 	 * Sends an asyncronous SOAP request much the same as an AJAX request.
  7 	 *
  8 	 * @example
  9 	 * <pre><code class="language-javascript">
 10 	 * var request = new bbq.ajax.SoapRequest({
 11 	 *     url: "/path/to/somewhere",
 12 	 *     args: {
 13 	 *          foo: "bar"
 14 	 *     },
 15 	 *     onSuccess: function(serverResponse, soapResponse) {
 16 	 *
 17 	 *    }
 18 	 * });
 19 	 * </pre></code>
 20 	 * @constructs
 21 	 * @param {Object} options
 22 	 * @extends bbq.ajax.AJAXRequest
 23 	 */
 24 	initialize: function($super, options) {
 25 		options.method = "POST";
 26 		options.contentType = "application/soap+xml";
 27 		
 28 		$super(options);
 29 	},
 30 
 31 	_createRequestHeaders: function() {
 32 		return {
 33 			"SoapAction": this.options.action,
 34 			"Content-Type": "application/soap+xml"
 35 		};
 36 	},
 37 
 38 	_getPostBody: function() {
 39 		var header = "";
 40 
 41 		if(this.options.authentication) {
 42 			header = "<soapenv:Header xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">" + 
 43 							"<wsse:Security soapenv:mustUnderstand=\"true\">" + 
 44 								this.options.authentication.getSecurityHeader() + 
 45 							"</wsse:Security>" +
 46 						"</soapenv:Header>";
 47 		}
 48 
 49 		return "<?xml version='1.0' encoding='UTF-8'?>" + 
 50 			"<soapenv:Envelope xmlns:soapenv='http://www.w3.org/2003/05/soap-envelope'>" +
 51 				header +  
 52 				"<soapenv:Body>" + 
 53 					"<" + this.options.action + "Request xmlns=\"" + this.options.namespace +"\">" + 
 54 						this._parseMessageBody(null, this.options.message) +
 55 					"</" + this.options.action + "Request>" + 
 56 				"</soapenv:Body>" + 
 57 			"</soapenv:Envelope>\r\n";
 58 	},
 59 
 60 	_parseMessageBody: function(key, message) {
 61 		if(message == null) {
 62 			return "";
 63 		}
 64 
 65 		if(Object.isNumber(message) || Object.isString(message)) {
 66 			return message;
 67 		}
 68 
 69 		var output = "";
 70 
 71 		if(Object.isArray(message)) {
 72 			message.each(function(value) {
 73 				if(value == null) {
 74 					return;
 75 				}
 76 				
 77 				output += "<" + key + ">" + this._parseMessageBody(key, message[key]) + "</" + key + ">";
 78 			});
 79 		} else {
 80 			for(var key in message) {
 81 				if(message[key] == null) {
 82 					continue;
 83 				}
 84 				
 85 				output += "<" + key + ">" + this._parseMessageBody(key, message[key]) + "</" + key + ">";
 86 			}
 87 		}
 88 
 89 		return output;
 90 	},
 91 
 92 	/**
 93 	 * @param	{String}		handlerName
 94 	 * @param	{Object}		args
 95 	 */
 96 	_callHandler: function($super, handlerName, args) {
 97 		var serverResponse = args[0];
 98 		var response;
 99 
100 		try {
101 			var doc = serverResponse.responseXML.documentElement;
102 			var responseElement = doc.getElementsByTagName(this.options.action + "Response")[0];
103 
104 			response = this._parse(responseElement);
105 
106 		} catch(e) {
107 			Log.error("Could not call handler " + handlerName, e);
108 
109 			var errorMessage = new bbq.gui.error.ServerError({
110 				url: this.options.url,
111 				args: this.options.args,
112 				serverResponse: serverResponse.responseText
113 			});
114 			errorMessage.appear();
115 		}
116 
117 		$super(handlerName, [serverResponse, response]);
118 	},
119 
120 	_parse: function(node) {
121 		//Log.info("parsing " + node.nodeName);
122 
123 		// are we parsing multiple sibling nodes with the same name?
124 		// if so, store them in an array
125 		var nodeName;
126 		var isArray;
127 
128 		$A(node.childNodes).each(function(childNode) {
129 			if(childNode.nodeName == nodeName) {
130 				isArray = true;
131 				
132 				throw $break;
133 			}
134 
135 			nodeName = childNode.nodeName; 
136 		});
137 
138 		// will be returned
139 		var response;
140 
141 		if(isArray) {
142 			response = [];
143 
144 			$A(node.childNodes).each(function(childNode) {
145 				if(childNode.nodeName == "#text") {
146 					// found text node, abort!
147 					response = this._parseText(childNode.nodeValue);
148 
149 					throw $break;
150 				}
151 
152 				response.push(this._parse(childNode));
153 			}.bind(this));
154 		} else {
155 			response = {};
156 
157 			$A(node.childNodes).each(function(childNode) {
158 				if(childNode.nodeName == "#text") {
159 					// found text node, abort!
160 					response = this._parseText(childNode.nodeValue);
161 
162 					throw $break;
163 				}
164 
165 				response[childNode.nodeName] = this._parse(childNode);
166 			}.bind(this));
167 		}
168 
169 		return response;
170 	},
171 
172 	_parseText: function(value) {
173 		// try as an integer
174 		var asInt = parseInt(value);
175 
176 		// if not not-a-number and the string value is the same as the int value
177 		if(!isNaN(asInt) && "" + asInt == value) {
178 			return asInt;
179 		}
180 
181 		// try as a float
182 		var asFloat = parseFloat(value);
183 
184 		// if not not-a-number and the string value is the same as the float value
185 		if(!isNaN(asFloat) && "" + asFloat == value) {
186 			return asFloat;
187 		}
188 
189 		// is it a date?
190 		if(value.charAt(4) == "-" && value.charAt(7) == "-" && value.charAt(10) == "T"
191 			&& value.charAt(13) == ":" && value.charAt(16) == ":") {
192 			return new Date(value);
193 		}
194 
195 		return value;
196 	}
197 });
198