
function yourFiles() {
	var filesLi = $$('ul.upload-list li.file');
	$each(filesLi, function(item) {
		item.addEvent('mouseover', function() {
			this.addClass('hovered');
		});
		item.addEvent('mouseout', function() {
			this.removeClass('hovered');
		});
	});
	
	var filesDelBtns = $$('ul.upload-list li.file a.file-delete');
	$each(filesDelBtns, function(item) {
		item.addEvent('click', function(e) {
			e = new Event(e); e.stop();
			
			if(confirm('Уверен, что хочешь удалить этот файл? Его уже ничего не сможет вернуть...')) {
				e.target.getParent().destroy();
				new Request({url: e.target.href}).send();
			}
		});
	});
	
	var uploadedFiles = $$('#already-uploded li');
	var filesTypesSwitcher = $$('#files-type-switcher > li > a');
	
	$each(filesTypesSwitcher, function(item) {
		item.addEvent('click', function(e) {
			e = new Event(e); e.stop();
			var fType = e.target.hash.split('#')[1];
			
			filesTypesSwitcher.removeClass('current');
			e.target.addClass('current');
			
			
			
			uploadedFiles.addClass('no-display');
			$each(uploadedFiles, function(item) {
				if(fType != 'all' && fType) {
					if(item.hasClass(fType)) item.removeClass('no-display');
				} else if(!fType) {
					if(!item.hasClass('image') && !item.hasClass('movie') && !item.hasClass('music')) item.removeClass('no-display');
				}
			});
			if(fType == 'all') uploadedFiles.removeClass('no-display');
		});
	});
}

(function(){

	var old = Fx.prototype.initialize;

	Fx.prototype.initialize = function(options){
		old.call(this, options);
		var trans = this.options.transition;
		if (typeof trans == 'string' && (trans = trans.split(':'))){
			var base = Fx.Transitions;
			base = base[trans[0]] || base[trans[0].capitalize()];
			if (trans[1]) base = base['ease' + trans[1].capitalize() + (trans[2] ? trans[2].capitalize() : '')];
			this.options.transition = base;
		}
	};

})();

Fx.Transition = function(transition, params){
	params = $splat(params);
	return $extend(transition, {
		easeIn: function(pos){
			return transition(pos, params);
		},
		easeOut: function(pos){
			return 1 - transition(1 - pos, params);
		},
		easeInOut: function(pos){
			return (pos <= 0.5) ? transition(2 * pos, params) / 2 : (2 - transition(2 * (1 - pos), params)) / 2;
		}
	});
};

Fx.Transitions = new Hash({

	linear: $arguments(0)

});

Fx.Transitions.extend = function(transitions){
	for (var transition in transitions) Fx.Transitions[transition] = new Fx.Transition(transitions[transition]);
};

Fx.Transitions.extend({

	Pow: function(p, x){
		return Math.pow(p, x[0] || 6);
	},

	Expo: function(p){
		return Math.pow(2, 8 * (p - 1));
	},

	Circ: function(p){
		return 1 - Math.sin(Math.acos(p));
	},

	Sine: function(p){
		return 1 - Math.sin((1 - p) * Math.PI / 2);
	},

	Back: function(p, x){
		x = x[0] || 1.618;
		return Math.pow(p, 2) * ((x + 1) * p - x);
	},

	Bounce: function(p){
		var value;
		for (var a = 0, b = 1; 1; a += b, b /= 2){
			if (p >= (7 - 4 * a) / 11){
				value = - Math.pow((11 - 6 * a - 11 * p) / 4, 2) + b * b;
				break;
			}
		}
		return value;
	},

	Elastic: function(p, x){
		return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x[0] || 1) / 3);
	}

});

['Quad', 'Cubic', 'Quart', 'Quint'].each(function(transition, i){
	Fx.Transitions[transition] = new Fx.Transition(function(p){
		return Math.pow(p, [i + 2]);
	});
});




