/**
 * FancyUpload - Flash meets Ajax for beauty uploads
 *
 * Based on Swiff.Base and Swiff.Uploader.
 *
 * Its intended that you edit this class to add your
 * own queue layout/text/effects. This is NO include
 * and forget class. If you want custom effects or
 * more output, use Swiff.Uploader as interface
 * for your new class or change this class.
 *
 * USAGE:
 *  var inputElement = $E('input[type="file"]');
 * 	new FancyUpload(inputElement, {
 * 		swf: '../swf/Swiff.Uploader.swf'
 * 		// more options
 * 	})
 *
 * 	The target element has to be in an form, the upload starts onsubmit
 * 	by default.
 *
 * NOTE:
 *
 * 	Flash FileReference is stupid, the request will have no cookies
 * 	or additional post data. Only the file is send in $_FILES['filedata'],
 * 	with a wrong content-type (application/octet-stream).
 * 	When u have sessions, append them as get-data to the the url.
 *
 *
 * @version		1.0rc2
 *
 * @license		MIT License
 *
 * @author		Harald Kirschner <mail [at] digitarald [dot] de>
 * @copyright	Authors
 */
var FancyUpload = new Class({

	options: {
		url: false,
		swf: '/scripts/fancy_upload/Swiff.Uploader.swf',
		multiple: true,
		queued: true,
		types: {'Images (*.jpg, *.jpeg, *.gif, *.png)': '*.jpg; *.jpeg; *.gif; *.png'},
		limitSize: false,
		limitFiles: false,
		createReplacement: function(el){ el.remove(); },//null,
		instantStart: true,
		allowDuplicates: false,
		optionFxDuration: 250,
		container: null,
		queueList: 'photoupload-queue',
		txtBrowse: 'Browse Files',
		txtCompleted: 'Completed',
		baseURL: false,
		cssFile: 'FancyUpload',
		
		// Events
		onBrowse: Class.empty,
		onComplete: Class.empty,
		onError: Class.empty,
		onCancel: Class.empty,
		onUpload: Class.empty,
		onAllComplete: Class.empty,
		
		// File Errors
		onFilesize: Class.empty,
		onMaxFiles: Class.empty,
		onDuplicate: Class.empty
	},

	initialize: function(el, options){
		this.element = $(el);
		this.setOptions(options);
		this.form = $(this.element.form || null);
		this.fileList = [];
		
		// Get script base path
		if(!this.options.baseURL) {
			var elements = document.getElementsByTagName('script');
			for (var i=0; i<elements.length; i++) {
				if (elements[i].src && (elements[i].src.indexOf('FancyUpload.js') != -1)) {
					var src = elements[i].src;
					this.options.baseURL = src.substring(0, src.lastIndexOf('/'));
					break;
				}
			}
			// Get document base path
			this.documentBasePath = document.location.href;
			if (this.documentBasePath.indexOf('?') != -1)
				this.documentBasePath = this.documentBasePath.substring(0, this.documentBasePath.indexOf('?'));
			this.documentBasePath = this.documentBasePath.substring(0, this.documentBasePath.lastIndexOf('/'));
			if (this.options.baseURL.indexOf('://') == -1 && this.options.baseURL.charAt(0) != '/')
				this.options.baseURL = this.documentBasePath + "/" + this.options.baseURL;
		}

		// Adds Stylesheet
		if(this.options.cssFile !== false) new Asset.css(this.options.baseURL + '/' + this.options.cssFile + '.css');
		this.options.url = this.options.url || (window.gecko?this.form.action:this.options.baseURL + '/' + this.form.action);

		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,
			container: this.options.container
		});
	},

	initializeFlash: function() {
		this.queue = $(this.options.queueList);
		if (this.form) this.form.addEvent('submit', this.upload.bindWithEvent(this));
		if (this.options.createReplacement) {
			this.options.createReplacement(this.element);
		} else {
			new Element('input', {
				type: 'button',
				value: this.options.txtBrowse,
				events: {
					click: this.browse.bind(this)
				}
			}).injectBefore(this.element);
			this.element.remove();
		}

	},

	browse: function() {
		this.fireEvent('onBrowse');
		this.uploader.browse();
	},

	upload: function(e) {
		if (e) e.stop();
		this.fireEvent('onUpload', this);
		this.uploader.send(this.options.url);
	},
	
	selectError: function(fire) {
		this.fireEvent('on'+fire);
		return false;
	},

	onSelect: function(name, size) {
		if (this.uploadTimer) this.uploadTimer = $clear(this.uploadTimer);
		if (this.options.limitSize && (size > this.options.limitSize)) return this.selectError('Filesize');
		if (this.options.limitFiles && (this.fileList.length >= this.options.limitFiles)) return this.selectError('MaxFiles');
		if (!this.options.allowDuplicates && this.findFile(name, size) != -1) return this.selectError('Duplicate');
		this.addFile(name, size);
		if (this.options.instantStart) this.uploadTimer = this.upload.delay(250, this);
		return true;
	},

	onOpen: function(name, size) {
		var index = this.findFile(name, size);
		this.fileList[index].status = 1;
		if (this.fileList[index].fx) return;
		this.fileList[index].fx = this.fileList[index].progress.effect('width', {
				duration: 200,
				wait: false,
				unit: '%',
				transition: Fx.Transitions.linear
			}).set(0);
	},

	onProgress: function(name, bytes, total, percentage) {
		this.uploadStatus(name, total, percentage);
	},

	onComplete: function(name, size) {
		var index = this.uploadStatus(name, size, 100);
		this.fileList[index].fx.element.getElement('span').setHTML(this.options.txtCompleted);
		this.fileList[index].status = 2;
		this.highlight(index, 'e1ff80');
		this.checkComplete(name, size, 'onComplete');
	},

	/**
	 * Error codes are just examples, customize them according to your server-errorhandling
	 *
	 */
	onError: function(name, size, error) {
		var msg = 'Upload Error ('+error+')';
		switch(error.toInt()) {
			case 500: msg = "Error: Internal server error, please contact Administrator"; break;
			case 405: msg = "Error: Filesize must be less than 2MB"; break;
			case 409: msg = "Error: Could not process image, please choose another"; break;
			case 415: msg = "Error: Unsupported image format, please choose another"; break;
			case 417: msg = "Error: The photo is too small, must be at least 200 x 200"; break;
		}
		var index = this.uploadStatus(name, size, 100);
		this.fileList[index].progress.getParent().remove();
		new Element('div', {'class': 'queue-error'}).setHTML(msg).injectInside(this.fileList[index].element);
		this.fileList[index].status = 2;
		this.highlight(index, 'ffd780');
		this.checkComplete(name, size, 'onError');
	},

	checkComplete: function(name, size, fire) {
		this.fireEvent(fire, [name, size]);
		if (this.nextFile() == -1) this.fireEvent('onAllComplete');
	},

	addFile: function(name, size) {
		if (!this.options.multiple && this.fileList.length) this.remove(this.fileList[0].name, this.fileList[0].size);
		this.fileList.push({
			name: name,
			size: size,
			status: 0,
			percentage: 0,
			element: new Element('li').setHTML('<span class="queue-file">'+ name +'</span><span class="queue-size" title="'+ size +' byte">~'+ Math.ceil(size / 1000) +' kb</span>').injectInside(this.queue)
		});
		
		var index = this.fileList.length-1;
		this.fileList[index].progress = new Element('div', {'class': 'queue-subloader'}).setHTML('<span />').injectInside(
			new Element('div', {'class': 'queue-loader'}).injectInside(this.fileList[index].element)
		)

		new Element('a', {
			href: '#',
			'class': 'input-delete',
			title: 'Remove from Queue',
			events: {
				click: this.cancelFile.bindWithEvent(this, [name, size])
			}
		}).injectBefore(this.fileList.getLast().element.getFirst());
		this.highlight(this.fileList.length - 1, 'e1ff80');
	},

	uploadStatus: function(name, size, percentage) {
		var index = this.findFile(name, size);
		this.fileList[index].fx.start( percentage ).element.getElement('span').setHTML(percentage +'%');
		this.fileList[index].percentage = percentage;
		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) {
		this.fileList[index].element.effect('background-color', {
			duration: this.options.optionFxDuration
		}).start(color, 'fff').chain(function(){
			if(this.fileList[index])
				this.fileList[index].element.removeProperty('style');
		}.bind(this));
	},

	cancelFile: function(e, name, size) {
		e.stop();
		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');
		}
		this.fileList[index].element.effect('opacity', {duration: this.options.optionFxDuration}).start(1, 0).chain(Element.remove.pass([this.fileList[index].element], Element));
		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--);
	}
});

FancyUpload.implement(new Events, new Options);