define([
	"dojo/dom-form",
	"dojo/dom-style",
	"dojo/dom-construct",
	"dojo/dom-attr",
	"dojo/_base/declare",
	"dojo/_base/config",
	"dojo/_base/connect",
	"dojo/_base/lang",
	"dojo/_base/array",
	"dojox/embed/Flash"
],function(domForm, domStyle, domConstruct, domAttr, declare, config, connect, lang, arrayUtil, embedFlash){


	return declare("dojox.form.uploader._Flash", [], {
		// summary:
		//		A mixin 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:
		//		All properties and methods listed here are specific to the Flash version only.
		//
		//
		// swfPath:String
		//		Path to SWF. Can be overwritten or provided in djConfig.
		swfPath:config.uploaderPath || require.toUrl("dojox/form/resources/uploader.swf"),

		// preventCache: Boolean
		//		If true, then flash request is sent with a value that changes with each request (timestamp)
		preventCache: true,
	
		// 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,
	
		postMixInProperties: function(){
			if(this.uploadType === 'flash'){
				this._files = [];
				this._fileMap = {};
				this._createInput = this._createFlashUploader;
				this.getFileList = this.getFlashFileList;
				this.reset = this.flashReset;
				this.upload = this.uploadFlash;
				this.fieldname = "flashUploadFiles"; ///////////////////// this.name
			}
			this.inherited(arguments);
		},
	
		/*************************
		 *	   Public Events	 *
		 *************************/
	
		onReady: function(/*dojox/form/FileUploader*/ uploader){
			// summary:
			//		Stub - Fired when embedFlash 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 = [];
			this._fileMap = {};
		},
	
		/*************************
		 *	   Private Methods	 *
		 *************************/
	
		uploadFlash: function(/*Object ? */ formData){
			// summary:
			//		Uploads selected files. Alias "upload()" should be used instead.
			// tags:
			//		private
			this.onBegin(this.getFileList());
			formData = formData || {};
			formData.returnType = "F";
			formData.uploadType = this.uploadType;
			console.log('flas upload', formData);
			this.flashMovie.doUpload(formData);
		},
	
		_change: function(fileArray){
			this._files = this._files.concat(fileArray);
			arrayUtil.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.
	
			// Sacrificing some readability 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 = lang.hitch(this, function(s, funcStr){
				this._subs.push(connect.subscribe(this.id + s, this, funcStr));
			});
	
			doSub("/filesSelected", "_change");
			doSub("/filesUploaded", "_complete");
			doSub("/filesProgress", "_progress");
			doSub("/filesError", "_error");
			doSub("/filesCanceled", "onCancel");
			doSub("/stageBlur", "_onFlashBlur");
	
			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){
				domAttr.set(this.domNode, "tabIndex", this.tabIndex);
			}
		},
		_createFlashUploader: function(){
			// summary:
			//		Internal. Creates Flash Uploader
	
			var w = this.btnSize.w;
			var h = this.btnSize.h;
			if(!w){
				// FIXME: Commit this
				setTimeout(dojo.hitch(this, function(){
					this._getButtonStyle(this.domNode);
					this._createFlashUploader();
				}), 200);
				return;
			}
			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 = domConstruct.create("div", {className:"dojoxFlashNode"}, this.domNode, "first");
			domStyle.set(this.inputNode, {
				position:"absolute",
				top:"-2px",
				width:w+"px",
				height:h+"px",
				opacity:0
			});
	
	
	
			var args = {
				expressInstall:true,
				path: (this.swfPath.uri || this.swfPath) + ((this.preventCache)?("?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 embedFlash(args, this.inputNode);
			this.flashObject.onError = lang.hitch(function(msg){
				console.error("Flash Error: " + msg);
			});
			this.flashObject.onReady = lang.hitch(this, function(){
				this.onReady(this);
			});
			this.flashObject.onLoad = lang.hitch(this, function(mov){
				this.flashMovie = mov;
				this.flashReady = true;
	
				this.onLoad(this);
			});
			this._connectFlash();
		}
	});
});