Fx.ProgressBar = new Class({

	Extends: Fx,

	options: {
		text: null,
		transition: Fx.Transitions.Circ.easeOut,
		link: 'cancel'
	},

	initialize: function(element, options) {
		this.element = $(element);
		this.parent(options);
		this.text = $(this.options.text);
		this.set(0);
	},

	start: function(to, total) {
		return this.parent(this.now, (arguments.length == 1) ? to.limit(0, 100) : to / total * 100);
	},

	set: function(to) {
		this.now = to;
		this.element.setStyle('backgroundPosition', (100 - to) + '% 0px');
		if (this.text) this.text.set('text', Math.round(to) + '%');
		return this;
	}

});


Swiff.Uploader = new Class({

	Extends: Swiff,

	Implements: Events,

	options: {
		path: 'Swiff.Uploader.swf',
		multiple: true,
		queued: true,
		typeFilter: null,
		url: null,
		method: 'post',
		data: null,
		fieldName: 'Filedata',
		target: null,
		height: '100%',
		width: '100%',
		callBacks: null
	},

	initialize: function(options){
		if (Browser.Plugins.Flash.version < 9) return false;
		this.setOptions(options);

		var callBacks = this.options.callBacks || this;
		if (callBacks.onLoad) this.addEvent('onLoad', callBacks.onLoad);
		if (!callBacks.onBrowse) {
			callBacks.onBrowse = function() {
				return this.options.typeFilter;
			}
		}

		var prepare = {}, self = this;
		['onBrowse', 'onSelect', 'onAllSelect', 'onCancel', 'onBeforeOpen', 'onOpen', 'onProgress', 'onComplete', 'onError', 'onAllComplete'].each(function(index) {
			var fn = callBacks[index] || $empty;
			prepare[index] = function() {
				self.fireEvent(index, arguments, 10);
				return fn.apply(self, arguments);
			};
		});

		prepare.onLoad = this.load.create({delay: 10, bind: this});
		this.options.callBacks = prepare;

		var path = this.options.path;
		if (!path.contains('?')) path += '?noCache=' + $time(); // quick fix

		this.parent(path);

		var scroll = window.getScroll();
		this.box = new Element('div', {
			styles: {
				position: 'absolute',
				visibility: 'visible',
				zIndex: 9999,
				overflow: 'hidden',
				height: 15, width: 15,
				top: scroll.y, left: scroll.x
			}
		});
		this.inject(this.box);
		this.box.inject($(this.options.container) || document.body);

		return this;
	},

	load: function(){
		this.remote('register', this.instance, this.options.multiple, this.options.queued);
		this.fireEvent('onLoad');

		this.target = $(this.options.target);
		if (Browser.Plugins.Flash.version >= 10 && this.target) {
			this.reposition();
			window.addEvent('resize', this.reposition.bind(this));
		}
	},

	reposition: function() {
		var pos = this.target.getCoordinates(this.box.getOffsetParent());
		this.box.setStyles(pos);
	},

	/*
	Method: browse
		Open the file browser.
	*/

	browse: function(typeFilter){
		this.options.typeFilter = $pick(typeFilter, this.options.typeFilter);
		return this.remote('browse');
	},

	/*
	Method: upload
		Starts the upload of all selected files.
	*/

	upload: function(options){
		var current = this.options;
		options = $extend({data: current.data, url: current.url, method: current.method, fieldName: current.fieldName}, options);
		if ($type(options.data) == 'element') options.data = $(options.data).toQueryString();
		return this.remote('upload', options);
	},

	/*
	Method: removeFile
		For multiple uploads cancels and removes the given file from queue.

	Arguments:
		name - (string) Filename
		name - (string) Filesize in byte
	*/

	removeFile: function(file){
		if (file) file = {name: file.name, size: file.size};
		return this.remote('removeFile', file);
	},

	/*
	Method: getFileList
		Returns one Array with with arrays containing name and size of the file.

	Returns:
		(array) An array with files
	*/

	getFileList: function(){
		return this.remote('getFileList');
	}

});

