/** * %%INFO 2007-10-01 16:38:00+0200 rgarcia%%
 * @author Rubén García
 * @usage FileUploadWidget(Object options)
 * @example
 * <script type="text/javascript">
 * // <![CDATA[
var sW = new FileUploadWidget(element, [options]);
* 
 * // ]]>
 * </script>
 */

FileUploadWidget = Class.create();
FileUploadWidget.prototype = {
	initialize: function(element, options) {
		this.element = $(element);
		if(!this.element) return;
		this.options = Object.extend({
			containerName:       'uploadBox',
			url:                 false,
			uploadUrl:           false,
			responseUrl:         '',
			swf:                 'js/libs/fileupload/swiff.uploader.swf',
			types:               {'Images (*.jpg, *.jpeg, *.gif, *.png)': '*.jpg; *.jpeg; *.gif; *.png'},
			limitSize:           false,
			limitFiles:          false,
			multiple:            true,
			fadeOut:             true,
			createReplacement:   null,
			instantStart:        false,
			allowDuplicates:     false,
			optionFxDuration:    0.25,
			uploadTimeout:       6, // add upload timeout limit;
			container:           null,
			queued:              true,
			queueListName:       'uploadQueue',
			onComplete:          Prototype.emptyFunction,
			onError:             Prototype.emptyFunction,
			onCancel:            Prototype.emptyFunction,
			onAllComplete:       Prototype.emptyFunction,
			uploadStatusName:    'uploadStatus',
			browseLabel:         'Browse Files...',
			removeFileLabel:     'Remove from queue',
			removeFileClassName: 'inputDelete',
			loaderClassName:     'queueLoader',
			loaderLabel:         'Uploading',
			queueFileClassName:  'queueFile',
			queueSizeClassName:  'queueSize',
			subloaderClassName:  'queueSubloader',
			finishedLabel:       'Completed',
			highlightStartColor: '#ffffff',
			highlightEndColor:   '#e1ff80',
			errorColor:          '#aa0000',
			defaultErrorMsg:     'Upload failed: ',
			errorMsgs: {
				500: "Internal server error, please contact Administrator!",
				400: "Upload failed, please check your filesize!",
				409: "Could not process image, please choose another!",
				412: "Invalid target, please reload page and try again!",
				415: "Unsupported media type, please upload GIF, PNG, TIFF or JPEG!",
				417: "Photo too small, please keep our photo manifest in mind!"
			}
		}, options || {});


		this.formAction = this.options.url;
		this.options.url = this.options.url || this.element.form.action || location.href;
		this.fileList = [];
		this.onCompleteCount = 0;

		if(this.options.fadeOut) {
			if(this.options.onError == Prototype.emptyFunction()) {
				this.options.onError = this.error;
			}
			if(this.options.onComplete == Prototype.emptyFunction()) {
				this.options.onComplete = this.success;
			}
			if(this.options.onAllComplete == Prototype.emptyFunction()) {
				this.options.onAllComplete = this.complete;
			}
		}

		this.uploader = new Swiff.Uploader({
				onOpen:     this.onOpen.bind(this),
				onProgress: this.onProgress.bind(this),
				onComplete: this.onComplete.bind(this),
				onError:    this.onError.bind(this),
				onSelect:   this.onSelect.bind(this)
			}, this.initializeFlash.bind(this), {
				swf:        this.options.swf,
				types:      this.options.types,
				multiple:   this.options.multiple,
				queued:     this.options.queued,
				url:        this.options.url,
				container:  this.options.container
		});
		//this.prepareElements();
	},
	initializeFlash: function() {
		this.queue = $(this.options.queueListName);
		if (!this.formAction) {
			Event.observe(this.element.form, 'submit', this.upload.bindAsEventListener(this));
			if (this.options.createReplacement) this.options.createReplacement(this.element);
			else {
				var div = document.createElement('div');
				div.type = 'button';
				div.value = this.options.browseLabel;
				Event.observe(div, 'click', this.upload.bindAsEventListener(this));
				this.element.form.insertBefore(div, this.element);
				this.element.remove();
			}
		}
		this.element.value = this.options.browseLabel;
	},
	browse: function() {
		this.uploader.browse();
	},
	upload: function(e) {
		if (e) Event.stop(e);
		this.uploader.send(this.options.url);
	},
	onSelect: function(name, size) {
		if (this.uploadTimer) { window.clearTimeout(this.uploadTimer); }
		if ((this.options.limitSize && (size > this.options.limitSize))
			|| (this.options.limitFiles && (this.fileList.length >= this.options.limitFiles))
			|| (!this.options.allowDuplicates && this.findFile(name, size) != -1)) {
			return false;
		}
		this.addFile(name, size);
		if (this.options.instantStart) {
			this.uploadTimer = setTimeout(function(){ this.upload() }.bind(this), 250);
		}
		return true;
	},
	onOpen: function(name, size) {
		var index = this.findFile(name, size);
		this.fileList[index].status = 1;
		if (this.fileList[index].fx) return;

		var loader = document.createElement('div');
		loader.className = this.options.loaderClassName;
		loader.innerHTML = this.options.loaderLabel;

		var subloader = document.createElement('div');
		subloader.className = this.options.subloaderClassName;
		loader.appendChild(subloader);

		this.fileList[index].element.appendChild(loader);
		this.fileList[index].fx = subloader;
	},
	onProgress: function(name, bytes, total, percentage) {
		this.uploadStatus(name, total, percentage);
	},
	onComplete: function(name, size) {
		var index = this.uploadStatus(name, size, 100);
		if(this.fileList[index].fx.morph && this.fileList[index].fx.morph.state == 'running') {
			this.fileList[index].fx.morph.cencel();
			this.fileList[index].fx.style.width = '100%';
		}
		this.fileList[index].fx.innerHTML = this.options.finishedLabel;
		this.fileList[index].status = 2;
		this.highlight(index, this.options.highlightEndColor);
		this.checkComplete(name, size, 'onComplete');
		if (this.fileList[index].uploadTimeout) {
			window.clearTimeout(this.fileList[index].uploadTimeout);
			delete this.fileList[index].uploadTimeout;
		}
	},
	onError: function(name, size, error) {
		var msg = this.options.defaultErrorMsg + error;
		if(this.options.errorMsgs[parseInt(error, 10)]) {
			msg = this.options.errorMsgs[parseInt(error, 10)];
		}
		var index = this.uploadStatus(name, size, 100);
		this.fileList[index].fx.style.background = this.options.errorColor;
		this.fileList[index].fx.innerHTML = msg;
		this.fileList[index].status = 2;
		this.highlight(index, this.options.errorColor);
		this.checkComplete(name, size, 'onError');
		if (this.fileList[index].uploadTimeout) {
			window.clearTimeout(this.fileList[index].uploadTimeout);
			delete this.fileList[index].uploadTimeout;
		}
	},
	checkComplete: function(name, size, fire) {
		//debug(name, size, fire);
		this.options[fire]([name, size]);
		if (this.nextFile() == -1) {
			this.options.onAllComplete();
		}
	},
	addFile: function(name, size) {
		if (!this.options.multiple && this.fileList.length) {
			this.remove(this.fileList[0].name, this.fileList[0].size);
		}
		var element = document.createElement('li');
		element.innerHTML = '<span class="'+ this.options.queueFileClassName +'">'+ name +'</span>' +
				'<span class="'+ this.options.queueSizeClassName +'" title="'+ size +' byte">' +
				' ~'+ Math.ceil(size / 1024) + ' kb</span>';
		this.queue.appendChild(element);
		this.fileList.push({
			name: name,
			size: size,
			status: 0,
			percentage: 0,
			element: element
		});
		var a = document.createElement('a');
		a.href = '#';
		a.title = this.options.removeFileLabel;
		a.className = this.options.removeFileClassName;
		Event.observe(a, 'click', this.cancelFile.bindAsEventListener(this, name, size));
		element.insertBefore(a, $(element).down());
		this.highlight(this.fileList.length - 1, this.options.highlightEndColor);
	},
	uploadStatus: function(name, size, percentage) {
		var index = this.findFile(name, size);
		this.fileList[index].fx.morph = new Effect.Morph(this.fileList[index].fx, {
			style: 'width: ' + percentage + '%', duration: 0.2, transition: Effect.Transitions.linear
		});
		this.fileList[index].fx.innerHTML = percentage + '%';
		this.fileList[index].percentage = percentage;
		if(this.options.uploadTimeout){
			if (this.fileList[index].uploadTimeout) window.clearTimeout(this.fileList[index].uploadTimeout);
			this.fileList[index].uploadTimeout = setTimeout(function(){
				if (this.fileList[index].status != 2) this.onComplete(name, size);
			}.bind(this), parseInt(this.options.uploadTimeout, 10) * 1000);
		}
		return index;
	},
	uploadOverview: function() {
		var l = this.fileList.length, i = -1, percentage = 0;
		while (++i < l) percentage += this.fileList[i].percentage;
		return Math.ceil(percentage / l);
	},
	highlight: function(index, color) {
		if (!this.fileList[index].fx) return;
		new Effect.Highlight(this.fileList[index].fx, {
			duration: this.options.optionFxDuration, startcolor: this.options.highlightStartColor, endcolor: color
		});
	},
	cancelFile: function(e, name, size) {
		Event.stop(e);
		this.remove(name, size);
	},
	remove: function(name, size, index) {
		if (name) index = this.findFile(name, size);
		if (index == -1) return;
		if (this.fileList[index].status < 2) {
			this.uploader.remove(name, size);
			this.checkComplete(name, size, 'onCancel');
		}
		var el = this.fileList[index].element;
		new Effect.Fade(el, {
			duration: this.options.optionFxDuration, afterFinish: function(){ el.remove(); }
		});
		this.fileList.splice(index, 1);
		return;
	},
	findFile: function(name, size) {
		var l = this.fileList.length, i = -1;
		while (++i < l) if (this.fileList[i].name == name && this.fileList[i].size == size) return i;
		return -1;
	},
	nextFile: function() {
		var l = this.fileList.length, i = -1;
		while (++i < l) if (this.fileList[i].status != 2) return i;
		return -1;
	},
	clearList: function(complete) {
		var i = -1;
		while (++i < this.fileList.length) if (complete || this.fileList[i].status == 2) this.remove(0, 0, 0, i--);
	},




	prepareElements: function() {
		var opts = {
					minChars: this.options.minChars
		};
		this.container = $(this.options.containerName);
		if(!this.container) {
			this.createContainer();
		}
		if(this.options.modifier) {
			this.modifier = $(this.options.modifierName);
			if(!this.modifier) {
				return;
			}
			opts.parameters = this.options.modifierParameter + '=' + $F(this.options.modifierName);
			this.modifier.observe('change', this.eventHandler);
		}
		this.autoCompleter = new Ajax.Autocompleter(
			this.element,
			this.options.containerName,
			this.options.URL,
			opts
		)
	},
	createContainer: function() {
		this.container = document.createElement('div');
		Element.extend(this.container);
		this.container.setAttribute('id',this.options.containerName);
		document.body.appendChild(this.container);
	},
	complete: function() {
		new Ajax.Request(this.options.responseUrl, {onSuccess: this.success});
	},
	success: function(req) {
		setTimeout(this.clearList(), 1500);
		$(this.options.uploadStatusName).update(req.responseText);
	},
	error: function(msg) {
		$(this.options.uploadStatusName).update(msg);
	}
}