Ext.ux.PluploadPanel = Ext.extend(Ext.Panel, {
	constructor: function(config) {
		this.bodyCssClass = 'x-plupload-body';
		this.success = [];
		this.failed = [];
		this.viewTpl = new Ext.XTemplate(
			'<tpl for=".">',
				'<dl id="{id}">',
					'<dt style="width:50%"><div><img class="itemIcon" src="images/fico/small/generic.png" width="16" height="16" border="0" alt="" align="top" />{name}</div></dt>',
					'<dt style="width:17%"><div style="color:dimgray;text-align:right">&nbsp;{formattedSize}</div></dt>',
					'<tpl exec="this.statusValue(status, percent, msg)"></tpl><dt style="width:28%"><div>{this.statusText}</div></dt>',
					'<div class="x-clear"></div>',
				'</dl>',
			'</tpl>',
			{   compiled: true,
				statusText: '-',
				statusTextQueued: config.statusQueuedText || 'Queued',
				statusTextUploading: config.statusUploadingText || 'Uploaded ({0}%)',
				statusTextFailed: config.statusFailedText || 'FAILED',
				statusTextDone: config.statusDoneText || 'DONE',
				statusValue: function (status, percent, msg) {
					if ( status == 1 ) {
						this.statusText = this.statusTextQueued;
					} else if ( status == 2 ) {
						this.statusText = String.format( this.statusTextUploading, percent );
					} else if ( status == 4 ) {
						this.statusText = msg || this.statusTextFailed;
					} else if ( status == 5 ) {
						this.statusText = this.statusTextDone;
					}
				}
			}
		);

		this.store = new Ext.data.JsonStore({
			fields: [ 'id', 'loaded', 'name', 'size', 'percent', 'status', 'msg' ],
			listeners: {
				load: this.onStoreLoad,
				remove: this.onStoreRemove,
				update: this.onStoreUpdate,
				scope: this
			}
		});

		this.pbar = new Ext.ProgressBar({animate: true});
		this.btns = {
			addButton: new Ext.Button({
				text: config.addButtonText || 'Add files',
				iconCls: config.addButtonCls,
				disabled: true
			}),
			del: new Ext.SplitButton({
				text: config.deleteButtonText || 'Remove',
				handler: this.onDeleteSelected,
				menu: new Ext.menu.Menu({
					items: [
						{text: config.deleteSelectedText, handler: this.onDeleteSelected, scope: this },
						{text: config.deleteUploadedText, handler: this.onDeleteUploaded, scope: this },
						{text: config.deleteAllText, handler: this.onDeleteAll, scope: this }
					]
				}),
				scope: this,
				disabled: true,
				iconCls: config.deleteButtonCls
			}),
			start: new Ext.Button({
				text: config.uploadButtonText,
				handler: this.onStart,
				scope: this,
				disabled: true,
				iconCls: config.uploadButtonCls
			}),
			cancel: new Ext.Button({
				text: config.cancelButtonText,
				handler: this.onCancel,
				scope: this,
				disabled: true,
				iconCls: config.cancelButtonCls
			})
		}
		this.menuBar = new Ext.Toolbar({
			enableOverflow: true,
			  items: [
				this.btns.addButton,
				this.btns.del,
				'->',
				this.btns.start,
				this.btns.cancel
			]
		});

		this.view = new Ext.DataView({
			store: this.store,
			tpl: this.viewTpl,
			autoScroll: true,
			multiSelect: true, autoHeight:true,
			overClass: 'plupload_over',
			selectedClass: 'plupload_selected',
			itemSelector: 'dl',
			emptyText: config.emptyText,
			emptyDropText: config.emptyDropText,
			deferEmptyText: false
		});
		this.layout = 'border';
		this.hideBorders = true;
		this.items = [{
			region: 'center', autoScroll: true,
			items: this.view
		},{
			region: 'south', height: 17,
			items: this.pbar
		}];
		this.bbar = this.menuBar;
		Ext.ux.PluploadPanel.superclass.constructor.apply(this, arguments);
	},
	initComponent: function() {
		Ext.ux.PluploadPanel.superclass.initComponent.apply(this, arguments);
	},
	afterRender: function() {
		Ext.ux.PluploadPanel.superclass.afterRender.apply(this, arguments);
		this.initialize_uploader();
	},
	onDeleteSelected: function () {
		Ext.each( this.view.getSelectedRecords(), 
			function (record) {this.remove_file(record.get('id'));}, this
		);
	},
	onDeleteAll: function () {
		this.store.each(
			function (record) {this.remove_file(record.get('id'));}, this
		);
	},
	onDeleteUploaded: function () {
		this.store.each(
			function (record) {
				if ( record.get( 'status' ) == 5 ) {this.remove_file(record.get('id'));}
			}, this
		);
	},
	onCancel: function () {this.uploader.stop();},
	onStart: function () {
		this.fireEvent('beforestart', this);
		if ( this.multipart_params ) {
			this.uploader.settings.multipart_params = this.multipart_params;
		}
		this.uploader.start();
	},
	initialize_uploader: function () {
		this.uploader = new plupload.Uploader({
			url: this.url,
			runtimes: this.runtimes,
			browse_button: this.btns.addButton.getEl().dom.id,
			container: this.menuBar.getEl().dom.id,
			max_file_size: this.max_file_size || '10mb',
			resize: this.resize || '',
			flash_swf_url: this.flash_swf_url || '',
			silverlight_xap_url: this.silverlight_xap_url || '',
			filters : this.filters || [],
			chunk_size: this.chunk_size,
			unique_names: this.unique_names,
			multipart: this.multipart,
			multipart_params: this.multipart_params,
			drop_element: this.body.dom.id,
			required_features: this.required_features
		});
		Ext.each(['Init', 'PostInit', 'ChunkUploaded', 'FilesAdded', 'FilesRemoved', 'FileUploaded', 'PostInit', 'QueueChanged', 'Refresh', 'StateChanged', 'UploadFile', 'UploadProgress', 'Error' ], function (v) { this.uploader.bind(v, eval("this." + v), this); }, this
		);
		this.uploader.bind('BeforeUpload', function(up, file) {
			up.settings.multipart_params.totalFileSize = file.size;
		});
		this.uploader.init();
	},
	remove_file: function (id) {
		var fileObj = this.uploader.getFile( id );
		if ( fileObj ) {
			this.uploader.removeFile( fileObj );
		}
		else {
			this.store.remove( this.store.getById( id ) );
		}
	},
	update_pbar: function () {
		var t = this.uploader.total;
		var speed = Ext.util.Format.fileSize(t.bytesPerSec);
		var total = this.store.data.length;
		var failed = this.failed.length; 
		var success = this.success.length;
		var sent = failed + success;
		var queued = total - success - failed;
		if ( total ) {
			if (this.runtime == 'html4') {speed = '?';}
			var pbarText = String.format(this.progressText, sent, total, success, failed, queued, speed );
			var percent = t.percent / 100;
			// flash and html4 runtime fix (uploader.total contains outdated info about queue)
			if ( this.runtime == 'flash' || this.runtime == 'html4' ) { 
				if ( total == sent || this.store.find('status', /1|2/) == -1 ) { //find queued or uploading status
					percent = 1  
				}
			}
			// end fix
			this.pbar.updateProgress(percent, pbarText);
		}
		else {
			this.pbar.updateProgress(0, ' ');
		}
		this.fireEvent('progress', this, percent);
	},
	update_store: function (v) {
		if ( !v.msg ) { v.msg = ''; }
		var data = this.store.getById(v.id);
		if ( data ) {
			data.data = v;
			data.commit();
		} else {
			this.store.loadData(v, true);
		}
	},
	onStoreLoad: function (store, record, operation) {
		this.update_pbar();
	},
	onStoreRemove: function (store, record, operation) {
		if ( ! store.data.length ) {
			this.btns.del.setDisabled(true);
			this.btns.start.setDisabled(true);
			this.uploader.total.reset();
		}
		var id = record.get( 'id' );

		Ext.each( this.success, 
			function (v) {
				if ( v && v.id == id ) {
					this.success.remove(v);
				}
			}, this
		);

		Ext.each( this.failed, 
			function (v) {
				if ( v && v.id == id ) {
					this.failed.remove(v);
				}
			}, this
		);
		this.update_pbar();
	},
	onStoreUpdate: function (store, record, operation) {
		this.update_pbar();
	},
	Init: function(uploader, data) {
		this.runtime = data.runtime;
		new Ext.ToolTip({
			html: FR.T('Runtime: ')+data.runtime.toUpperCase(), target: this.btns.start.getEl(), anchor: 'top', hideDelay: 0, showDelay: 1500
		});
		this.btns.addButton.setDisabled(false);
		this.fireEvent('init', this);
	},
	ChunkUploaded: function(up, file, info) {
		 this.fireEvent('chunkuploaded', this, up, file, info);
	},
	FilesAdded: function(uploader, files) {
		this.btns.del.setDisabled(false);
		this.btns.start.setDisabled(false);
		Ext.each(files, function (v) {
			if (!v.size) {v.formattedSize = '&nbsp;';} else {v.formattedSize = Ext.util.Format.fileSize(v.size);}
			this.update_store(v);
		}, this);
	},
	FilesRemoved: function(uploader, files) {
		Ext.each(files, function (file) {this.store.remove(this.store.getById(file.id));}, this);
	},
	FileUploaded: function(uploader, file, status) {
		var response = Ext.util.JSON.decode( status.response );
		if ( response.success == true ) {
			file.server_error = 0;
			this.success.push(file);
		}
		else {
			if ( response.message ) {
				file.msg = '<span style="color: red">' + response.message + '</span>';
			}
			file.server_error = 1;
			this.failed.push(file);
		}
		this.update_store( file );
		this.fireEvent('fileuploaded', this, uploader, file, response, status);
	},
	PostInit: function(uploader) {
		if (this.uploader.features.dragdrop) {
			var v = this.view;
			v.emptyText = this.emptyDropText;
			if (v.rendered) {v.refresh();}
		}
		this.fireEvent('postinit', this, uploader);
	},
	QueueChanged: function(uploader) {
		Ext.each(uploader.files, 
			function (v) {
				if (v) {
					var ext = window.parent.FR.utils.getFileExtension(v.name);
					if (blockedFileTypes.indexOf(ext) != -1) {
						this.uploader.removeFile(v);
					}
				}
			}, this
		);
	},
	Refresh: function(uploader) {
		Ext.each(uploader.files, 
			function (v) {
				this.update_store( v );
			}, this
		);
	},
	StateChanged: function(uploader) {
		if ( uploader.state == 2 ) {
			this.fireEvent('uploadstarted', this);
			this.btns.cancel.setDisabled(false);
			this.btns.start.setDisabled(true);
		} else {
			this.fireEvent('uploadcomplete', this, this.success, this.failed);
			this.btns.cancel.setDisabled(true);
			this.btns.start.setDisabled(false);
		}
	},
	UploadFile: function() {
	},
	UploadProgress: function(uploader, file) {
		if ( file.server_error ) {
			file.status = 4;
		}
		this.update_store( file );
	},
	Error: function (uploader, data) {
		this.fireEvent('error', uploader, data);
		if (data.file) {
			data.file.status = 4;
			if ( data.code == -600 ) {
				data.file.msg = String.format( '<span style="color: red">{0}</span>', this.statusInvalidSizeText || 'Too big' );
			} else if ( data.code == -700 ) {
				data.file.msg = String.format( '<span style="color: red">{0}</span>', this.statusInvalidExtensionText || 'Invalid file type' );
			} else {
				data.file.msg = String.format( '<span style="color: red">{2} ({0}: {1})</span>', data.code, data.details, data.message );
			}
			this.update_store( data.file );
		}
	}
});

Ext.reg('pluploadpanel', Ext.ux.PluploadPanel);