/*
	Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
	Available via Academic Free License >= 2.1 OR the modified BSD license.
	see: http://dojotoolkit.org/license for details
*/


if(!dojo._hasResource["dojox.io.xhrMultiPart"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.io.xhrMultiPart"] = true;
dojo.provide("dojox.io.xhrMultiPart");
dojo.require("dojox.uuid.generateRandomUuid");

(function(){
	/*=====
	dojox.io.__xhrContentArgs = function(){
		//	name: String
		//		Name of the form value.
		//	content: String
		//		The contents of the value.
		//	filename: String?
		//		An optional filename to pass to the server, as defined by the boundary.
		//	contentType: String?
		//		An optional content-type (MIME) to pass to the server, if value is being
		//		treated as a file.
		//	charset: String?
		//		Optional charset to pass, for the server to interpret the file correctly.
		//	contentTransferEncoding: String?
		//		Optional transfer encoding header value.
		this.name = name;
		this.content = content;
		this.filename = filename;
		this.contentType = contentType;
		this.charset = charset;
		this.contentTransferEncoding = contentTransferEncoding;
	}
	=====*/
	function _createPart(/* dojox.io.__xhrContentArgs */args, /* String */boundary){
		//	summary
		//		Assemble an array of boundary parts based on the passed values in args.
		if(!args["name"] && !args["content"]){
			throw new Error("Each part of a multi-part request requires 'name' and 'content'.");
		}

		var tmp = [];
		tmp.push(
			"--" + boundary,
			 "Content-Disposition: form-data; name=\"" + args.name + "\"" + (args["filename"] ? "; filename=\"" + args.filename + "\"" : "")
		);

		if(args["contentType"]){
			var ct = "Content-Type: " + args.contentType;
			if(args["charset"]){
				ct += "; Charset=" + args.charset;
			}
			tmp.push(ct);
		}

		if(args["contentTransferEncoding"]){
			tmp.push("Content-Transfer-Encoding: " + args.contentTransferEncoding);
		}
		tmp.push("", args.content);
		return tmp;		//	Array
	}

	function _partsFromNode(/* DOMNode */node, /* String */boundary){
		//	summary
		//		Assemble an array of boundary parts based on the passed FORM node.
		var o=dojo.formToObject(node), parts=[];
		for(var p in o){
			if(dojo.isArray(o[p])){
				dojo.forEach(o[p], function(item){
					parts = parts.concat(_createPart({ name: p, content: item }, boundary));
				});
			} else {
				parts = parts.concat(_createPart({ name: p, content: o[p] }, boundary));
			}
		}
		return parts;	//	Array
	}

	/*=====
	dojox.io.__xhrMultiArgs = function(){
		//	url: String
		//		URL to server endpoint.
		//	content: Object?
		//		Contains properties with string values. These
		//		properties will be serialized using multi-part
		//		boundaries.
		//	file: Object?
		//		Alias for "content".  Provided for backwards compatibility.
		//	timeout: Integer?
		//		Milliseconds to wait for the response. If this time
		//		passes, the then error callbacks are called.
		//	form: DOMNode?
		//		DOM node for a form. Used to extract the form values
		//		and send to the server; each form value will be serialized
		//		using multi-part boundaries.
		//	preventCache: Boolean?
		//		Default is false. If true, then a
		//		"dojo.preventCache" parameter is sent in the request
		//		with a value that changes with each request
		//		(timestamp). Useful only with GET-type requests.
		//	handleAs: String?
		//		Acceptable values depend on the type of IO
		//		transport (see specific IO calls for more information).
		//	load: Function?
		//		function(response, ioArgs){}. response is an Object, ioArgs
		//		is of type dojo.__IoCallbackArgs. The load function will be
		//		called on a successful response.
		//	error: Function?
		//		function(response, ioArgs){}. response is an Object, ioArgs
		//		is of type dojo.__IoCallbackArgs. The error function will
		//		be called in an error case.
		//	handle: Function?
		//		function(response, ioArgs){}. response is an Object, ioArgs
		//		is of type dojo.__IoCallbackArgs. The handle function will
		//		be called in either the successful or error case.
		this.url = url;
		this.content = content;
		this.file = file;
		this.timeout = timeout;
		this.form = form;
		this.preventCache = preventCache;
		this.handleAs = handleAs;
		this.load = load;
		this.error = error;
		this.handle = handle;
	}
	=====*/
	dojox.io.xhrMultiPart = function(/* dojox.io.__xhrMultiArgs */args){
		if(!args["file"] && !args["content"] && !args["form"]){
			throw new Error("content, file or form must be provided to dojox.io.xhrMultiPart's arguments");
		}

		// unique guid as a boundary value for multipart posts
		var boundary=dojox.uuid.generateRandomUuid(), tmp=[], out="";
		if(args["file"] || args["content"]){
			var v = args["file"] || args["content"];
			dojo.forEach((dojo.isArray(v) ? v : [v]), function(item){
				tmp = tmp.concat(_createPart(item, boundary));
			});
		}
		else if(args["form"]){
			if(dojo.query("input[type=file]", args["form"]).length){
				throw new Error("dojox.io.xhrMultiPart cannot post files that are values of an INPUT TYPE=FILE.  Use dojo.io.iframe.send() instead.");
			}
			tmp = _partsFromNode(args["form"], boundary);
		}

		if(tmp.length){
			tmp.push("--"+boundary+"--", "");
			out = tmp.join("\r\n");
		}

		console.log(out);

		return dojo.rawXhrPost(dojo.mixin(args, {
			contentType: "multipart/form-data; boundary=" + boundary,
			postData: out
		}));	//	dojo.Deferred
	}
})();

}