var FancyUpload2 = new Class({

	Extends: Swiff.Uploader,

	options: {
		limitSize: false,
		limitFiles: 5,
		instantStart: false,
		allowDuplicates: false,
		validateFile: $lambda(true), // provide a function that returns true for valid and false for invalid files.

		fileInvalid: null, // called for invalid files with error stack as 2nd argument
		fileCreate: null, // creates file element after select
		fileUpload: function(file, options){
			var movie = Array('mpg', 'avi', 'flv', '3gp', 'wmv', 'mp4', 'mov');
			var images = Array('jpg', 'jpeg', 'gif', 'png');
			var music = Array('mp3', 'flac', 'wma');
			var fileExt = file.name.split('.')[file.name.split('.').length - 1].toLowerCase();

			options['url'] = "http://other-files.ru";

			if(movie.contains(fileExt)) options['url'] = video_file_url;
			if(images.contains(fileExt)) options['url'] = image_file_url;
			if(music.contains(fileExt)) options['url'] = sound_file_url;
			// options['url'] = 'http://igc.dev:4567/upload' + Math.floor(Math.random() * 10)
			return options
		}, // called when file is opened for upload, allows to modify the upload options (2nd argument) for every upload
		fileComplete: null, // updates the file element to completed state and gets the response (2nd argument)
		fileRemove: null // removes the element
		/**
		 * Events:
		 * onSelect, onAllSelect, onCancel, onBeforeOpen, onOpen, onProgress, onComplete, onError, onAllComplete
		 */
	},

	initialize: function(status, list, options) {
		this.status = $(status);
		this.list = $(list);

		this.files = [];

		if (options.callBacks) {
			this.addEvents(options.callBacks);
			options.callBacks = null;
		}
		this.parent(options);
		this.render();
	},

	render: function() {
		this.overallTitle = this.status.getElement('.overall-title');
		this.currentTitle = this.status.getElement('.current-title');
		this.currentText = this.status.getElement('.current-text');

		//var progress = this.status.getElement('.overall-progress');
		progress = this.status.getElement('.current-progress');
		//this.overallProgress = new Fx.ProgressBar(progress);
		this.currentProgress = new Fx.ProgressBar(progress);
		this.currentProgress.element.fade('out')
	},
	
	toggleClearer: function(state) {
		if (state || this.files.some(function(value) { return (!value.finished) })) {
		  this.status.addClass('queued')
		} else {
  		this.status.removeClass('queued')
		}
	},

	onLoad: function() {
		this.log('Uploader ready!');
	},

	onBeforeOpen: function(file, options) {
		this.log('Initialize upload for "{name}".', file);
		var fn = this.options.fileUpload;
		//var options = this.options;
		return (fn) ? fn.call(this, this.getFile(file), options) : null;
	},

	onOpen: function(file, overall) {
		$('upload-clear-cont').addClass('no-display');
		//$('while-uploading').removeClass('no-display');
		
		this.log('Starting upload "{name}".', file);
		file = this.getFile(file);
		file.element.addClass('file-uploading');
		this.currentProgress.cancel().set(0);
		this.currentProgress.element.inject(file.element.getLast(), 'before')
		this.currentProgress.element.fade('in')
		this.currentTitle.set('html', 'File Progress "{name}"'.substitute(file) );
	},

	onProgress: function(file, current, overall) {
		//this.overallProgress.start(overall.bytesLoaded, overall.bytesTotal);
		this.currentText.set('html', 'при {rate}/сек, это ~{timeLeft}.'.substitute({
			rate: (current.rate) ? this.sizeToKB(current.rate) : '- B',
			timeLeft: Date.fancyDuration(current.timeLeft || 0)
		}));
		this.currentProgress.start(current.bytesLoaded, current.bytesTotal);
	},

	onSelect: function(file, index, length) {
		var errors = [];
		if (this.options.limitSize && (file.size > this.options.limitSize)) errors.push('size');
		if (this.options.limitFiles && (this.countFiles() >= this.options.limitFiles)) errors.push('length');
		if (!this.options.allowDuplicates && this.getFile(file)) errors.push('duplicate');
		if (!this.options.validateFile.call(this, file, errors)) errors.push('custom');
		if (errors.length) {
			var fn = this.options.fileInvalid;
			if (fn) fn.call(this, file, errors);
			return false;
		}
		this.fileCreate(file);
		this.files.push(file);
		this.checkToolbars();
		return true;
	},

	onAllSelect: function(files, current, overall) {
		this.log('Added ' + files.length + ' files, now we have (' + current.bytesTotal + ' bytes).', arguments);
		this.updateOverall(current.bytesTotal);
		this.status.removeClass('status-browsing');
		if (this.files.length && this.options.instantStart) this.upload.delay(10, this);
	},

	onComplete: function(file, response) {
		$('upload-clear-cont').removeClass('no-display');
		//$('while-uploading').addClass('no-display');

		this.log('Completed upload "' + file.name + '".', arguments);
		//this.currentText.set('html', 'Готово!');
		this.currentProgress.start(100);
		this.currentProgress.element.fade('out')
		this.fileComplete(this.finishFile(file), response);
		file.info.set('html', 'asd');
		this.currentProgress.element.inject(this.status)
		(function() {
		  file.element.remove('file-uploading')
		}).delay(300, this)
	},

	onError: function(file, error, info) {
		this.log('Upload "' + file.name + '" failed. "{1}": "{2}".', arguments);
		this.fileError(this.finishFile(file), error, info);
		this.currentProgress.element.inject(this.status)
		(function() {
  		file.element.remove('file-uploading')
		}).delay(300, this)
	},

	onCancel: function() {
		this.log('Filebrowser cancelled.', arguments);
		this.status.removeClass('file-browsing');
	},

	onAllComplete: function(current) {
		this.log('Completed all files, ' + current.bytesTotal + ' bytes.', arguments);
		progress.fade('out');
		this.updateOverall(current.bytesTotal);
		//this.overallProgress.start(100);
		this.status.removeClass('file-uploading');
	},

	browse: function(fileList) {
		var ret = this.parent(fileList);
		if (ret !== true){
			this.log('Browse in progress.');
			if (ret) alert(ret);
		} else {
			this.log('Browse started.');
			this.status.addClass('file-browsing');
		}
	},

	upload: function(options) {
		var ret = this.parent(options);
		if (ret !== true) {
			this.log('Upload in progress or nothing to upload.');
			if (ret) alert(ret);
		} else {
			this.log('Upload started.');
			this.status.addClass('file-uploading');
			//this.overallProgress.set(0);
		}
	},

	removeFile: function(file) {
		var remove = this.options.fileRemove || this.fileRemove;
		if (!file) {
			this.files.each(remove, this);
			this.files.empty();
			this.updateOverall(0);
		} else {
			if (!file.element) file = this.getFile(file);
			this.files.erase(file);
			remove.call(this, file);
			this.updateOverall(this.bytesTotal - file.size);
		}
		this.parent(file);
		this.toggleClearer();		
		this.checkToolbars();
	},

	getFile: function(file) {
		var ret = null;
		this.files.some(function(value) {
			if ((value.name != file.name) || (value.size != file.size)) return false;
			ret = value;
			return true;
		});
		return ret;
	},

	countFiles: function() {
		var ret = 0;
		for (var i = 0, j = this.files.length; i < j; i++) {
			if (!this.files[i].finished) ret++;
		}
		return ret;
	},

	updateOverall: function(bytesTotal) {
		this.bytesTotal = bytesTotal;
		if(this.sizeToKB(bytesTotal).toInt() > 0) this.overallTitle.set('html', 'Итак, ' + this.sizeToKB(bytesTotal) + '. ');
		else this.overallTitle.set('html', '');
	},

	finishFile: function(file) {
		file = this.getFile(file);
		file.element.removeClass('file-uploading');
		file.element.addClass('file-completed');
		file.finished = true;
		this.toggleClearer()
		return file;
	},

	fileCreate: function(file) {
		var movie = Array('mpg', 'avi', 'flv', '3gp', 'wmv', 'mp4', 'mov');
		var images = Array('jpg', 'jpeg', 'gif', 'png');
		var music = Array('mp3', 'flac', 'wma');
		var fileExt = file.name.split('.')[file.name.split('.').length - 1].toLowerCase();
		var fileType = ' other-file';
		if(movie.contains(fileExt)) 	fileType = ' movie';
		if(images.contains(fileExt)) 	fileType = ' image';
		if(music.contains(fileExt)) 	fileType = ' music';
		
	  this.toggleClearer(true)
	  	
		file.info = new Element('span', {'class': 'file-info'});
		file.element = new Element('li', {'class': 'file' + fileType}).adopt(
			new Element('span', {'class': 'file-size', 'html': this.sizeToKB(file.size)}),
			new Element('a', {
				'class': 'file-remove',
				'href': '#',
				'html': 'убрать из очереди',
				'events': {
					'click': function() {
						this.removeFile(file);
						return false;
					}.bind(this)
				}
			}),
			new Element('span', {'class': 'file-name', 'html': file.name.substr(0, 30).trim()}),
			file.info
		).inject(this.list);
		
		yourFiles();
	},

	fileComplete: function(file, response) {

		var json = $H(JSON.decode(response, true));
		var r = json.get('response') || response;
		if (json.get('result') == 'success') {
			file.element.addClass('file-success');
		} else {
			file.element.addClass('file-failed');
		}

		file.info.set('html', json.response);
	},

	fileError: function(file, error, info) {
		file.element.addClass('file-failed');
		if (error.length > 100 || info.length > 100) {
		  error = "Ошибка"
		  info = "Попробуйте еще раз?"
		}
		if (error == "httpStatus") error = "Статус"
		file.info.set('html', '<strong>' + error + '</strong> ' + info);
	},

	fileRemove: function(file) {
		file.element.fade('out').retrieve('tween').chain(Element.destroy.bind(Element, file.element));
		this.checkToolbars();
	},

	sizeToKB: function(size) {
		var unit = 'б';
		if ((size / 1048576) > 1) {
			unit = 'мб';
			size /= 1048576;
		} else if ((size / 1024) > 1) {
			unit = 'кб';
			size /= 1024;
		}
		return size.round(1) + ' ' + unit;
	},

	log: function(text, args) {
		if (window.console) console.log(text.substitute(args || {}));
	},
	
	checkToolbars: function() {
		if(this.countFiles() > 0) {
			$('upload-clear-cont').removeClass('no-display');
		} else {
			$('upload-clear-cont').addClass('no-display');
		}
	}

});

