dojo.provide("dojox.form.uploader.plugins.Flash");

dojo.require("dojox.form.uploader.plugins.HTML5");
dojo.require("dojox.embed.flashVars");
dojo.require("dojox.embed.Flash");

dojo.declare("dojox.form.uploader.plugins.Flash", [], {
	//
	// Version: 1.6
	//
	// summary:
	//		A plugin for dojox.form.Uploader that utilizes a Flash SWF for handling to upload in IE.
	//		All other browsers will use the HTML5 plugin, unless force="flash" is used, then Flash
	//		will be used in all browsers. force="flash"	is provided because Flash has some features
	//		that HTML5 does not yet have. But it is still not recommended because of the many problems
	//		that Firefox and Webkit have with the Flash plugin.
	//
	//	description:
	//		Inherits all properties from dojox.form.Uploader and dojox.form.uploader.plugins.HTML5.
	//		All properties and methods listed here are specific to the Flash plugin only.
	//
	//	swfPath:String
	//		Path to SWF. Can be overwritten or provided in djConfig.
	swfPath:dojo.config.uploaderPath || dojo.moduleUrl("dojox.form", "resources/uploader.swf"),
	//
	// skipServerCheck: Boolean
	// 		If true, will not verify that the server was sent the correct format.
	//		This can be safely set to true. The purpose of the server side check
	//		is mainly to show the dev if they've implemented the different returns
	//		correctly.
	skipServerCheck:true,
	//
	// serverTimeout:Number (milliseconds)
	//		The amount of time given to the uploaded file
	//		to wait for a server response. After this amount
	//		of time, the onComplete is fired but with a 'server timeout'
	//		error in the returned item.
	serverTimeout: 2000,
	//
	//	isDebug: Boolean
	//		If true, outputs traces from the SWF to console. What exactly gets passed
	//		is very relative, and depends upon what traces have been left in the DEFT SWF.
	isDebug:false,
	//
	//	devMode: Boolean.
	//		Re-implemented. devMode increases the logging, adding style tracing from the SWF.
	devMode:false,
	//
	//	deferredUploading: Number (1 - X)
	//		(Flash only) throttles the upload to a certain amount of files at a time.
	//		By default, Flash uploads file one at a time to the server, but in parallel.
	//		Firefox will try to queue all files at once, leading to problems. Set this
	//		to the amount to upload in parallel at a time.
	//		Generally, 1 should work fine, but you can experiment with queuing more than
	//		one at a time.
	//		This is of course ignored if selectMultipleFiles equals false.
	deferredUploading:0,
	//
	//	force: String
	//		Use "flash" to always use Flash (and hopefully force the user to download the plugin
	//		if they don't have it).
	force:"",

	postMixInProperties: function(){
		if(!this.supports("multiple")){
			// Flash will only be used in IE6-8 unless force="flash"
			this.uploadType = "flash";
			this._files = [];
			this._fileMap = {};
			this._createInput = this._createFlashUploader;
			this.getFileList = this.getFlashFileList;
			this.reset = this.flashReset;
			this.upload = this.uploadFlash;
			this.submit = this.submitFlash;
			this.fieldname = "flashUploadFiles"; ///////////////////// this.name
		}
		this.inherited(arguments);
	},

	/*************************
	 *	   Public Events	 *
	 *************************/

	onReady: function(/* dojox.form.FileUploader */ uploader){
		// summary:
		//		Stub - Fired when dojox.embed.Flash has created the
		//		Flash object, but it has not necessarilly finished
		//		downloading, and is ready to be communicated with.
	},

	onLoad: function(/* dojox.form.FileUploader */ uploader){
		// summary:
		//		Stub - SWF has been downloaded 100%.
	},

	onFileChange: function(fileArray){
		// summary:
		// 		Stub - Flash-specific event. Fires on each selection of files
		// 		and only provides the files selected on that event - not all files
		// 		selected, as with HTML5
	},

	onFileProgress: function(fileArray){
		// summary:
		// 		Stub - Flash-specific event. Fires on progress of upload
		// 		and only provides a file-specific event
	},


	/*************************
	 *	   Public Methods	 *
	 *************************/

	getFlashFileList: function(){
		// summary:
		//		Returns list of currently selected files
		return this._files; // Array
	},

	flashReset: function(){
		this.flashMovie.reset();
		this._files = [];
	},

	/*************************
	 *	   Private Methods	 *
	 *************************/

	uploadFlash: function(){
		// summary:
		// 		Uploads selected files. Alias "upload()" should be used instead.
		// tags:
		//		private
		this.onBegin(this.getFileList());
		this.flashMovie.doUpload();
	},

	submitFlash: function(/* Object */formParams){
		// summary:
		// 		Uploads selected files with form data. Alias "submit()" should be used instead.
		// tags:
		//		private
		this.onBegin(this.getFileList());
		this.flashMovie.doUpload(formParams);
	},


	_change: function(fileArray){
		this._files = this._files.concat(fileArray);
		dojo.forEach(fileArray, function(f){
			f.bytesLoaded = 0;
			f.bytesTotal = f.size;
			this._fileMap[f.name+"_"+f.size] = f;
		}, this);
		this.onChange(this._files);
		this.onFileChange(fileArray);
	},
	_complete: function(fileArray){
		var o = this._getCustomEvent();
		o.type = "load";
		this.onComplete(fileArray);
	},
	_progress: function(f){
		this._fileMap[f.name+"_"+f.bytesTotal].bytesLoaded = f.bytesLoaded;
		var o = this._getCustomEvent();
		this.onFileProgress(f);
		this.onProgress(o);
	},
	_error: function(err){
		this.onError(err);
	},
	_onFlashBlur: function(fileArray){
		//console.log("UploaderFlash._onFlashBlur");
	},

	_getCustomEvent: function(){
		var o = {
			bytesLoaded:0,
			bytesTotal:0,
			type:"progress",
			timeStamp:new Date().getTime()
		};


		for(var nm in this._fileMap){
			o.bytesTotal += this._fileMap[nm].bytesTotal;
			o.bytesLoaded += this._fileMap[nm].bytesLoaded;
		}
		o.decimal = o.bytesLoaded / o.bytesTotal;
		o.percent = Math.ceil((o.bytesLoaded / o.bytesTotal)*100)+"%";
		return o; // Object
	},

	_connectFlash: function(){
		// 	summary:
		//		Subscribing to published topics coming from the
		//		Flash uploader.
		// 	description:
		//		Sacrificing some readbilty for compactness. this.id
		//		will be on the beginning of the topic, so more than
		//		one uploader can be on a page and can have unique calls.
		//

		this._subs = [];
		this._cons = [];

		var doSub = dojo.hitch(this, function(s, funcStr){
			this._subs.push(dojo.subscribe(this.id + s, this, funcStr));
		});

		doSub("/filesSelected", "_change");
		doSub("/filesUploaded", "_complete");
		doSub("/filesProgress", "_progress");
		doSub("/filesError", "_error");
		doSub("/filesCanceled", "onCancel");
		doSub("/stageBlur", "_onFlashBlur");

		var cs = dojo.hitch(this, function(s, nm){
			this._cons.push(dojo.subscribe(this.id + s, this, function(evt){
				this.button._cssMouseEvent({type:nm});
			}));
		});
		cs("/up", "mouseup");
		cs("/down", "mousedown");
		cs("/over", "mouseover");
		cs("/out", "mouseout");

		this.connect(this.domNode, "focus", function(){
			// TODO: some kind of indicator that the Flash button
			//	is in focus
			this.flashMovie.focus();
			this.flashMovie.doFocus();
		});
		if(this.tabIndex>=0){
			dojo.attr(this.domNode, "tabIndex", this.tabIndex);
		}
	},
	_createFlashUploader: function(){
		// summary:
		//		Internal. Creates Flash Uploader
		//
		var url = this.getUrl();
		if(url){
			if(url.toLowerCase().indexOf("http")<0 && url.indexOf("/")!=0){
				// Appears to be a relative path. Attempt to
				//	convert it to absolute, so it will better
				//target the SWF.
				//
				var loc = window.location.href.split("/");
				loc.pop();
				loc = loc.join("/")+"/";
				url = loc+url;
			}
		}else{
			console.warn("Warning: no uploadUrl provided.");
		}

		this.inputNode = dojo.create("div", {className:"dojoxFlashNode"}, this.domNode, "first");
		dojo.style(this.inputNode, {
			position:"absolute",
			top:"-2px",
			width:this.btnSize.w+"px",
			height:this.btnSize.h+"px",
			opacity:0
		});

		var w = this.btnSize.w;
		var h = this.btnSize.h;

		var args = {
			expressInstall:true,
			path: (this.swfPath.uri || this.swfPath) + "?cb_" + (new Date().getTime()),
			width: w,
			height: h,
			allowScriptAccess:"always",
			allowNetworking:"all",
			vars: {
				uploadDataFieldName: this.flashFieldName || this.name+"Flash",
				uploadUrl: url,
				uploadOnSelect: this.uploadOnSelect,
				deferredUploading:this.deferredUploading || 0,
				selectMultipleFiles: this.multiple,
				id: this.id,
				isDebug: this.isDebug,
				noReturnCheck: this.skipServerCheck,
				serverTimeout:this.serverTimeout
			},
			params: {
				scale:"noscale",
				wmode:"transparent",
				wmode:"opaque",
				allowScriptAccess:"always",
				allowNetworking:"all"
			}

		};

		this.flashObject = new dojox.embed.Flash(args, this.inputNode);
		this.flashObject.onError = dojo.hitch(function(msg){
			console.error("Flash Error: " + msg);
		});
		this.flashObject.onReady = dojo.hitch(this, function(){
			this.onReady(this);
		});
		this.flashObject.onLoad = dojo.hitch(this, function(mov){
			this.flashMovie = mov;
			this.flashReady = true;

			this.onLoad(this);
		});
		this._connectFlash();
	}
});
dojox.form.addUploaderPlugin(dojox.form.uploader.plugins.Flash);