dojo.provide("dojox.wire.ml.RestHandler");

dojo.require("dojox.wire._base");
dojo.require("dojox.wire.ml.util");

dojo.declare("dojox.wire.ml.RestHandler", null, {
	// summary:
	//		A REST service handler
	// description:
	//		This class serves as a base REST service.
	//		Sub-classes may override _getContent() and _getResult() to handle
	//		specific content types.
	contentType: "text/plain",
	handleAs: "text",

	bind: function(method, parameters, deferred, url){
		// summary:
		//		Call a service method with parameters.
		// description:
		//		A service is called with a URL generated by _getUrl() and
		//		an HTTP method specified with 'method'.
		//		For "POST" and "PUT", a content is generated by _getContent().
		//		When data is loaded, _getResult() is used to pass the result to
		//		Deferred.callback().
		// method:
		//		A method name
		// parameters:
		//		An array of parameters
		// deferred:
		//		'Deferred'
		// url:
		//		A URL for the method
		method = method.toUpperCase();
		var self = this;
		var args = {
			url: this._getUrl(method, parameters, url),
			contentType: this.contentType,
			handleAs: this.handleAs,
			headers: this.headers,
			preventCache: this.preventCache
		};
		var d = null;
		if(method == "POST"){
			args.postData = this._getContent(method, parameters);
			d = dojo.rawXhrPost(args);
		}else if(method == "PUT"){
			args.putData = this._getContent(method, parameters);
			d = dojo.rawXhrPut(args);
		}else if(method == "DELETE"){
			d = dojo.xhrDelete(args);
		}else{ // "GET"
			d = dojo.xhrGet(args);
		}
		d.addCallbacks(function(result){
			deferred.callback(self._getResult(result));
		}, function(error){
			deferred.errback(error);
		});
	},

	_getUrl: function(/*String*/method, /*Array*/parameters, /*String*/url){
		// summary:
		//		Generate a URL
		// description:
		//		If 'method' is "GET" or "DELETE", a query string is generated
		//		from a query object specified to the first parameter in
		//		'parameters' and appended to 'url'.
		//		If 'url' contains variable seguments ("{parameter_name}"),
		//		they are replaced with corresponding parameter values, instead.
		// method:
		//		A method name
		// parameters:
		//		An array of parameters
		// url:
		//		A base URL
		// returns:
		//		A URL
		var query;
		if(method == "GET" || method == "DELETE"){
			if(parameters.length > 0){
				query = parameters[0];
			}
		}else{ // "POST" || "PUT"
			if(parameters.length > 1){
				query = parameters[1];
			}
		}
		if(query){
			var queryString = "";
			for(var name in query){
				var value = query[name];
				if(value){
					value = encodeURIComponent(value);
					var variable = "{" + name + "}";
					var index = url.indexOf(variable);
					if(index >= 0){ // encode in path
						url = url.substring(0, index) + value + url.substring(index + variable.length);
					}else{ // encode as query string
						if(queryString){
							queryString += "&";
						}
						queryString += (name + "=" + value);
					}
				}
			}
			if(queryString){
				url += "?" + queryString;
			}
		}
		return url; //String
	},

	_getContent: function(/*String*/method, /*Array*/parameters){
		// summary:
		//		Generate a request content
		// description:
		//		If 'method' is "POST" or "PUT", the first parameter in
		//		'parameters' is returned.
		// method:
		//		A method name
		// parameters:
		//		An array of parameters
		// returns:
		//		A request content
		if(method == "POST" || method == "PUT"){
			return (parameters ? parameters[0] : null); //anything
		}else{
			return null; //null
		}
	},

	_getResult: function(/*anything*/data){
		// summary:
		//		Extract a result
		// description:
		//		A response data is returned as is.
		// data:
		//		A response data returned by a service
		// returns:
		//		A result object
		return data; //anything
	}
});