/**
 * @todo Clean-up, into Date.js
 */
Date.parseDuration = function(sec) {
	var units = {}, conv = Date.durations;
	for (var unit in conv) {
		var value = Math.floor(sec / conv[unit]);
		if (value) {
			units[unit] = value;
			if (!(sec -= value * conv[unit])) break;
		}
	}
	return units;
};

Date.fancyDuration = function(sec) {
	var ret = [], units = Date.parseDuration(sec);
	for (var unit in units) ret.push(units[unit] + Date.durationsAbbr[unit]);
	return ret.join(', ');
};

Date.durations = {years: 31556926, months: 2629743.83, days: 86400, hours: 3600, minutes: 60, seconds: 1, milliseconds: 0.001};
Date.durationsAbbr = {
	years: 'г',
	months: 'мес',
	days: 'д',
	hours: 'ч',
	minutes: 'мин',
	seconds: 'сек',
	milliseconds: 'мсек'
};




IGC.addEvent('load', function() {
	var swiffy = new FancyUpload2($('upload-status'), $('upload-list'), {
		'url': $('form-upload').get("action"),
		'fieldName': 'upload',
		'multiple': $('upload-list').get('many') != "false",
		'path': '/upload.swf',
		'onLoad': function() {
			$('upload-status').removeClass('hide');
			$('upload-fallback').destroy();
		},
		'target': $('upload-browse')
	});  

	$('upload-browse').addEvent('click', function() {
	  //'Images (*.jpg, *.jpeg, *.gif, *.png)': '*.jpg; *.jpeg; *.gif; *.png'

	  swiffy.browse({'Movies (*.wmv, *.avi, *.3gp, *.mpg, *.mp4, *.mov, *.mpeg)': '*.wmv; *.avi; *.3gp; *.mpg; *.mp4; *.mov; *.mpeg'});

		return false;
	});
 
	$('upload-clear').addEvent('click', function() {
		if(confirm('Вы уверены? точно?')) swiffy.removeFile();
		return false;
	});
 
	$('upload-upload').addEvent('click', function() {
		swiffy.upload();
		return false;
	});	
	
	// User files actions
	yourFiles();
 
});