Ext.namespace('Zarafa.plugins.files');

/**
 * @class Zarafa.plugins.files.ABOUT
 * @extends String
 *
 * The copyright string holding the copyright notice for the Zarafa files Plugin.
 */
Zarafa.plugins.files.ABOUT = ""
        + "<p>Copyright (C) 2005-2015  Zarafa B.V. &lt;info@zarafa.com&gt; and its licensors</p>"
	+ "<p>This program is free software: you can redistribute it and/or modify "
	+ "it under the terms of the GNU Affero General Public License as "
	+ "published by the Free Software Foundation, either version 3 of the "
	+ "License, or (at your option) any later version.</p>"

	+ "<p>This program is distributed in the hope that it will be useful, "
	+ "but WITHOUT ANY WARRANTY; without even the implied warranty of "
	+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the "
	+ "GNU Affero General Public License for more details.</p>"

	+ "<p>You should have received a copy of the GNU Affero General Public License "
	+ "along with this program.  If not, see <a href=\"http://www.gnu.org/licenses/\" target=\"_blank\">http://www.gnu.org/licenses/</a>.</p>"

	+ "<hr />"

	+ "<p>The files plugin contains the following third-party components:</p>"

	+ "<h1>ExtJS ux.Media 2.1.3 extension</h1>"

	+ "<p>Copyright(c) 2007-2010, Active Group, Inc.</p>"

	+ "<p>License: ux.Media classes are licensed under the terms of the Open Source GPL 3.0 license (details: http://www.gnu.org/licenses/gpl.html).</p>";
Ext.namespace('Zarafa.plugins.files.data');

/**
 * @class Zarafa.plugins.files.data.ResponseHandler
 * @extends Zarafa.core.data.AbstractResponseHandler
 *
 * Files specific response handler.
 */
Zarafa.plugins.files.data.ResponseHandler = Ext.extend(Zarafa.core.data.AbstractResponseHandler, {

	/**
	 * @cgf {String} The id of the opened node in fuile tree recieved from the Files
	 */
	nodeId: undefined,

	/**
	 * @cfg {Function} successCallback The function which
	 * will be called after success request.
	 */
	successCallback : null,
	
	/**
	 * @cfg {Function} failureCallback The function which
	 * will be called after a failed request.
	 */
	failureCallback : null,
	
	/**
	 * Call the successCallback callback function.
	 * @param {Object} response Object contained the response data.
	 */
	doLoaddirectory : function(response) {
		if(response.status === true) {
			this.successCallback(response.items, response);
		} else {
			this.failureCallback(response);
		}
	},
	
	/**
	 * Call the successCallback callback function.
	 * @param {Object} response Object contained the response data.
	 */
	doGetversion : function(response) {
		this.successCallback(response);
	},
	
	/**
	 * Call the successCallback callback function.
	 * @param {Object} response Object contained the response data.
	 */
	doCheckifexists : function(response) {
		this.successCallback(response);
	},
	
	/**
	 * Call the successCallback callback function.
	 * @param {Object} response Object contained the response data.
	 */
	doGetdynamics : function(response) {
		this.successCallback(response);
	},
	
	/**
	 * Call the successCallback callback function.
	 * @param {Object} response Object contained the response data.
	 */	
	doTmpdownload : function(response) {
		this.successCallback(response.items, response);
	},
	
	/**
	 * Call the successCallback callback function.
	 * @param {Object} response Object contained the response data.
	 */
	doCreatedir : function(response) {
		this.successCallback(response);
	},
	
	/**
	 * Call the successCallback callback function.
	 * @param {Object} response Object contained the response data.
	 */
	doUploadtooc : function(response) {
		this.successCallback(response);
	},
	
	/**
	 * Call the successCallback callback function.
	 * @param {Object} response Object contained the response data.
	 */
	doUpdatesession : function(response) {
		this.successCallback(response);
	},
	
	/**
	 * Call the successCallback callback function.
	 * @param {Object} response Object contained the response data.
	 */
	doClearcache : function(response) {
		this.successCallback(response);
	},
	
	/**
	 * Call the successCallback callback function.
	 * @param {Object} response Object contained the response data.
	 */
	doMove : function(response) {
		if(response.status === true) {
			this.successCallback(response);
		} else {
			this.failureCallback(response);
		}
	},

	/**
	 * In case exception happened on server, server will return
	 * exception response with the code of exception.
	 * @param {Object} response Object contained the response data.
	 */
	doError: function(response) {
		if(response.error) {
			Zarafa.common.dialogs.MessageBox.show({
				title   : dgettext('plugin_files', 'Error'),
				msg     : response.error.info.original_message,
				icon    : Zarafa.common.dialogs.MessageBox.ERROR,
				buttons : Zarafa.common.dialogs.MessageBox.OK
			});
		}else {
			Zarafa.common.dialogs.MessageBox.show({
				title   : dgettext('plugin_files', 'Error'),
				msg     : response.info.original_message,
				icon    : Zarafa.common.dialogs.MessageBox.ERROR,
				buttons : Zarafa.common.dialogs.MessageBox.OK
			});
		}
	}
});

Ext.reg('zarafa.filesresponsehandler', Zarafa.plugins.files.data.ResponseHandler);
Ext.namespace('Zarafa.plugins.files.data');

/**
 * @class Zarafa.plugins.files.data.DirectoryLoader
 * @extends Ext.tree.TreeLoader
 *
 * Files Directory loader. Extends Ext treeloader to use Zarafa
 * specific requests.
 */
Zarafa.plugins.files.data.DirectoryLoader = Ext.extend(Ext.tree.TreeLoader, {

	/**
	 * also load files
	 */
	files : false,
	
	/**
	 * @constructor
	 * @param {Object} config Configuration object
	 */
	constructor : function(config) {
		config = config || {};
		
		if(Ext.isDefined(config.loadfiles))
			this.files = config.loadfiles;

		Ext.applyIf(config, {
			preloadChildren: true,
			directFn : this.loadFolder.createDelegate(this),
			listeners: {
				loadexception: function(tl, node, response) {
					Zarafa.common.dialogs.MessageBox.show({
						title : dgettext('plugin_files', 'Loading failed'),
						msg : response.error,
						icon : Zarafa.common.dialogs.MessageBox.ERROR,
						buttons : Zarafa.common.dialogs.MessageBox.OK
					});
				}
			}
		});

		Zarafa.plugins.files.data.DirectoryLoader.superclass.constructor.call(this, config);
	},

	/**
	 * Will do single request to files module with provided nodeId and
	 * in case of success will load the content of this node.
	 *
	 * @param {Number} nodeId The id of node which content need to be loaded
	 * @param {Function} callback The function which need to be called after response received
	 */
	loadFolder : function(nodeId, callback) {
		var self = this;
		var responseHandler = new Zarafa.plugins.files.data.ResponseHandler({
			successCallback: function(items, response) {
				// reanable upload button Zarafa.plugins.files.ui.UploadButton
				var toolBar = Zarafa.plugins.files.data.ComponentBox.getViewPanelToolbar();
				if(toolBar) {
					var button = toolBar.uploadbutton;
					if(button)
						button.enable();
				}
				
				callback(items, response); // run callback
			},
			failureCallback: function(response) {
				
				var toolBar = Zarafa.plugins.files.data.ComponentBox.getViewPanelToolbar();
				var tabBarItems = Zarafa.plugins.files.data.ComponentBox.getTabPanelItems();
				var openedWindow = Ext.WindowMgr.getActive();
				
				// close the opened dialog
				if(openedWindow)
					openedWindow.close();
				
				// close all opened upload tabs
				var FilesUploadContentPanel = container.getSharedComponent(Zarafa.core.data.SharedComponentType['common.create']);
				Ext.each(tabBarItems, function (item) {
					if(Ext.isDefined(item.xtype) && item.xtype === "zarafa.filesuploadcontentpanel") {
						item.close();
					}
				});
				
				// try to disable Zarafa.plugins.files.ui.UploadButton
				if(toolBar) {
					var button = toolBar.uploadbutton;
					if(button)
						button.disable();
				}
				
				Zarafa.common.dialogs.MessageBox.show({
					title : dgettext('plugin_files', 'Error'),
					msg : response.error,
					icon : Zarafa.common.dialogs.MessageBox.ERROR,
					buttons : Zarafa.common.dialogs.MessageBox.OK
				});
				
				callback(undefined, {status : true, items : undefined}); // run callback
			},
			nodeId: nodeId
		});
		
		container.getRequest().singleRequest(
			'filesbrowsermodule',
			'loaddirectory',
			{
				id : nodeId,
				loadfiles : this.files
			},
			responseHandler
		);
	}
});
Ext.namespace('Zarafa.plugins.files.data');

/**
 * @class Zarafa.plugins.files.data.Version
 * @extends Object
 *
 * Global Version Manager
 */
Zarafa.plugins.files.data.Version = Ext.extend(Object, {
	/**
	 * The owncloud version string or undefined if no owncloud is used.
	 * @property
	 * @type String
	 */
	ocversion : undefined,
	
	/**
	 * The plugin version string.
	 * @property
	 * @type String
	 */
	plversion : undefined,
	
	/**
	 * Flag to indicate that owncloud is used as file backend. False if no owncloud is used.
	 * @property
	 * @type Boolean
	 */
	isoc : false,
	
	/**
	 * Triggers a call to the backend to load version information.
	 */
	init : function() {
		var responseHandler = new Zarafa.plugins.files.data.ResponseHandler({
			successCallback: this.gotVersion.createDelegate(this)
		});
		
		container.getRequest().singleRequest(
			'filesmodule',
			'getversion',
			{
				plugin : "files"
			},
			responseHandler
		);
	},
	
	/**
	 * This function is called on a successful response from the backend.
	 * @param {Object} response
	 */
	gotVersion : function(response) {
		this.ocversion = response.ocversion;
		this.plversion = response.version;
		
		if(this.ocversion)
			this.isoc = true;
		else
			this.isoc = false;
	},
	
	/**
	 * Returns true if file backend is owncloud.
	 * @return {Boolean}
	 */
	isOwncloud : function() {
		return this.isoc;
	},
	
	/**
	 * Returns the plugin version string.
	 * @return {String}
	 */
	getPluginVersion : function() {
		return this.plversion;
	},
	
	/**
	 * Returns the files backend version string or unknown if no version
	 * information is found.
	 * @return {String}
	 */
	getFilesVersion : function() {
		if(this.ocversion) {
			this.isoc = true;
			return this.ocversion;
		} else {
			this.isoc = false;
			return dgettext('plugin_files', 'Unknown');
		}
	}
});

// Make it a singleton
Zarafa.plugins.files.data.Version = new Zarafa.plugins.files.data.Version();
Ext.namespace('Zarafa.plugins.files.data');

/**
 * @class Zarafa.plugins.files.data.Dynamics
 * @extends Object
 *
 * Global dynamic value manager
 */
Zarafa.plugins.files.data.Dynamics = Ext.extend(Object, {
	/**
	 * This object stores the JSON response from the backend.
	 * @property
	 * @type Object
	 */
	dynData : undefined,
	
	/**
	 * Triggers a call to the backend to load version information.
	 */
	init : function() {
		var responseHandler = new Zarafa.plugins.files.data.ResponseHandler({
			successCallback: this.gotDynamics.createDelegate(this)
		});
		
		container.getRequest().singleRequest(
			'filesmodule',
			'getdynamics',
			{
				plugin : "files"
			},
			responseHandler
		);
	},
	
	/**
	 * This function is called on a successful response from the backend.
	 * @param {Object} response
	 */
	gotDynamics : function(response) {
		this.dynData = response;
	},
	
	/**
	 * Returns the upload size limit in bytes.
	 * @return {Number} Will return undefined on error.
	 */
	getMaxUploadFilesize : function() {
		if(!Ext.isEmpty(this.dynData) && this.dynData.uploadLimit) {
			return this.dynData.uploadLimit;
		}
		
		return undefined;
	},
	
	/**
	 * Returns the current store size.
	 * @return {Number} Will return -1 on error.
	 */
	getCurrentStoreSize : function() {
		if(!Ext.isEmpty(this.dynData) && this.dynData.quotaSupport === true) {
			return parseFloat(this.dynData.quotaUsed);
		}
		
		return -1;
	},
	
	/**
	 * Returns the available store size.
	 * @return {Number} Will return -1 on error.
	 */
	getAvailableStoreSize : function() {
		if(!Ext.isEmpty(this.dynData) && this.dynData.quotaSupport === true) {
			return parseFloat(this.dynData.quotaAvailable);
		}
		
		return -1;
	}
});

// Make it a singleton
Zarafa.plugins.files.data.Dynamics = new Zarafa.plugins.files.data.Dynamics();
Ext.namespace('Zarafa.plugins.files.settings');

/**
 * @class Zarafa.plugins.files.settings.SettingsFilesComponentsWidget
 * @extends Zarafa.settings.ui.SettingsWidget
 * @xtype Zarafa.plugins.files.settingsfileswidget
 *
 * The {@link Zarafa.settings.ui.SettingsWidget widget} for configuring
 * the general files options in the {@link Zarafa.files.settings.SettingsFilesComponentsCategory files category}.
 */
Zarafa.plugins.files.settings.SettingsFilesComponentsWidget = Ext.extend(Zarafa.settings.ui.SettingsWidget, {

	/**
	 * @constructor
	 * @param {Object} config Configuration object
	 */
	constructor : function(config) {
		config = config || {};

		Ext.applyIf(config, {
			title : String.format(dgettext('plugin_files', 'Enable/Disable {0} components'), container.getSettingsModel().get('zarafa/v1/plugins/files/button_name')),
			layout : 'form',
			items : [{
				xtype : 'checkbox',
				name : 'zarafa/v1/plugins/attachfromfiles/enable',
				ref : 'attachFrom',
				fieldLabel : String.format(dgettext('plugin_files', 'Attach a file from {0}'), container.getSettingsModel().get('zarafa/v1/plugins/files/button_name')),
				lazyInit : false
			},
			{
				xtype : 'checkbox',
				name : 'zarafa/v1/plugins/savetofiles/enable',
				ref : 'attachTo',
				fieldLabel : String.format(dgettext('plugin_files', 'Save received attachments to {0}'), container.getSettingsModel().get('zarafa/v1/plugins/files/button_name')),
				lazyInit : false
			},
			{
				xtype : 'checkbox',
				name : 'zarafa/v1/plugins/filescontext/enable',
				ref : 'enableBrowser',
				fieldLabel : dgettext('plugin_files', 'Enable file browser'),
				lazyInit : false
			}]
		});

		Zarafa.plugins.files.settings.SettingsFilesComponentsWidget.superclass.constructor.call(this, config);
	},

	/**
	 * Called by the {@link Zarafa.settings.ui.SettingsCategory Category} when
	 * it has been called with {@link zarafa.settings.ui.SettingsCategory#update}.
	 * This is used to load the latest version of the settings from the
	 * {@link Zarafa.settings.SettingsModel} into the UI of this category.
	 * @param {Zarafa.settings.SettingsModel} settingsModel The settings to load
	 */
	update : function(settingsModel) {
		this.model = settingsModel;
		this.attachFrom.setValue(settingsModel.get(this.attachFrom.name));
		this.attachTo.setValue(settingsModel.get(this.attachTo.name));
		this.enableBrowser.setValue(settingsModel.get(this.enableBrowser.name));
	},

	/**
	 * Called by the {@link Zarafa.settings.ui.SettingsCategory Category} when
	 * it has been called with {@link zarafa.settings.ui.SettingsCategory#updateSettings}.
	 * This is used to update the settings from the UI into the {@link Zarafa.settings.SettingsModel settings model}.
	 * @param {Zarafa.settings.SettingsModel} settingsModel The settings to update
	 */
	updateSettings : function(settingsModel) {
		settingsModel.set(this.attachFrom.name, this.attachFrom.getValue());
		settingsModel.set(this.attachTo.name, this.attachTo.getValue());
		settingsModel.set(this.enableBrowser.name, this.enableBrowser.getValue());
	}
});

Ext.reg('Zarafa.plugins.files.settingsfilescomponentswidget', Zarafa.plugins.files.settings.SettingsFilesComponentsWidget);
Ext.namespace('Zarafa.plugins.files.settings');

/**
 * @class Zarafa.files.settings.SettingsFilesWidget
 * @extends Zarafa.settings.ui.SettingsWidget
 * @xtype Zarafa.plugins.files.settingsfileswidget
 *
 * The {@link Zarafa.settings.ui.SettingsWidget widget} for configuring
 * the general files options in the {@link Zarafa.files.settings.SettingsFilesCategory files category}.
 */
Zarafa.plugins.files.settings.SettingsFilesWidget = Ext.extend(Zarafa.settings.ui.SettingsWidget, {
	/**
	 * @constructor
	 * @param {Object} config Configuration object
	 */
	constructor : function(config) {
		config = config || {};

		 // default backend selector
		var backendStore = {
			xtype : 'jsonstore',
			autoDestroy : true,
			fields : ['type', 'text'],
			data : [{
				text : _('Webdav'),
				type : 'webdav'
			}, {
				text : _('FTP'),
				type : 'ftp'
			}]
		};
		
		Ext.applyIf(config, {
			title : String.format(dgettext('plugin_files', 'General {0} settings'), container.getSettingsModel().get('zarafa/v1/plugins/files/button_name')),
			layout : 'form',
			items : [{
				xtype : 'textfield',
				name : 'zarafa/v1/contexts/files/server',
				ref : 'serverField',
				fieldLabel : dgettext('plugin_files', 'Server address'),
				emptyText : 'demo.files.org',
				anchor : '100%'
			},
			{
				xtype : 'textfield',
				name : 'zarafa/v1/contexts/files/port',
				ref : 'portField',
				fieldLabel : dgettext('plugin_files', 'Server port'),
				emptyText : '80',
				anchor : '100%'
			},
			{
				xtype : 'textfield',
				name : 'zarafa/v1/contexts/files/port_ssl',
				ref : 'portsslField',
				fieldLabel : dgettext('plugin_files', 'Server SSL port'),
				emptyText : '443',
				anchor : '100%'
			},
			{
				xtype : 'textfield',
				name : 'zarafa/v1/contexts/files/files_path',
				ref : 'pathField',
				fieldLabel : String.format(dgettext('plugin_files', 'Path to {0}'), container.getSettingsModel().get('zarafa/v1/plugins/files/button_name')),
				emptyText : '',
				anchor : '100%',
				validator: function(value) {
					if (/.*\/remote\.php\/webdav\/$|.*\/files\/webdav\.php\/$/g.test(value)) {
						return dgettext('plugin_files', 'No trailing slashes!');
					}
					
					return true;
				}
			},
			{
				xtype : 'checkbox',
				name : 'zarafa/v1/contexts/files/session_auth',
				ref : 'sessionAuth',
				fieldLabel : dgettext('plugin_files', 'Use Zarafa credentials for authentication'),
				lazyInit : false,
				listeners : {
					check : this.onCheck,
					scope : this
				}
			},
			{
				xtype : 'textfield',
				name : 'zarafa/v1/contexts/files/username',
				ref : 'usernameField',
				fieldLabel : dgettext('plugin_files', 'Username'),
				emptyText : 'test',
				anchor : '100%'
			},
			{
				xtype : 'textfield',
				name : 'zarafa/v1/contexts/files/password',
				ref : 'passwordField',
				inputType : 'password',
				fieldLabel : dgettext('plugin_files', 'Password'),
				emptyText : 'test',
				anchor : '100%'
			},
			{
				xtype : 'checkbox',
				name : 'zarafa/v1/contexts/files/use_ssl',
				ref : 'useSSL',
				fieldLabel : dgettext('plugin_files', 'Use SSL connections'),
				lazyInit : false,
				listeners : {
					check : this.onCheck,
					scope : this
				}
			},
			{
				xtype : 'combo',
				name : 'zarafa/v1/contexts/files/backend',
				ref : 'backendCombo',
				fieldLabel : dgettext('plugin_files', 'Backend to use'),
				store : backendStore,
				mode: 'local',
				triggerAction: 'all',
				displayField: 'text',
				valueField: 'type',
				lazyInit: false,
				forceSelection: true,
				editable: false,
				autoSelect: true,
				lazyInit : false
			}]
		});

		Zarafa.plugins.files.settings.SettingsFilesWidget.superclass.constructor.call(this, config);
	},

	/**
	 * Called by the {@link Zarafa.settings.ui.SettingsCategory Category} when
	 * it has been called with {@link zarafa.settings.ui.SettingsCategory#update}.
	 * This is used to load the latest version of the settings from the
	 * {@link Zarafa.settings.SettingsModel} into the UI of this category.
	 * @param {Zarafa.settings.SettingsModel} settingsModel The settings to load
	 */
	update : function(settingsModel) {
		this.model = settingsModel;
		this.serverField.setValue(settingsModel.get(this.serverField.name));
		this.portField.setValue(settingsModel.get(this.portField.name));
		this.portsslField.setValue(settingsModel.get(this.portsslField.name));
		this.pathField.setValue(settingsModel.get(this.pathField.name));
		this.sessionAuth.setValue(settingsModel.get(this.sessionAuth.name));
		this.usernameField.setValue(settingsModel.get(this.usernameField.name));
		this.passwordField.setValue(Zarafa.plugins.files.data.Helper.Base64.decode(settingsModel.get(this.passwordField.name)));
		this.useSSL.setValue(settingsModel.get(this.useSSL.name));
		this.backendCombo.setValue(settingsModel.get(this.backendCombo.name));
		
		if (settingsModel.get(this.useSSL.name) === true) {
			this.portsslField.show();
			this.portsslField.label.show();
			this.portField.hide();
			this.portField.label.hide();
		} else {
			this.portsslField.hide();
			this.portsslField.label.hide();
			this.portField.show();
			this.portField.label.show();
		}
		
		if (settingsModel.get(this.sessionAuth.name) === true) {
			this.usernameField.hide();
			this.usernameField.label.hide();
			this.passwordField.hide();
			this.passwordField.label.hide();
		} else {
			this.usernameField.show();
			this.usernameField.label.show();
			this.passwordField.show();
			this.passwordField.label.show();
		}
	},

	/**
	 * Called by the {@link Zarafa.settings.ui.SettingsCategory Category} when
	 * it has been called with {@link zarafa.settings.ui.SettingsCategory#updateSettings}.
	 * This is used to update the settings from the UI into the {@link Zarafa.settings.SettingsModel settings model}.
	 * @param {Zarafa.settings.SettingsModel} settingsModel The settings to update
	 */
	updateSettings : function(settingsModel) {
		// We must either set the requested subject, or the default subject
		var server	 = this.serverField.getValue()	 || this.serverField.emptyText;
		var port	 = this.portField.getValue()	 || this.portField.emptyText;
		var portssl	 = this.portsslField.getValue()	 || this.portsslField.emptyText;
		var path	 = this.pathField.getValue()	 || this.pathField.emptyText;
		var username = this.usernameField.getValue() || this.usernameField.emptyText;
		var password = this.passwordField.getValue() || this.passwordField.emptyText;
		var backend	 = this.backendCombo.getValue() || "webdav";
		
		settingsModel.beginEdit();
		settingsModel.set(this.serverField.name, server);
		settingsModel.set(this.portField.name, port);
		settingsModel.set(this.portsslField.name, portssl);
		settingsModel.set(this.pathField.name, path);
		settingsModel.set(this.sessionAuth.name, this.sessionAuth.getValue());
		settingsModel.set(this.usernameField.name, username);
		settingsModel.set(this.passwordField.name, Zarafa.plugins.files.data.Helper.Base64.encode(password));
		settingsModel.set(this.useSSL.name, this.useSSL.getValue());
		settingsModel.set(this.backendCombo.name, backend);
		settingsModel.endEdit();
		
		// also update the session to make sure we use the actual data
		// FIXME: this needs to be called after the store commit...
		container.getRequest().singleRequest(
			'filesmodule',
			'updatesession',
			{},
			new Zarafa.plugins.files.data.ResponseHandler({
				successCallback : this.updateSessionDone.createDelegate(this)
			})
		);
	},
	
	/**
	 * Updating session done =)
	 * @param {Object} response
	 * @private
	 */
	updateSessionDone : function(response) {
		if(response.status === true) {
			// this is needed, because the previous request is done before all data is saved -.-
			container.getRequest().singleRequest(
				'filesmodule',
				'updatesession',
				{},
				null
			);
			Zarafa.plugins.files.data.Actions.reloadNavigatorTree();
			container.getNotifier().notify('info.files', dgettext('plugin_files', 'Session updated!'), dgettext('plugin_files', 'Settings applied successfully.'));
		} else
			container.getNotifier().notify('error', dgettext('plugin_files', 'Session update failed!'), dgettext('plugin_files', 'Session update failed, please log in again.'));
	},	

	/**
	 * Event handler called when checkbox has been modified
	 *
	 * @param {Ext.form.CheckBox} checkbox Checkbox element from which the event originated
	 * @param {Boolean} checked State of the checkbox
	 * @private
	 */
	onCheck : function(checkbox, checked) {		
		if (checkbox.name === this.sessionAuth.name && checked) {
			this.usernameField.hide();
			this.usernameField.label.hide();
			this.passwordField.hide();
			this.passwordField.label.hide();
		} else if(checkbox.name === this.sessionAuth.name) {
			this.usernameField.show();
			this.usernameField.label.show();
			this.passwordField.show();
			this.passwordField.label.show();
		}
		
		if (checkbox.name === this.useSSL.name && checked) {
			this.portsslField.show();
			this.portsslField.label.show();
			this.portField.hide();
			this.portField.label.hide();
		} else if(checkbox.name === this.useSSL.name) {
			this.portsslField.hide();
			this.portsslField.label.hide();
			this.portField.show();
			this.portField.label.show();
		}
	}
});

Ext.reg('Zarafa.plugins.files.settingsfileswidget', Zarafa.plugins.files.settings.SettingsFilesWidget);
Ext.namespace('Zarafa.plugins.files.settings');

/**
 * @class Zarafa.files.settings.SettingsFilesVersionWidget
 * @extends Zarafa.settings.ui.SettingsWidget
 * @xtype Zarafa.plugins.files.settingsfileswidget
 *
 * The {@link Zarafa.settings.ui.SettingsWidget widget} for configuring
 * the general files options in the {@link Zarafa.files.settings.SettingsFilesCategory files category}.
 */
Zarafa.plugins.files.settings.SettingsFilesVersionWidget = Ext.extend(Zarafa.settings.ui.SettingsWidget, {
	/**
	 * @constructor
	 * @param {Object} config Configuration object
	 */
	constructor : function(config) {
		config = config || {};
		
		Ext.applyIf(config, {
			title : dgettext('plugin_files', 'Version information'),
			layout : 'form',
			items :[{
				xtype : 'displayfield',
				fieldLabel : dgettext('plugin_files', 'Files Backend'),
				value : Zarafa.plugins.files.data.Version.getFilesVersion(),
				htmlEncode : true
			},
			{
				xtype : 'displayfield',
				fieldLabel : dgettext('plugin_files', 'Plugin'),
				value : Zarafa.plugins.files.data.Version.getPluginVersion(),
				htmlEncode : true
			},
			{
				xtype : 'displayfield',
				fieldLabel : dgettext('plugin_files', 'Maximum upload size'),
				value : Ext.util.Format.fileSize(Zarafa.plugins.files.data.Dynamics.getMaxUploadFilesize()),
				htmlEncode : true
			}]
		});

		Zarafa.plugins.files.settings.SettingsFilesVersionWidget.superclass.constructor.call(this, config);
	}
});

Ext.reg('Zarafa.plugins.files.settingsfilesversionwidget', Zarafa.plugins.files.settings.SettingsFilesVersionWidget);
Ext.namespace('Zarafa.plugins.files.settings');

/**
 * @class Zarafa.files.settings.SettingsFilesQuotaWidget
 * @extends Zarafa.settings.ui.SettingsWidget
 * @xtype Zarafa.plugins.files.settingsfilesquotawidget
 *
 * The {@link Zarafa.settings.ui.SettingsWidget widget} for configuring
 * the general files options in the {@link Zarafa.files.settings.SettingsFilesCategory files category}.
 */
Zarafa.plugins.files.settings.SettingsFilesQuotaWidget = Ext.extend(Zarafa.settings.ui.SettingsWidget, {
	/**
	 * @constructor
	 * @param {Object} config Configuration object
	 */
	constructor : function(config) {
		config = config || {};
		
		Ext.applyIf(config, {
			title : dgettext('plugin_files', 'Quota information'),
			layout : 'form',
			items :[{
				xtype : 'zarafa.plugins.files.quotabar',
				width : 400,
				hidden: true,
				ref : 'quotaBar',
				storeSize : 0,
				warnQuota : 0,
				hardQuota : 0
			},{
				xtype : 'displayfield',
				width : 400,
				hideLabel : true,
				ref : 'unavailableQuotaInfo',
				hidden: true,
				value : dgettext('plugin_files', 'Quota information is not available.')
			},{
				xtype : 'displayfield',
				hideLabel : true,
				width : 400,
				ref : 'quotaInfo'
			}]
		});

		Zarafa.plugins.files.settings.SettingsFilesQuotaWidget.superclass.constructor.call(this, config);
		
		this.on('afterrender', this.updateQuotaInfo, this);
	},
	
	/**
	 * Function sets information in quota bar widget,
	 * it updates quota bar and information string aswell.
	 * @private
	 */
	updateQuotaInfo : function()
	{
		var storeSize = Zarafa.plugins.files.data.Dynamics.getCurrentStoreSize();
		var hardQuota = storeSize + Zarafa.plugins.files.data.Dynamics.getAvailableStoreSize();
		var warnQuota = hardQuota - 100 * 1024; // Warnquota is 100MB below hard Quota.;

		// Create quota-info string to display in displayfield.
		var quotaInfo = String.format(dgettext('plugin_files', '{0} of disk space is used.'), Ext.util.Format.fileSize(storeSize));
		var quotaInfoHTML = '<span class="zarafa-quota-string">' + quotaInfo + '</span>';

		if(hardQuota && hardQuota > 0) {
			// If hard quota is set then show quotabar.
			this.quotaBar.setStoreSize(storeSize);
			this.quotaBar.setHardQuota(hardQuota);
			this.quotaBar.setWarnQuota(warnQuota);
			
			this.quotaBar.setVisible(true);
			this.unavailableQuotaInfo.setVisible(false);

			// Add hard quota info in quota-info string.
			quotaInfo = this.getQuotaSuggestionString(hardQuota, storeSize);
			this.quotaInfo.setVisible(true);
			if(!Ext.isEmpty(quotaInfo)) {
				quotaInfoHTML += ' ' + quotaInfo;
			}
		} else {
			// If any of the hard quota is not set then show message.
			this.quotaBar.setVisible(false);
			this.quotaInfo.setVisible(false);
			this.unavailableQuotaInfo.setVisible(true);
		}

		this.quotaInfo.setValue(quotaInfoHTML);
	},
	
	/**
	 * Function returns info/warning message according to
	 * store's usage and quota information.
	 * @param {Int} hardQuota hard quota limit for user
	 * @param {Int} storeSize size of user's store
	 * @return {String} info/warning message.
	 * @private
	 */
	getQuotaSuggestionString : function(hardQuota, storeSize)
	{
		if(!Ext.isDefined(storeSize))
			return;

		if (hardQuota && storeSize > hardQuota) {
			return String.format(dgettext('plugin_files', 'You have exceeded quota ({0}), you can not store more files on the server.'), Ext.util.Format.fileSize(hardQuota));
		} else if (hardQuota && storeSize < hardQuota) {
			return String.format(dgettext('plugin_files', "At {0} you won't be able to store files on the server."), Ext.util.Format.fileSize(hardQuota));
		}
	}
});

Ext.reg('Zarafa.plugins.files.settingsfilesquotawidget', Zarafa.plugins.files.settings.SettingsFilesQuotaWidget);
Ext.namespace('Zarafa.plugins.files.settings');

/**
 * @class Zarafa.plugins.files.settings.SettingsFilesResetSettingsWidget
 * @extends Zarafa.settings.ui.SettingsWidget
 * @xtype Zarafa.plugins.files.settingsfilesresetsettingswidget
 *
 * The Reset Settings widget
 */
Zarafa.plugins.files.settings.SettingsFilesResetSettingsWidget= Ext.extend(Zarafa.settings.ui.SettingsWidget, {

	/**
	 * The loadMask object which will be shown when reset request is being sent to the server.
	 * @property
	 * @type Zarafa.common.ui.LoadMask
	 */
	loadMask : undefined,

	/**
	 * @constructor
	 * @param {Object} config Configuration object
	 */
	constructor : function(config) {
		config = config || {};

		Ext.applyIf(config, {
			title : _('Reset Files settings'),
			layout : 'form',
			items : [{
				xtype : 'displayfield',
				hideLabel : true,
				value : _('Resets Files settings to their original defaults')
			},{
				xtype : 'button',
				text : _('Reset Files settings'),
				width : 150,
				handler : this.onResetSettings,
				scope : this
			}]
		});

		Zarafa.plugins.files.settings.SettingsFilesResetSettingsWidget.superclass.constructor.call(this, config);
	},

	/**
	 * Event handler when the "Reset Files Settings" button was clicked.
	 * This will {@link Zarafa.settings.SettingsModel#reset reset} the 
	 * {@link Zarafa.settings.data.SettingsDefaultValue values} of the settings.
	 * @private
	 */
	onResetSettings : function() {
		var message = _('Your Files\'s settings will be restored to their default condition. Are you sure you want to reset all Files settings?');
		message += '<br/><br/>';
		message += _('WebApp will automatically restart in order for these changes to take effect');
		message += '<br/>';

		Zarafa.common.dialogs.MessageBox.addCustomButtons({
			title: _('Reset Files settings'),
			msg : message,
			icon: Ext.MessageBox.QUESTION,
			fn : this.resetDefaultSettings,
			customButton : [{
				text : _('Reset'),
				name : 'reset'
			}, {
				text : _('Cancel'),
				name : 'cancel'
			}],
			scope : this
		});

	},

	/**
	 * Event handler for {@link #onResetSettings}. This will check if the user
	 * wishes to reset the default settings or not.
	 * @param {String} button The button which user pressed.
	 * @private
	 */
	resetDefaultSettings : function(button)
	{
		if (button === 'reset') {
			var settingsModel = container.getSettingsModel();
			settingsModel.reset('zarafa/v1/contexts/files');
			settingsModel.save();

			this.loadMask = new Zarafa.common.ui.LoadMask(Ext.getBody(), {
				msg : '<b>' + _('Webapp is reloading, Please wait.') + '</b>'
			});

			this.loadMask.show();

			this.mon(settingsModel, 'save', this.onSettingsSave, this);
			this.mon(settingsModel, 'exception', this.onSettingsException, this);
		}

	},

	/**
	 * Called when the {@link Zarafa.settings.SettingsModel} fires the {@link Zarafa.settings.SettingsModel#save save}
	 * event to indicate the settings were successfully saved and it will forcefully realod the webapp.
	 * @param {Zarafa.settings.SettingsModel} model The model which fired the event.
	 * @param {Object} parameters The key-value object containing the action and the corresponding
	 * settings which were saved to the server.
	 * @private
	 */
	onSettingsSave : function(model, parameters)
	{
		if(parameters.action === Zarafa.core.Actions['reset']) {
			this.mun(model, 'save', this.onSettingsSave, this);
			this.mun(model, 'exception', this.onSettingsException, this);
			Zarafa.core.Util.reloadWebapp();
		}
	},

	/**
	 * Called when the {@link Zarafa.settings.SettingsModel} fires the {@link Zarafa.settings.SettingsModel#exception exception}
	 * event to indicate the settings were not successfully saved.
	 * @param {Zarafa.settings.SettingsModel} model The settings model which fired the event
	 * @param {String} type The value of this parameter will be either 'response' or 'remote'. 
	 * @param {String} action Name of the action (see {@link Ext.data.Api#actions}).
	 * @param {Object} options The object containing a 'path' and 'value' field indicating
	 * respectively the Setting and corresponding value for the setting which was being saved.
	 * @param {Object} response The response object as received from the PHP-side
	 * @private
	 */
	onSettingsException : function(model, type, action, options, response)
	{
		if(options.action === Zarafa.core.Actions['reset']) {
			this.loadMask.hide();
			// Remove event handlers
			this.mun(model, 'save', this.onSettingsSave, this);
			this.mun(model, 'exception', this.onSettingsException, this);
		}
	}
});

Ext.reg('Zarafa.plugins.files.settingsfilesresetsettingswidget', Zarafa.plugins.files.settings.SettingsFilesResetSettingsWidget);Ext.namespace('Zarafa.plugins.files.settings');

/**
 * @class Zarafa.plugins.files.settings.SettingsFilesCategory
 * @extends Zarafa.settings.ui.SettingsCategory
 * @xtype Zarafa.plugins.files.settingsfilescategory
 *
 * The files category for users which will
 * allow the user to configure Files related settings
 */
Zarafa.plugins.files.settings.SettingsFilesCategory = Ext.extend(Zarafa.settings.ui.SettingsCategory, {
	// Insertion points for this class
	/**
	 * @insert context.settings.category.files
	 * Insertion point to register new {@link Zarafa.settings.ui.SettingsWidget widgets}
	 * for the {@link Zarafa.files.settings.SettingsFilesCategory Owncoud Category}.
	 * @param {Zarafa.files.settings.SettingsFilesCategory} category The files
	 * category to which the widgets will be added.
	 */

	/**
	 * @constructor
	 * @param {Object} config Configuration object
	 */
	constructor : function(config) {
		config = config || {};

		Ext.applyIf(config, {
			title : container.getSettingsModel().get('zarafa/v1/plugins/files/button_name'),
			categoryIndex : 1,
			iconCls : 'icon_files_category',
			items : [{
				xtype : 'Zarafa.plugins.files.settingsfilescomponentswidget'	// enable/disable plugins
			},
			{
				xtype : 'Zarafa.plugins.files.settingsfileswidget'			// files specific settings like server address...
			},
			{
				xtype : 'Zarafa.plugins.files.settingsfilesquotawidget'		// files plugin quota
			},
			{
				xtype : 'Zarafa.plugins.files.settingsfilesversionwidget'		// files plugin version
			},
			{
				xtype : 'Zarafa.plugins.files.settingsfilesresetsettingswidget'		// files plugin reset
			},
			container.populateInsertionPoint('context.settings.category.files', this)
			]
		});

		Zarafa.plugins.files.settings.SettingsFilesCategory.superclass.constructor.call(this, config);
	}
});

Ext.reg('Zarafa.plugins.files.settingsfilescategory', Zarafa.plugins.files.settings.SettingsFilesCategory);
Ext.namespace('Zarafa.plugins.files.dialogs');

/**
 * @class Zarafa.plugins.files.dialogs.AttachFromFilesTreePanel
 * @extends Ext.tree.TreePanel
 * @xtype Zarafa.plugins.files.attachfromfilestreepanel
 *
 * Shows tree of all user files from Files
 */
Zarafa.plugins.files.dialogs.AttachFromFilesTreePanel = Ext.extend(Ext.tree.TreePanel, {

	/**
	 * Global Email Record
	 * only set via webdav browser
	 */
	emailRecord : undefined,

	/**
	 * @constructor
	 * @param {Object} config
	 */
	constructor : function(config) {
		config = config || {};
		
		if(Ext.isDefined(config.emailrecord)) 
			this.emailRecord = config.emailrecord;
			
		Ext.applyIf(config, {
			root: {
				nodeType: 'async',
				text: '/',
				id: '/',
				expanded : true
			},
			autoScroll: true,
			viewConfig: {
				style : { overflow: 'auto', overflowX: 'hidden' }
			},
			maskDisabled: true,
			loader : new Zarafa.plugins.files.data.DirectoryLoader({loadfiles: true}),
			buttons : [
				this.createActionButtons()
			]
		});
		Zarafa.plugins.files.dialogs.AttachFromFilesTreePanel.superclass.constructor.call(this, config);
	},

	/**
	 * Creates action button for adding file
	 * from Files to email as attachment
	 * @return {Array}
	 * @private
	 */
	createActionButtons : function() {
		return [{
			xtype   : 'button',
			text    : '&nbsp;&nbsp;&nbsp;&nbsp;' + dgettext('plugin_files', 'Add attachment'),
			tooltip : {
				title : dgettext('plugin_files', 'Add attachment'),
				text  : dgettext('plugin_files', 'Add selected attachment from files to email attachment.')
			},
			iconCls : 'icon_files_category',
			handler : this.downloadSelectedFilesFromFilesToTmp,
			scope   : this
		}];
	},

	/**
	 * Sends a query with ids of selected files from user's Files folder
	 * @private
	 */
	downloadSelectedFilesFromFilesToTmp : function() {
		var selectedNodes =  this.getChecked();
		var idsList = [];
		var emailRecord = this.dialog.record;
		
		if(Ext.isDefined(this.emailRecord))
			emailRecord = this.emailRecord;
		
		var attachmentStore = emailRecord.getAttachmentStore();
		var max_file_size = container.getSettingsModel().get('zarafa/v1/main/attachments/max_attachment_size');
		
		var size_exceeded = false;
		
		Ext.each(selectedNodes, function(node, index) {
			if(node.attributes.filesize > max_file_size) {
				Zarafa.common.dialogs.MessageBox.show({
					title : dgettext('plugin_files', 'Warning'),
					msg : String.format(dgettext('plugin_files', 'The file {0} is too large!'), node.attributes.filename) + ' (' + dgettext('plugin_files', 'max') + ': ' + Ext.util.Format.fileSize(max_file_size) + ')',
					icon : Zarafa.common.dialogs.MessageBox.WARNING,
					buttons : Zarafa.common.dialogs.MessageBox.OK
				});
				size_exceeded = true;
				return false;
			}
			idsList.push( node.id );
		});
		
		if(!size_exceeded) {
			if(idsList.length < 1) {
				Zarafa.common.dialogs.MessageBox.show({
					title : dgettext('plugin_files', 'Warning'),
					msg : dgettext('plugin_files', 'You have to choose at least one file!'),
					icon : Zarafa.common.dialogs.MessageBox.WARNING,
					buttons : Zarafa.common.dialogs.MessageBox.OK
				});
			} else {
				try {
					this.disable();
					container.getRequest().singleRequest(
						'filesmodule',
						'download-to-tmp',
						{
							ids : idsList,
							dialog_attachments: attachmentStore.getId()
						},
						new Zarafa.plugins.files.data.ResponseHandler({
							successCallback : this.addDownloadedFilesAsAttachmentToEmail.createDelegate(this)
						})
					);
				} catch (e) {
					Zarafa.common.dialogs.MessageBox.show({
						title : dgettext('plugin_files', 'Warning'),
						msg : e.getMessage(),
						icon : Zarafa.common.dialogs.MessageBox.WARNING,
						buttons : Zarafa.common.dialogs.MessageBox.OK
					});
				}
			}
		}
	},

	/**
	 * Converts received file information to attachment record
	 * @param {Object} downloadedFileInfo
	 * @private
	 */
	convertDownloadedFileInfoToAttachmentRecord : function(downloadedFileInfo) {
		var attachmentRecord = Zarafa.core.data.RecordFactory.createRecordObjectByObjectType(Zarafa.core.mapi.ObjectType.MAPI_ATTACH);

		attachmentRecord.set('tmpname', downloadedFileInfo.tmpname);
		attachmentRecord.set('name', downloadedFileInfo.name);
		attachmentRecord.set('size', downloadedFileInfo.size);
		return attachmentRecord;
	},

	/**
	 * Adds files received from the user's Files folder to
	 * the email as attachments
	 * @param {Array} downloadedFilesInfoArray
	 * @private
	 */
	addDownloadedFilesAsAttachmentToEmail : function(downloadedFilesInfoArray) {
		var emailRecord = this.dialog.record;
		if(Ext.isDefined(this.emailRecord))
			emailRecord = this.emailRecord;
			
		var attachmentStore = emailRecord.getAttachmentStore();

		var attachmentRecord = null;
		Ext.each(downloadedFilesInfoArray, function(downloadedFileInfo, index) {
			attachmentRecord = this.convertDownloadedFileInfoToAttachmentRecord(downloadedFileInfo);
			attachmentStore.add(attachmentRecord);
		}, this);
		this.dialog.close();
	}
});

Ext.reg('Zarafa.plugins.files.attachfromfilestreepanel', Zarafa.plugins.files.dialogs.AttachFromFilesTreePanel);
Ext.namespace('Zarafa.plugins.files.dialogs');

/**
 * @class Zarafa.plugins.files.dialogs.AttachFromFilesContentPanel
 * @extends Zarafa.core.ui.ContentPanel
 * @xtype Zarafa.plugins.files.attachfromfilescontentpanel
 *
 * The content panel which shows the hierarchy tree of Files account files.
 */
Zarafa.plugins.files.dialogs.AttachFromFilesContentPanel = Ext.extend(Zarafa.core.ui.ContentPanel, {

	/**
	 * @cfg {Zarafa.core.data.IPMRecord} record The record to which
	 * we need to add attachment.
	 */
	record : null,

	/**
	 * @constructor
	 * @param {Object} config Configuration structure
	 */
	constructor : function(config) {
		config = config || {};
		Ext.applyIf(config, {
			layout : 'fit',
			title : String.format(dgettext('plugin_files', '{0} Attachment'), container.getSettingsModel().get('zarafa/v1/plugins/files/button_name')),
			closeOnSave : true,
			width : 400,
			height : 300,
			//Add panel
			items : [{
				xtype : 'Zarafa.plugins.files.attachfromfilestreepanel',
				emailrecord : config.emailrecord,
				ref : 'treePanel'
			}]
		});

		Zarafa.plugins.files.dialogs.AttachFromFilesContentPanel.superclass.constructor.call(this, config);
	}
});

Ext.reg('Zarafa.plugins.files.attachfromfilescontentpanel', Zarafa.plugins.files.dialogs.AttachFromFilesContentPanel);
Ext.namespace('Zarafa.plugins.files.dialogs');

/**
 * @class Zarafa.plugins.files.dialogs.SaveToFilesTreePanel
 * @extends Ext.tree.TreePanel
 * @xtype Zarafa.plugins.files.savetofilestreepanel
 *
 * Shows tree of all user files from Files
 */
Zarafa.plugins.files.dialogs.SaveToFilesTreePanel = Ext.extend(Ext.tree.TreePanel, {

	/**
	 * Holds the selected folder, in which the attachment will be stored
	 */
	selectedFolder : null,
	
	/**
	 * The response object from the content panel
	 */
	response : null,

	/**
	 * @constructor
	 * @param {Object} config
	 */
	constructor : function(config) {
		config = config || {};
		this.response = config.response;
		
		Ext.applyIf(config, {
			root: {
				nodeType: 'async',
				text: '/',
				id: '/',
				expanded : true
			},
			autoScroll: true,
			viewConfig: {
				style	:	{ overflow: 'auto', overflowX: 'hidden' }
			},
			maskDisabled: true,
			listeners: {
				click: function(n) {
					this.selectedFolder = n.attributes.id;
				}
			},
			loader : new Zarafa.plugins.files.data.DirectoryLoader({loadfiles: false}),
			buttons : [
				this.createActionButtons()
			]
		});
		Zarafa.plugins.files.dialogs.SaveToFilesTreePanel.superclass.constructor.call(this, config);
	},

	/**
	 * Creates action button for adding file
	 * from Files to email as attachment
	 * @return {Array}
	 * @private
	 */
	createActionButtons : function() {
		return [{
			xtype   : 'button',
			text    : dgettext('plugin_files', 'New folder'),
			tooltip : {
				title   : dgettext('plugin_files', 'New folder'),
				text    : dgettext('plugin_files', 'Create a new folder') 
			},
			handler : this.newFolder,
			scope   : this
		},
		{
			xtype   : 'button',
			text    : '&nbsp;&nbsp;&nbsp;&nbsp;' + dgettext('plugin_files', 'Save'),
			tooltip : {
				title   : dgettext('plugin_files', 'Store attachment'),
				text    : String.format(dgettext('plugin_files', 'Store attachment to the selected {0} folder.'), container.getSettingsModel().get('zarafa/v1/plugins/files/button_name'))
			},
			iconCls : 'icon_files_category',
			handler : this.uploadFile,
			scope   : this
		}];
	},

	/**
	 * Uploads the prepared attachment to Files
	 * @private
	 */
	uploadFile : function() {
		if(!Ext.isDefined(this.selectedFolder) || Ext.isEmpty(this.selectedFolder)) {
			Zarafa.plugins.files.data.Actions.msgWarning(dgettext('plugin_files', 'You have to choose a folder!'));
		} else {
			// create array to check for dups
			var checkMe = new Array();
			for (var i = 0, len = this.response.count; i < len; i++) {
				checkMe[i] = {
					id: (this.selectedFolder + this.response.items[i].filename),
					isFolder: false
				};
			}

			try {
				container.getRequest().singleRequest(
					'filesmodule',
					'checkifexists',
					{
						records: checkMe,
						destination: this.selectedFolder
					},
					new Zarafa.plugins.files.data.ResponseHandler({
						successCallback : this.checkForDuplicateFileDone.createDelegate(this)
					})
				);
			} catch (e) {
				Zarafa.plugins.files.data.Actions.msgWarning(e.message);
				
				return false;
			}
		}
	},
	
	/**
	 * Upload done =)
	 * @param {Object} response
	 * @private
	 */
	uploadDone : function(response) {
		if(response.status === true)
			container.getNotifier().notify('info.files', dgettext('plugin_files', 'Uploaded'), String.format(dgettext('plugin_files', 'Attachment successfully stored to {0}'), container.getSettingsModel().get('zarafa/v1/plugins/files/button_name')));
		else
			container.getNotifier().notify('error', dgettext('plugin_files', 'Upload Failed'), String.format(dgettext('plugin_files', 'Attachment could not be stored in {0}! Error:'), container.getSettingsModel().get('zarafa/v1/plugins/files/button_name')) + ' ' + response.status);

		this.dialog.close();
	},	
	
	/**
	 * Creates a new files folder
	 * @private
	 */
	newFolder : function() {
		if(!Ext.isDefined(this.selectedFolder) || Ext.isEmpty(this.selectedFolder)) {
			Zarafa.plugins.files.data.Actions.msgWarning(dgettext('plugin_files', 'You have to choose a folder!'));
		} else {
			Zarafa.common.dialogs.MessageBox.prompt(dgettext('plugin_files', 'Folder Name'), dgettext('plugin_files', 'Please enter a foldername'), this.checkForDuplicateFolder, this);
		}
	},
	
	/**
	 * This function is called after the {@Zarafa.plugins.files.data.FilesStore} has loaded the target folder.
	 * It will check if one of the selected files already exists in the store. If there is a duplicate file
	 * a warning will be shown.
	 *
	 * @param {String} button
	 * @param {String} text Text that was entered in the input box
	 * @private
	 */
	checkForDuplicateFolder : function(button, text) {
		if(button === "ok") {
			// check if foldername contains a / - if so, dont rename it
			if(!Zarafa.plugins.files.data.Helper.File.isValidFilename(text)) {
				Zarafa.plugins.files.data.Actions.msgWarning(dgettext('plugin_files', 'Incorrect foldername'));
			} else {
				try {
					container.getRequest().singleRequest(
						'filesmodule',
						'checkifexists',
						{
							id : this.selectedFolder + text,
							isfolder : true
						},
						new Zarafa.plugins.files.data.ResponseHandler({
							successCallback : this.checkForDuplicateFolderDone.createDelegate(this, [text], true)
						})
					);
				} catch (e) {
					Zarafa.plugins.files.data.Actions.msgWarning(e.message);
					
					return false;
				}
			}
		}
	},
	
	/**
	 * Function is called after completing the duplicate check for a folder.
	 *
	 * @param {Object} response
	 * @param {Object} foldername New foldername that will be created if no duplicate was found
	 * @private
	 */
	checkForDuplicateFolderDone : function (response, foldername) {
		if(response.duplicate === false) {
			this.createRemoteFolder(foldername);
		} else {
			Zarafa.plugins.files.data.Actions.msgWarning(dgettext('plugin_files', 'Folder already exists'));
		}
	},
	
	/**
	 * Function is called after completing the duplicate check.
	 *
	 * @param {Object} response
	 * @private
	 */
	checkForDuplicateFileDone : function (response) {
		if(response.duplicate === false) {
			this.doUpload();
		} else {
			Ext.MessageBox.confirm(
				dgettext('plugin_files', 'Confirm overwrite'), 
				dgettext('plugin_files', 'File already exists. Do you want to overwrite it?'),
				this.doUpload,
				this
			);
		}
	},
	
	/** 
	 * Start uploading the selected file to the backend.
	 *
	 * @param {String} button If button is set it must be "yes" to start the upload.
	 * @private
	 */
	doUpload : function (button) {
		if(!Ext.isDefined(button) || button === "yes") {
			container.getNotifier().notify('info.files', dgettext('plugin_files', 'Uploading...'), dgettext('plugin_files', 'Please be patient while the files are uploaded...'));
			try {
				this.disable();
				container.getRequest().singleRequest(
					'filesmodule',
					'uploadtooc',
					{
						items: this.response.items,
						count: this.response.count,
						type: this.response.type,
						destdir: this.selectedFolder
					},
					new Zarafa.plugins.files.data.ResponseHandler({
						successCallback : this.uploadDone.createDelegate(this)
					})
				);
			} catch (e) {
				Zarafa.plugins.files.data.Actions.msgWarning(e.message);
			}
		}
	},
	
	/**
	 * This function will create a new folder on the backend.
	 *
	 * @param {Object} foldername New foldername that will be created
	 * @private
	 */
	createRemoteFolder : function (foldername) {
		try {
			container.getRequest().singleRequest(
				'filesmodule',
				'createdir',
				{
					dirname : this.selectedFolder + foldername,
					basedir : this.selectedFolder
				},
				new Zarafa.plugins.files.data.ResponseHandler({
					successCallback : this.createDirDone.createDelegate(this)
				})
			);
		} catch (e) {
			Zarafa.plugins.files.data.Actions.msgWarning(e.message);
		}
	},
	
	/**
	 * Function is called after a directory has been created on the server.
	 *
	 * @param {Object} response
	 * @private
	 */
	createDirDone : function(response) {
		if(response.status === true) {
			container.getNotifier().notify('info.files', dgettext('plugin_files', 'Created'), dgettext('plugin_files', 'Directory created!'));

			var node = this.getNodeById(response.basedir);
		
			if(Ext.isDefined(node)) {
				if(!node.isLeaf()) {
					node.reload();
				} else {
					var currentfolder = (response.basedir.substr(-1) == '/') ? response.basedir.substr(0, response.basedir.length - 1) : response.basedir;
					var parentnode = this.getNodeById(currentfolder.match( /.*\// )); // load parent pathname
					if(Ext.isDefined(parentnode)) {
						parentnode.on("expand", this.reloadParentDone.createDelegate(this, [response.basedir]), this, {single: true});						
						parentnode.reload();
					}
				}
			}
		} else {
			container.getNotifier().notify('error', dgettext('plugin_files', 'Creation failed'), dgettext('plugin_files', 'Directory not created!'));
		}
	},
	
	/**
	 * This function is called after the parentnode has been reloaded.
	 * It is used to select a subnode of the parent node and expand it.
	 *
	 * @private
	 * @param {String} subnode Foldername of the subnode to expand
	 */
	reloadParentDone : function (subnode) {
		var node = this.getNodeById(subnode);
		
		if(Ext.isDefined(node)) {
			node.expand();
		}
	}
});

Ext.reg('Zarafa.plugins.files.savetofilestreepanel', Zarafa.plugins.files.dialogs.SaveToFilesTreePanel);
Ext.namespace('Zarafa.plugins.files.dialogs');

/**
 * @class Zarafa.plugins.files.dialogs.SaveToFilesContentPanel
 * @extends Zarafa.core.ui.ContentPanel
 * @xtype Zarafa.plugins.files.savetofilescontentpanel
 *
 * The content panel which shows the hierarchy tree of Files account files.
 */
Zarafa.plugins.files.dialogs.SaveToFilesContentPanel = Ext.extend(Zarafa.core.ui.ContentPanel, {

	/**
	 * @constructor
	 * @param config Configuration structure
	 */
	constructor : function(config) {
		config = config || {};

		Ext.applyIf(config, {
			layout : 'fit',
			title : String.format(dgettext('plugin_files', '{0} Attachment'), container.getSettingsModel().get('zarafa/v1/plugins/files/button_name')),
			closeOnSave : true,
			width : 400,
			height : 300,
			//Add panel
			items : [{
				xtype : 'Zarafa.plugins.files.savetofilestreepanel',
				ref : 'treePanel',
				response : config.record
			}]
		});

		Zarafa.plugins.files.dialogs.SaveToFilesContentPanel.superclass.constructor.call(this, config);
	}
});

Ext.reg('Zarafa.plugins.files.savetofilescontentpanel' , Zarafa.plugins.files.dialogs.SaveToFilesContentPanel);
Ext.namespace('Zarafa.plugins.files');

/**
 * @class Zarafa.plugins.files.FilesAttachmentPlugin
 * @extends Zarafa.core.Plugin
 * This class is used for adding files from the users's Files folder
 * to his emails as attachments
 */
Zarafa.plugins.files.AttachFromFilesPlugin = Ext.extend(Zarafa.core.Plugin, {

	/**
	 * @constructor
	 * @param {Object} config
	 */
	constructor : function(config) {
		config = config || {};
		Zarafa.plugins.files.AttachFromFilesPlugin.superclass.constructor.call(this, config);
	},

	/**
	 * initialises insertion point for plugin
	 * @protected
	 */
	initPlugin : function() {
		Zarafa.plugins.files.AttachFromFilesPlugin.superclass.initPlugin.apply(this, arguments);
		
		// load attachments from files
		this.registerInsertionPoint('main.attachment.method', this.onAttachmentInsertion)
		Zarafa.core.data.SharedComponentType.addProperty('common.dialog.attachments.files');
	},

	/**
	 * Insert files option in all attachment suggestions
	 * @return {Array}
	 */
	onAttachmentInsertion : function(include, btn) {
		return {
			text : container.getSettingsModel().get('zarafa/v1/plugins/files/button_name'),
			handler : this.showFilesAttachmentDialog.createDelegate(this, [btn]),
			scope: this,
			iconCls: 'icon_files_category'
		};
	},

	/**
	 * Initializes Dialog for adding attachment from Files to efiles
	 * @param {Object} btn
	 * @private
	 */
	showFilesAttachmentDialog : function(btn) {
		Zarafa.core.data.UIFactory.openLayerComponent(Zarafa.core.data.SharedComponentType['common.dialog.attachments.files'], btn.record, {
			title : String.format(dgettext('plugin_files', 'Add attachment from {0}'), container.getSettingsModel().get('zarafa/v1/plugins/files/button_name')),
			manager : Ext.WindowMgr
		});
	},
	
	/**
	 * Bid for the type of shared component
	 * and the given record.
	 * This will bid on calendar.dialogs.importevents
	 * @param {Zarafa.core.data.SharedComponentType} type Type of component a context can bid for.
	 * @param {Ext.data.Record} record Optionally passed record.
	 * @return {Number} The bid for the shared component
	 */
	bidSharedComponent : function(type, record) {
		var bid = -1;
		
		switch(type) {
			case Zarafa.core.data.SharedComponentType['common.dialog.attachments.files']:
				if (record instanceof Zarafa.core.data.IPMRecord) {
					if (record.supportsAttachments())
						bid = 1;
				}
				break;
		}
		
		return bid;
	},

	/**
	 * Will return the reference to the shared component.
	 * Based on the type of component requested a component is returned.
	 * @param {Zarafa.core.data.SharedComponentType} type Type of component a context can bid for.
	 * @param {Ext.data.Record} record Optionally passed record.
	 * @return {Ext.Component} Component
	 */
	getSharedComponent : function(type, record) {
		var component;

		switch(type) {
			case Zarafa.core.data.SharedComponentType['common.dialog.attachments.files']:
				component = Zarafa.plugins.files.dialogs.AttachFromFilesContentPanel;
				break;
		}

		return component;
	}
});

Zarafa.onReady(function() {
	if(Ext.isDefined(container.getSettingsModel().get('zarafa/v1/plugins/files/button_name'))) { // check if user store is initialised
		if(container.getSettingsModel().get('zarafa/v1/plugins/files/enable') === true) { // make sure that the master plugin is enabled
			container.registerPlugin(new Zarafa.core.PluginMetaData({
				name : 'attachfromfiles',
				allowUserVisible : false,
				displayName : String.format(dgettext('plugin_files', 'Attach a file from {0}'), container.getSettingsModel().get('zarafa/v1/plugins/files/button_name')),
				pluginConstructor : Zarafa.plugins.files.AttachFromFilesPlugin
			}));
		}
	}
});
Ext.namespace('Zarafa.plugins.files');

/**
 * @class Zarafa.plugins.files.FilesRcvAttachmentPlugin
 * @extends Zarafa.core.Plugin
 * This class is used for adding files from the users's Files folder
 * to his efiless as attachments
 */
Zarafa.plugins.files.SaveToFilesPlugin = Ext.extend(Zarafa.core.Plugin, {

	/**
	 * @constructor
	 * @param {Object} config
	 */
	constructor : function(config) {
		config = config || {};
		Zarafa.plugins.files.SaveToFilesPlugin.superclass.constructor.call(this, config);
	},

	/**
	 * initialises insertion point for plugin
	 * @protected
	 */
	initPlugin : function() {
		Zarafa.plugins.files.SaveToFilesPlugin.superclass.initPlugin.apply(this, arguments);
		
		/* store attachments in files */
		this.registerInsertionPoint('common.contextmenu.attachment.actions', this.createAttachmentUploadInsertionPoint, this);
		this.registerInsertionPoint('context.mail.contextmenu.actions', this.createEmailUploadInsertionPoint, this);

		Zarafa.core.data.SharedComponentType.addProperty('common.dialog.attachments.savetofiles');
	},

	/**
	 * Insert files option in all attachment suggestions
	 * @return {Array}
	 * @private
	 */
	createAttachmentUploadInsertionPoint : function(include, btn) {
		return {
			text : container.getSettingsModel().get('zarafa/v1/plugins/files/button_name'),
			handler : this.showFilesUploadAttachmentDialog.createDelegate(this, [btn]),
			scope: this,
			iconCls: 'icon_files_category'
		};
	},

	/**
	 * This method hooks to the email context menu and allows users to store emails from
	 * to the  Files plugin.
	 *
	 * @param include
	 * @param btn
	 * @returns {Object}
	 */
	createEmailUploadInsertionPoint: function (include, btn) {
		return {
			text: dgettext('plugin_files', 'Add to Files'),
			handler: this.showFilesUploadEmailDialog.createDelegate(this, [btn]),
			scope: this,
			iconCls: 'icon_files_category'
		};
	},

	/**
	 * Display a loading dialog with moving progress bar
	 * @private
	 */
	showLoadingBar: function() {
		Zarafa.common.dialogs.MessageBox.show({
			title: dgettext('plugin_files', 'Please wait'),
			msg: dgettext('plugin_files', 'Loading attachment') + '...',
			progressText: dgettext('plugin_files', 'Initializing') + '...',
			width:300,
			wait:true,
			waitConfig: {interval:200},
			closable:false
		});
	},

	/**
	 * This method will open the {@link Zarafa.plugins.files.ui.dialogs.SaveToFilesContentPanel folder chooser panel}.
	 *
	 * @param btn
	 */
	showFilesUploadAttachmentDialog: function (btn) {

		var attachmentRecord = btn.records;
		var attachmentStore = attachmentRecord.store;

		var store = attachmentStore.getParentRecord().get('store_entryid');
		var entryid = attachmentStore.getAttachmentParentRecordEntryId();
		var attachNum = new Array(1);
		if (attachmentRecord.get('attach_num') != -1)
			attachNum[0] = attachmentRecord.get('attach_num');
		else
			attachNum[0] = attachmentRecord.get('tmpname');
		var dialog_attachments = attachmentStore.getId();
		var filename = attachmentRecord.get('name');

		jsonRecords = new Array();
		jsonRecords[0] = {
			entryid: entryid,
			store: store,
			attachNum: attachNum,
			dialog_attachments: dialog_attachments,
			filename: filename
		};

		var configRecord = {
			items: jsonRecords,
			type: "attachment",
			count: jsonRecords.length
		};

		Zarafa.core.data.UIFactory.openLayerComponent(Zarafa.core.data.SharedComponentType['common.dialog.attachments.savetofiles'], configRecord, {
			title: String.format(dgettext('plugin_files', 'Add attachment to {0}'), container.getSettingsModel().get('zarafa/v1/plugins/files/button_name')),
			manager: Ext.WindowMgr
		});
	},

	/**
	 * This method will open the {@link Zarafa.plugins.files.ui.dialogs.SaveToFilesContentPanel folder chooser panel}.
	 *
	 * @param btn
	 */
	showFilesUploadEmailDialog: function (btn) {
		/* store the eml to a temporary folder and prepare it for uploading */
		var emailRecord = btn.records;

		var records = [].concat(emailRecord);

		var jsonRecords = new Array();
		for (var i = 0, len = records.length; i < len; i++) {
			jsonRecords[i] = {
				store: records[i].get('store_entryid'),
				entryid: records[i].get('entryid'),
				filename: (Ext.isEmpty(records[i].get('subject')) ? _('Untitled') : records[i].get('subject')) + ".eml"
			};
		}

		var configRecord = {
			items: jsonRecords,
			type: "mail",
			count: jsonRecords.length
		};

		Zarafa.core.data.UIFactory.openLayerComponent(Zarafa.core.data.SharedComponentType['common.dialog.attachments.savetofiles'], configRecord, {
			title: String.format(dgettext('plugin_files', 'Add email to {0}'), container.getSettingsModel().get('zarafa/v1/plugins/files/button_name')),
			manager: Ext.WindowMgr
		});
	},

	/**
	 * Bid for the type of shared component
	 * and the given record.
	 * This will bid on common.dialog.attachments.savetofiles
	 * @param {Zarafa.core.data.SharedComponentType} type Type of component a context can bid for.
	 * @param {Object} response Optionally passed response.
	 * @return {Number} The bid for the shared component
	 */
	bidSharedComponent : function(type, response) {
		var bid = -1;
		
		switch(type) {
			case Zarafa.core.data.SharedComponentType['common.dialog.attachments.savetofiles']:
				bid = 1;
				break;
		}
		
		return bid;
	},

	/**
	 * Will return the reference to the shared component.
	 * Based on the type of component requested a component is returned.
	 * @param {Zarafa.core.data.SharedComponentType} type Type of component a context can bid for.
	 * @param {Object} response Optionally passed response.
	 * @return {Ext.Component} Component
	 */
	getSharedComponent : function(type, response) {
		var component;

		switch(type) {
			case Zarafa.core.data.SharedComponentType['common.dialog.attachments.savetofiles']:
				component = Zarafa.plugins.files.dialogs.SaveToFilesContentPanel;
				break;
		}

		return component;
	}
});

Zarafa.onReady(function() {
	if(Ext.isDefined(container.getSettingsModel().get('zarafa/v1/plugins/files/button_name'))) { // check if user store is initialised
		if(container.getSettingsModel().get('zarafa/v1/plugins/files/enable') === true) { // make sure that the master plugin is enabled
			container.registerPlugin(new Zarafa.core.PluginMetaData({
				name : 'savetofiles',
				allowUserVisible : false,
				displayName : String.format(dgettext('plugin_files', 'Save received attachments to {0}'), container.getSettingsModel().get('zarafa/v1/plugins/files/button_name')),
				pluginConstructor : Zarafa.plugins.files.SaveToFilesPlugin
			}));
		}
	}
});Ext.namespace('Zarafa.plugins.files.data');

/**
 * @class Zarafa.plugins.files.data.Helper
 * Some static helper functions 
 * @singleton
 */
Zarafa.plugins.files.data.Helper = {

	/** 
	 * Base64 tools
	 */
	Base64 : {
		// private property
		_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

		/**
		 * Encode the given string to base64.
		 * @param {String} input
		 * @return {String}
		 */
		encode : function (input) {
			var output = "";
			var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
			var i = 0;

			input = this._utf8_encode(input);

			while (i < input.length) {

				chr1 = input.charCodeAt(i++);
				chr2 = input.charCodeAt(i++);
				chr3 = input.charCodeAt(i++);

				enc1 = chr1 >> 2;
				enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
				enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
				enc4 = chr3 & 63;

				if (isNaN(chr2))
					enc3 = enc4 = 64;
				else if (isNaN(chr3))
					enc4 = 64;

				output = output +
				this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
				this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);

			}

			return output;
		},
		
		/**
		 * Decode the given base64 encoded string.
		 * @param {String} input
		 * @return {String}
		 */
		decode : function (input) {
			var output = "";
			var chr1, chr2, chr3;
			var enc1, enc2, enc3, enc4;
			var i = 0;

			input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

			while (i < input.length) {

				enc1 = this._keyStr.indexOf(input.charAt(i++));
				enc2 = this._keyStr.indexOf(input.charAt(i++));
				enc3 = this._keyStr.indexOf(input.charAt(i++));
				enc4 = this._keyStr.indexOf(input.charAt(i++));

				chr1 = (enc1 << 2) | (enc2 >> 4);
				chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
				chr3 = ((enc3 & 3) << 6) | enc4;

				output = output + String.fromCharCode(chr1);

				if (enc3 != 64)
					output = output + String.fromCharCode(chr2);
				if (enc4 != 64)
					output = output + String.fromCharCode(chr3);

			}

			output = this._utf8_decode(output);

			return output;

		},
		
		/**
		 * Decodes the given base64 encoded utf-8 string.
		 * @param {String} input
		 * @return {String}
		 * @private
		 */
		_utf8_decode : function (utftext) {
			var string = "";
			var i = 0;
			var c = 0
			var c1 = 0;
			var c2 = 0;
			var c3 = 0;

			while ( i < utftext.length ) {

				c = utftext.charCodeAt(i);

				if (c < 128) {
					string += String.fromCharCode(c);
					i++;
				}
				else if((c > 191) && (c < 224)) {
					c2 = utftext.charCodeAt(i+1);
					string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
					i += 2;
				}
				else {
					c2 = utftext.charCodeAt(i+1);
					c3 = utftext.charCodeAt(i+2);
					string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
					i += 3;
				}

			}

			return string;
		},

		/**
		 * Encode the given string to base64 in utf-8.
		 * @param {String} input
		 * @return {String}
		 * @private
		 */
		_utf8_encode : function (string) {
			string = string.replace(/\r\n/g,"\n");
			var utftext = "";

			for (var n = 0; n < string.length; n++) {

				var c = string.charCodeAt(n);

				if (c < 128)
					utftext += String.fromCharCode(c);
				else if((c > 127) && (c < 2048)) {
					utftext += String.fromCharCode((c >> 6) | 192);
					utftext += String.fromCharCode((c & 63) | 128);
				}
				else {
					utftext += String.fromCharCode((c >> 12) | 224);
					utftext += String.fromCharCode(((c >> 6) & 63) | 128);
					utftext += String.fromCharCode((c & 63) | 128);
				}

			}

			return utftext;
		}
	},
	
	/** 
	 * Rendering functions
	 */
	Renderer : {
		
		/**
		 * Typerenderer for folders or files
		 * @param {Object} value The data value for the cell.
		 * @param {Object} p An object with metadata
		 * @param {Ext.data.record} record The {Ext.data.Record} from which the data was extracted.
		 * @return {String} The formatted string
		 */
		typeRenderer : function(value, p, record) {
			switch (value) {
				case Zarafa.plugins.files.data.FileTypes.FOLDER: p.css = "zarafa-files-listview-icon " + Zarafa.plugins.files.data.Helper.File.getIconClass("folder", "16"); break;
				case Zarafa.plugins.files.data.FileTypes.FILE: p.css = "zarafa-files-listview-icon " + Zarafa.plugins.files.data.Helper.File.getIconClass(record.get('filename'), "16"); break;
				default : break;
			}

			// add extra css class for empty cell
			p.css += ' zarafa-grid-empty-cell';

			return '';
		},
	
		/**
		 * Renders timestamps
		 * @param {Object} value The data value for the cell.
		 * @param {Object} p An object with metadata
		 * @param {Ext.data.record} record The {Ext.data.Record} from which the data was extracted.
		 * @return {String} The formatted string
		 */
		datetimeRenderer : function(value, p, record) {
			p.css = 'mail_date';

			// # TRANSLATORS: See http://docs.sencha.com/ext-js/3-4/#!/api/Date for the meaning of these formatting instructions
			value = new Date(value);
			return Ext.isDate(value) ? value.format(dgettext('plugin_files', 'l d/m/Y G:i')) : dgettext('plugin_files', 'Never');
		}
	},
	
	/** 
	 * Formatting functions
	 */
	Format : {
		/**
         * Simple format for a file size (xxx bytes, xxx KB, xxx MB, xxx GB)
         * @param {Number/String} size The numeric value to format
         * @return {String} The formatted file size
         */
        fileSize : function(size) {
		    if(size === -1 || size === "none") {
				return "";
			} else {
				if (size < 1024) {
					return size + " bytes";
				} else if (size < 1048576) {
					return (Math.round(((size*10) / 1024))/10) + " KB";
				} else if(size < 1073741824) {
					return (Math.round(((size*10) / 1048576))/10) + " MB";
				} else { // < 1 TB
					return (Math.round(((size*10) / 1073741824))/10) + " GB";
				} 
			}
        },
		
		/**
         * Simple format for a file size (xxx KB, xxx MB, xxx GB, xxx TB)
         * @param {Number/String} size The numeric value to format
         * @return {String} The formatted file size
         */
        fileSizeList : function(size) {
		    if(size === -1 || size === "none") {
				return "";
			} else {
				if (size < 1024) { // < 1 KB
					if(size <= 100 && size != 0) {
						return "0.1 &nbsp;KB";
					} else {
						return (Math.round(((size*10) / 1024))/10) + " &nbsp;KB";
					}
				} else if (size < 1048576) { // < 1 MB
					return (Math.round(((size*10) / 1024))/10) + " &nbsp;KB";
				} else if(size < 1073741824) { // < 1 GB
					return (Math.round(((size*10) / 1048576))/10) + " &nbsp;MB";
				} else if(size < 1099511627776) { // < 1 TB
					return (Math.round(((size*10) / 1073741824))/10) + " &nbsp;GB";
				} else { // > 1 TB
					return (Math.round(((size*10) / 1099511627776))/10) + " &nbsp;TB";
				}
			}
        }
	},
	
	File : {
		/**
		 * Get the extension from the filename
		 *
		 * @param {String} filename
		 * @return {String} Extension string without dot
		 */
		getExtension : function(filename) {
			var i = filename.lastIndexOf('.');
			return (i < 0) ? '' : filename.substr(i+1); // also remove dot
		},
		
		/**
		 * Get the icon class for the filetype
		 * @param {String} filename
		 * @param {String} size Iconsize without px
		 * @return {String} Icon class
		 */
		getIconClass : function (filename, size) {
			if(!Ext.isDefined(size)) {
				size = "48";
			}
			var existingIcons = ["aac", "ai", "aiff", "avi", "bmp", "c", "cpp", "css", "dat", "dmg",
				"doc", "docx", "dotx", "dwg", "dxf", "eps", "exe", "flv", "gif", "gz", "h", "hpp", "html", "ics",
				"iso", "java", "jpg", "js", "key", "less", "mid", "mp3", "mp4", "mpg", "odf", "ods",
				"odt", "otp", "ots", "ott", "pdf", "php", "png", "ppt", "psd", "py", "qt", "rar",
				"rb", "rtf", "sass", "sql", "tga", "tgz", "tiff", "txt", "wav", "xls", "xlsx", "xml",
				"yml", "zip"];
				
			if(filename === "folder") {
				return "files" + size + "icon_folder";
			}
			
			var extension = this.getExtension(filename).toLowerCase();
			var exists = existingIcons.indexOf(extension);
			
			if(Ext.isEmpty(extension) || exists === -1) {
				return "files" + size + "icon_blank";
			}
			
			return "files" + size + "icon_" + extension;
		},
		
		/**
		 * Check if the filename (or foldername) includes unwanted characters
		 * @param {String} filename
		 * @return {Boolean} true if filename is valid
		 */
		isValidFilename : function (filename) {
			
			// empty filenames are not allowed
			if(Ext.isEmpty(filename))
				return false;
			
			// filename must not contain a slash
			if(filename.indexOf("/") !== -1)
				return false;
			
			// this symbols are not allowed in owncloud
			if( filename.indexOf("\\") !== -1 
				|| filename.indexOf("<") !== -1 
				|| filename.indexOf(">") !== -1
				|| filename.indexOf(":") !== -1
				|| filename.indexOf("'") !== -1
				|| filename.indexOf("|") !== -1
				|| filename.indexOf("?") !== -1
				|| filename.indexOf("*") !== -1
			)
				return false;
			
			return true;
		}
	}
}
Ext.namespace('Zarafa.plugins.files.data');

/**
 * @class Zarafa.plugins.files.data.ComponentBox
 * The global component box which holds all aliases to important components
 * @singleton
 */
Zarafa.plugins.files.data.ComponentBox = Ext.extend(Object, {
	/**
	 * Get the files context
	 * @return {Zarafa.plugins.files.context.FilesContext}
	 */
	getContext : function() {
		// should we return container.getContextByName("filescontext")? performance will be lower...
		return container.getCurrentContext();
	},
	
	/**
	 * Get the files context model
	 * @return {Zarafa.plugins.files.context.FilesContextModel}
	 */
	getContextModel : function() {
		return this.getContext().getModel();
	},
	
	/**
	 * Get the files gridstore
	 * @return {Zarafa.plugins.files.data.FilesStore}
	 */
	getStore : function() {
		return this.getContextModel().getStore();
	},
	
	/**
	 * Get the navigatorpanel
	 * @return {Zarafa.core.ui.NavigationPanel}
	 */
	getNavigatorPanel : function() {
		return container.getNavigationBar();
	},
	
	/**
	 * Get the navigator treepanel
	 * @return {Zarafa.plugins.files.ui.NavigatorTreePanel}
	 */
	getNavigatorTreePanel : function() {
		return this.getNavigatorPanel().filesTreepanel;
	},
	
	/**
	 * Get the main panel
	 * @return {Zarafa.core.ui.MainViewport}
	 */
	getMainPanel : function() {
		try {
			return container.getContentPanel();
		} catch (e) {
			// this is a workaround for webapps < 1.3
			return container.getTabPanel().getItem(0).getActiveItem();
		}
	},
	
	/**
	 * Get the preview panel
	 * @return {Zarafa.plugins.files.ui.FilesPreviewPanel}
	 */
	getPreviewPanel : function() {
		return this.getMainPanel().filesPreview;
	},
	
	/**
	 * Get the tabpanel
	 * @return {Zarafa.core.ui.ContextContainer}
	 */
	getTabPanel : function() {
		return container.getTabPanel();
	},
	
	/**
	 * Get the tabpanel items
	 * @return {Array}
	 */
	getTabPanelItems : function() {
		return this.getTabPanel().items.items;
	},
	
	/**
	 * Get the files gridpanel
	 * @return {Zarafa.plugins.files.ui.FilesFileGrid}
	 */
	getViewPanel : function() {
		return this.getMainPanel().filesViewPanel;
	},
	
	/**
	 * Get the files grid toolbar
	 * @return {Zarafa.plugins.files.ui.FilesToolbar}
	 */
	getViewPanelToolbar : function() {
		var viewPanel = this.getViewPanel();
		if(viewPanel)
			return viewPanel.topToolbar;
		else
			return undefined;
	}
});

// make it a singleton
Zarafa.plugins.files.data.ComponentBox = new Zarafa.plugins.files.data.ComponentBox();
Ext.namespace('Zarafa.plugins.files.data');

/**
 * @class Zarafa.plugins.files.data.DataModes
 * @extends Zarafa.core.Enum
 *
 * Enum containing the different data modes of the files context. 
 * 
 * @singleton
 */
Zarafa.plugins.files.data.DataModes = Zarafa.core.Enum.create({
	/**
	 * View all files items from the selected folder(s).
	 *
	 * @property
	 * @type Number
	 */
	ALL : 0
});
Ext.namespace('Zarafa.plugins.files.data');

/**
 * @class Zarafa.plugins.files.data.FileTypes
 * @extends Zarafa.core.Enum
 *
 * Enum containing the different file types of the files context. 
 * 
 * @singleton
 */
Zarafa.plugins.files.data.FileTypes = Zarafa.core.Enum.create({
	/**
	 * Filetype: folder
	 *
	 * @property
	 * @type Number
	 */
	FOLDER : 0,
	/**
	 * Filetype: file
	 *
	 * @property
	 * @type Number
	 */
	FILE : 1
});
Ext.namespace('Zarafa.plugins.files.data');

/**
 * @class Zarafa.plugins.files.data.ViewModes
 * @extends Zarafa.core.Enum
 *
 * Enum containing the different viewing modes of the files context.
 * 
 * @singleton
 */
Zarafa.plugins.files.data.ViewModes = Zarafa.core.Enum.create({
	/**
	 * Don't show the preview panel
	 * @property
	 * @type Number
	 */
	NO_PREVIEW : 0,

	/**
	 * Show the preview panel to the right
	 * @property
	 * @type Number
	 */
	RIGHT_PREVIEW : 1,

	/**
	 * Show the preview panel in the bottom
	 * @property
	 * @type Number
	 */
	BOTTOM_PREVIEW : 2
});
Ext.namespace('Zarafa.plugins.files.data');

/**
 * @class Zarafa.plugins.files.data.Views
 * @extends Zarafa.core.Enum
 *
 * Enum containing the different views of the files context. 
 * 
 * @singleton
 */
Zarafa.plugins.files.data.Views = Zarafa.core.Enum.create({
	/**
	 * View all files items from the selected folder(s) in the 'list' view.
	 *
	 * @property
	 * @type Number
	 */
	LIST : 0,
	
	/**
	 * View all files items from the selected folder(s) in the 'icon' view.
	 *
	 * @property
	 * @type Number
	 */
	ICON : 1
});
Ext.namespace('Zarafa.plugins.files.data');

/**
 * @class Zarafa.plugins.files.Actions
 * Common actions which can be used within {@link Ext.Button buttons}
 * or other {@link Ext.Component components} with action handlers.
 * @singleton
 */
Zarafa.plugins.files.data.Actions = {
	/**
	 * The internal 'iframe' which is hidden from the user, which is used for downloading
	 * attachments. See {@link #doOpen}.
	 * @property
	 * @type Ext.Element
	 */
	downloadFrame : undefined,
	
	/**
	 * Converts received file information to attachment record
	 * @param {Object} record
	 * @private
	 */
	convertDownloadedFileInfoToAttachmentRecord : function(record) {
		var attachmentRecord = Zarafa.core.data.RecordFactory.createRecordObjectByObjectType(Zarafa.core.mapi.ObjectType.MAPI_ATTACH);

		attachmentRecord.set('tmpname', record.tmpname);
		attachmentRecord.set('name', record.name);
		attachmentRecord.set('size', record.size);
		return attachmentRecord;
	},
	
	/**
	 * Open a Panel in which a new {@link Zarafa.core.data.IPMRecord record} can be
	 * further edited.
	 *
	 * @param {Zarafa.core.data.IPMRecord} emailRecord The email record that will be edited.
	 * @param {Array} records Filerecords that will be added as attachments.
	 * @param {Object} config (optional) Configuration object used to create
	 * the Content Panel.
	 */
	openCreateMailContent : function(emailRecord, records, config) {
		var attachmentStore = emailRecord.getAttachmentStore();
		var attachmentRecord = null;
		
		Ext.each(records, function(record, index) {
			attachmentRecord = this.convertDownloadedFileInfoToAttachmentRecord(record);
			attachmentStore.add(attachmentRecord);
		}, this);
		
		Zarafa.core.data.UIFactory.openCreateRecord(emailRecord, config);
	},
	
	/**
	 * Open a Panel in which a new {@link Zarafa.core.data.IPMRecord record} can be
	 * further edited.
	 *
	 * @param {Zarafa.mail.MailContextModel} model Context Model object that will be used
	 * to {@link Zarafa.mail.MailContextModel#createRecord create} the E-Mail.
	 * @param {Zarafa.addressbook.AddressBookRecord} contacts One or more contact records.
	 * @param {Object} config (optional) Configuration object used to create
	 * the Content Panel.
	 */
	openCreateMailContentForContacts : function(model, contacts, config) {	
		var emailRecord = container.getContextByName("mail").getModel().createRecord();
		
		Zarafa.core.data.UIFactory.openLayerComponent(Zarafa.core.data.SharedComponentType['zarafa.plugins.files.attachdialog'], undefined , {
			title : String.format(dgettext('plugin_files', 'Add attachment from {0}'), container.getSettingsModel().get('zarafa/v1/plugins/files/button_name')),
			emailrecord : emailRecord,
			manager : Ext.WindowMgr
		});
		
		var recipientStore = emailRecord.getRecipientStore();
		var tasks = [];
		
		contacts = Ext.isArray(contacts) ? contacts : [ contacts ];
		for (var i = 0, len = contacts.length; i < len; i++) {
			var contact = contacts[i];

			if (contact.isOpened()) {
				// The contact is opened and contains all the information which we need
				var recipient = contact.convertToRecipient(Zarafa.core.mapi.RecipientType.MAPI_TO, true);
				recipientStore.add(recipient);
			} else {
				// The contact is not opened yet, register a task to open the contact once
				// the panel has been opened.
				tasks.push({
					/* By encapsulating the task function it is possible to get the contact object 
					* into the scope of the task function. When you add more tasks the contact 
					* reference changes and without this encapsulation it will change the contact in
					* all the previously added task functions as well.
					*/
					fn : function(){
						// This contactRecord becomes a private variable, not changable outside.
						var contactRecord = contact;
						return function(panel, record, task, callback) {
							var fn = function(store, record) {
								if (record === contactRecord) {
									store.un('open', fn, task);
									var recipient = contactRecord.convertToRecipient(Zarafa.core.mapi.RecipientType.MAPI_TO, true);
									recipientStore.add(recipient);
									callback();
								}
							};

							contactRecord.getStore().on('open', fn, task);
							contactRecord.open();
						}
					// This triggers the encapsulation and returns the task function
					}()
				});
			}
		}
		
		config = Ext.applyIf(config || {}, {
			recordComponentPluginConfig : {
				loadTasks : tasks
			}
		});
		
		Zarafa.core.data.UIFactory.openCreateRecord(emailRecord, config);
	},
	
	
	/**
	 * Create a new item...
	 * @param {Zarafa.mail.MailContextModel} model Context Model.
	 * @param {Object} config (optional) Configuration object used to create
	 * the Content Panel.
	 */
	openCreateFilesContent : function(model, config) {
		var record = model.createRecord();
		Zarafa.core.data.UIFactory.openCreateRecord(record, config);
	},
	
	/**
	 * Open a Panel in which the {@link Zarafa.core.data.IPMRecord record}
	 * can be viewed, or further edited.
	 *
	 * @param {Zarafa.core.data.IPMRecord} records The records to open
	 * @param {Object} config (optional) Configuration object used to create
	 * the Content Panel.
	 */
	openFilesContent : function(records, config) {
		var navpanel = Zarafa.plugins.files.data.ComponentBox.getNavigatorTreePanel();
		var store = Zarafa.plugins.files.data.ComponentBox.getStore();
		
		if(records.length == 1 && records[0].get('type') === Zarafa.plugins.files.data.FileTypes.FOLDER) {
			store.loadPath(records[0].get('id'));
			navpanel.getNodeById(records[0].get('id')).reload();
		} else if(records.length > 1) {
			this.downloadItem(records);
		}
	},
	
	/**
	 * Refreshes the left navigator tree
	 *
	 */
	refreshNavigatorTree : function() {
		var navpanel = Zarafa.plugins.files.data.ComponentBox.getNavigatorTreePanel();
		var store = Zarafa.plugins.files.data.ComponentBox.getStore();
		
		// reload the navigation tree
		var node = navpanel.getNodeById(store.getPath());
		
		if(Ext.isDefined(node) && !node.isLeaf()) {
			node.reload();
		}
	},
	
	/**
	 * Create the upload form
	 *
	 * @param {Zarafa.mail.MailContextModel} model Context Model.
	 * @param {Object} config (optional) Configuration object used to create
	 * the Content Panel.
	 * @param {String} path The destination path in which the uploaded file will be stored.
	 */
	createUploadDialog : function(model, config, path) {
		if(!Ext.isDefined(path) || Ext.isEmpty(path))
			path = model.getStore().getPath();
	
		config = Ext.applyIf(config || {}, {
			modal : true,
			parentID: path
		});
		
		var componentType = Zarafa.core.data.SharedComponentType['zarafa.plugins.files.uploadpanel'];
		Zarafa.core.data.UIFactory.openLayerComponent(componentType, undefined, config);
	},

	/**
	 * Create a new Folder in {@link Zarafa.core.data.IPMRecord node}
	 *
	 * @param {Zarafa.mail.MailContextModel} model Context Model.
	 * @param {Object} config (optional) Configuration object used to create
	 * the Content Panel.
	 * @param {String} path The destination path in which the new folder will be created.
	 */
	createFolder : function(model, config, path) {
		if(!Ext.isDefined(path) || Ext.isEmpty(path))
			path = model.getStore().getPath();

		Ext.MessageBox.prompt(dgettext('plugin_files', 'Folder name'), dgettext('plugin_files', 'Please enter a foldername'), this.doCreateFolder.createDelegate(this, [model, path], true), this);
	},
	
	/**
	 * Create a new Folder on the server.
	 *
	 * @param {String} button The value of the button
	 * @param {String} text Inputfield value, the foldername
	 * @param {Object} options Unused
	 * @param {Zarafa.mail.MailContextModel} model Context Model.
	 * @param {String} path The destination path in which the uploaded file will be stored.
	 * @private
	 */
	doCreateFolder : function(button, text, options, model, path) {
		if(button === "ok") {
			try {
				// check if folder with same name already exists
				var alreadyExists = false;
				if(model.getStore().findExact("id", path + text + "/") != -1) {
					alreadyExists = true;
				}
				// check if foldername contains a / - if so, dont rename it
				if(!Zarafa.plugins.files.data.Helper.File.isValidFilename(text)) {
					this.msgWarning(dgettext('plugin_files', 'Incorrect foldername'));
				} else if(alreadyExists) {
					this.msgWarning(dgettext('plugin_files', 'Folder already exists'));
				} else {
					var d = new Date();
					var nowUTC = d.getTime() + d.getTimezoneOffset()*60*1000;
					var data = {
						"filename" : text,
						"path" : path,
						"id" : path + text + "/", 
						"message_size" : "-1",
						"lastmodified" : nowUTC,
						"type" : Zarafa.plugins.files.data.FileTypes.FOLDER
					};

					var rec = Zarafa.core.data.RecordFactory.createRecordObjectByCustomType(Zarafa.core.data.RecordCustomObjectType.ZARAFA_FILES, data);

					model.getStore().add(rec);
					model.getStore().on("update", this.reloadCurrentDir, this, {single:true});
					model.getStore().commitChanges();
				}
			} catch (e) {
				this.msgWarning(e.message);
			}
		}
	},
	
	/**
	 * Move specified records to the new folder
	 * 
	 * @param records array of records
	 * @param destination record or id
	 * @param overwrite boolean flag - if true, existing dst records will be overwritten, default: true
	 */
	moveRecords : function(records, destination, overwrite) {
		overwrite = Ext.isDefined(overwrite) ? overwrite : false;
		var targetFolder = destination instanceof Zarafa.plugins.files.data.FilesRecord ? destination.get('id') : destination;
		
		if(!overwrite) {
			var ids = [];
			Ext.each(records, function(record) {
				ids.push(record.get('id'));
			});
			
			var fileStore = Zarafa.plugins.files.data.ComponentBox.getStore();
			
			fileStore.on('load', this.checkForDuplicate.createDelegate(this, [ids, fileStore.getPath()], true) , this, {single: true});
			fileStore.loadPath(targetFolder);
		} else {
			this.doMoveRecords("yes", null, null, ids, targetFolder);
		}
	},
	
	/**
	 * This function is called after the {@Zarafa.plugins.files.data.FilesStore} has loaded the target folder.
	 * It will check if one of the selected files already exists in the store. If there is a duplicate file
	 * a warning will be shown.
	 *
	 * @param {Ext.data.Store} store
	 * @param {Ext.data.Record|Array} records The Records that were loaded
	 * @param {Object} options The loading options that were specified (see {@link #load} for details)
	 * @param {Array} files Array of {String} file-id's
	 * @private
	 */
	checkForDuplicate : function(store, records, options, files, originalPath) {
		// check if the selected file already exists
		var duplicateFiles = [];
		var destination = store.getPath();
		
		Ext.each(files, function(file){
			var recId = store.findExact("id", destination + file.split("/").pop());
			
			if(recId != -1) {
				duplicateFiles.push(store.getById(recId));
			}
		});
		
		store.loadPath(originalPath); // switch back to the source directory
		
		if(duplicateFiles.length > 0) {
			// Store already contains file - warn user.
			Ext.MessageBox.confirm(
				dgettext('plugin_files', 'Confirm overwrite'), 
				dgettext('plugin_files', 'File already exists. Do you want to overwrite it?'),
				this.doMoveRecords.createDelegate(this, [files, destination], true),
				this
			);
		} else {
			this.doMoveRecords("yes", null, null, files, destination);
		}
	},
	
	/**
	 * This function will actually move the given files to a new destination.
	 *
	 * @param {String} button If button is set it must be "yes" to move files.
	 * @param {String} value Unused
	 * @param {Object} options Unused
	 * @param {Array} files Array of {String} file-id's
	 * @param {String} destination Destination folder
	 * @private
	 */
	doMoveRecords : function (button, value, options, files, destination) {
		if(!Ext.isDefined(button) || button === "yes") {
			try {
				container.getRequest().singleRequest(
					'filesbrowsermodule',
					'move',
					{
						ids : files,
						overwrite : true,
						destination : destination,
						destinationIsFolder : true
					},
					new Zarafa.plugins.files.data.ResponseHandler({
						successCallback : this.moveRecordsDone.createDelegate(this, [true], true),
						failureCallback : this.moveRecordsDone.createDelegate(this, [false], true)
					})
				);
			} catch (e) {
				this.msgWarning(e.message);
				
				return false;
			}
		}
	},
	
	/**
	 * Function is called after successfull or unsuccessfull moving of records.
	 *
	 * @private
	 * @param {Object} response
	 * @param {Boolean} success
	 */
	moveRecordsDone : function (response, success) {
		if(!success) {
			Zarafa.common.dialogs.MessageBox.show({
				title   : dgettext('plugin_files', 'Error'),
				msg     : response.message,
				icon    : Zarafa.common.dialogs.MessageBox.ERROR,
				buttons : Zarafa.common.dialogs.MessageBox.OK
			});
		}
		Zarafa.plugins.files.data.Actions.reloadCurrentDir();
	},
	
	/**
	 * Open a rename dialog and rename the item
	 * 
	 * @param {Zarafa.plugins.files.context.FilesContextModel} model
	 * @param {Zarafa.plugins.files.data.FilesRecord} record
	 */
	openRenameDialog : function (model, record) {
		Ext.MessageBox.prompt(dgettext('plugin_files', 'Rename'), dgettext('plugin_files', 'Please enter a new name'), this.doRename.createDelegate(this, [record], true), this, false, record.get('filename'));
	},
	
	/**
	 * Rename a record on the server
	 *
	 * @param {String} button The value of the button
	 * @param {String} text Inputfield value, new name
	 * @param {Object} options Unused
	 * @param {Zarafa.plugins.files.data.FilesRecord} record
	 * @private
	 */
	doRename : function (button, text, options, record) {
		if(button === "ok") {
			try {
				var path = record.get('path') === "/" ? "" : record.get('path');
				var isFolder = /\/$/.test(record.get('id')) ? "/" : "";
				
				// check if folder with same name already exists
				var alreadyExists = false;
				if(record.getStore().findExact("id", record.get('path') + text + isFolder) != -1) {
					alreadyExists = true;
				}
				
				// check if filename contains a / - if so, dont rename it
				if(!Zarafa.plugins.files.data.Helper.File.isValidFilename(text)) {
					this.msgWarning(dgettext('plugin_files', 'Incorrect filename'));
				} else if(alreadyExists) {
					this.msgWarning(/\/$/.test(record.get('id')) ? dgettext('plugin_files', 'Foldername already exists') : dgettext('plugin_files', 'Filename already exists'));
				} else {
					record.getStore().on('save', this.reloadCurrentDir, this, {single: true});

					record.beginEdit();
					record.set('filename', text);
					record.set('id', path + "/" + text + isFolder);
					record.endEdit();
				}				
			} catch (e) {
				this.msgWarning(e.message);
			}
		}
	},
	
	/**
	 * Does a full reload of both stores
	 *
	 */
	reloadCurrentDir : function () {
		Zarafa.plugins.files.data.ComponentBox.getStore().reload();
		this.refreshNavigatorTree();
	},
	
	/**
	 * Reloads the root node of the Treepanel
	 */
	reloadNavigatorTree : function () {
		var tree = Zarafa.plugins.files.data.ComponentBox.getNavigatorTreePanel();
		
		if(Ext.isDefined(tree)) {
			tree.setRootNode({
				nodeType: 'async',
				text: '/',
				id: '/',
				expanded : true
			});
		}
	},
	
	/**
	 * Clears the webdav request cache
	 * @param reaload if true, the gridstore will be reloaded, default: true
	 */
	clearCache : function(reload) {
		
		reload = Ext.isDefined(reload) ? reload : true;
		
		try {
			container.getRequest().singleRequest(
				'filesmodule',
				'clearcache',
				{},
				new Zarafa.plugins.files.data.ResponseHandler({
					successCallback : this.clearCacheDone.createDelegate(this, [reload], true)
				})
			);
		} catch (e) {
			this.msgWarning(e.message);
		}
	},
	
	/**
	 * Reloads the directory after clearing the cache.
	 *
	 * @private
	 * @param {Object} response
	 * @param {Boolean} reload If set to true the current directory will be reloaded.
	 */
	clearCacheDone : function (response, reload) {
		if(reload) {
			Zarafa.plugins.files.data.Actions.reloadCurrentDir();
		}
	},
	
	/**
	 * Download the selected items from files
	 *
	 * @param {Array} ids An array of ids
	 */
	downloadItem : function(records) {
		container.getNotifier().notify('info.files', dgettext('plugin_files', 'Downloading'), dgettext('plugin_files', 'Download started... please wait!'));
		
		var downloadFrame = Ext.getBody().createChild({
			tag: 'iframe',
			cls: 'x-hidden'
		});
		if(records.length == 1) {
			var url = this.getDownloadLink(records[0], false);
			downloadFrame.dom.contentWindow.location = url;
		} else if(records.length > 1) {
			var url = this.getDownloadLinkForMultipleFiles(records, false);
			downloadFrame.dom.contentWindow.location = url;
		}
	},
	
	/**
	 * Uploads the given files
	 *
	 * @param {Array} files An array of files
	 * @param {Object} store The destination {@Zarafa.plugins.files.data.FilesStore}
	 */
	uploadItem : function(files, store) {
		// Prepare the upload
		var destination = store.getPath();
		var parameters = {};
		var data = new FormData();
		var uploadfiles = [];
		
		parameters['attachments'] = files;
		parameters['parentID'] = destination;
		
		// check if file already exists on server
		var alreadyExists = false;
		var fileTooLarge = false;
		
		// show loading mask
		var loadingMask = new Ext.LoadMask(Zarafa.plugins.files.data.ComponentBox.getMainPanel().getEl(), {msg:dgettext('plugin_files', 'Uploading files') + '...'});
		loadingMask.show();
		
		// Convert the parameters into FormData
		for (var key in parameters) {
			var value = parameters[key];
			if (Ext.isArray(value) || value instanceof FileList) {
				for (var i = 0, len = value.length; i < len; i++) {
					
					if(store.findExact("id", destination + value[i].name) != -1) {
						alreadyExists = true;
					}
					data.append(key + '[]', value[i]);
					
					if(value[i].size > Zarafa.plugins.files.data.Dynamics.getMaxUploadFilesize()) {
						fileTooLarge = true;
					}
				}
			} else {
				data.append(key, value);
			}
		}
		
		if(fileTooLarge) {
			// show a warning to the user
			Zarafa.common.dialogs.MessageBox.show({
				title : dgettext('plugin_files', 'Error'),
				msg : String.format(dgettext('plugin_files', 'File is too large! Maximum allowed filesize: {0}.'), Zarafa.plugins.files.data.Helper.Format.fileSize(Zarafa.plugins.files.data.Dynamics.getMaxUploadFilesize())),
				icon : Zarafa.common.dialogs.MessageBox.ERROR,
				buttons : Zarafa.common.dialogs.MessageBox.OK
			});
			loadingMask.hide();
		} else {
			if(alreadyExists) {
				// Store already contains file - warn user.
				Ext.MessageBox.confirm(
					dgettext('plugin_files', 'Confirm overwrite'), 
					dgettext('plugin_files', 'File already exists. Do you want to overwrite it?'),
					this.doUpload.createDelegate(this, [data, loadingMask], true),
					this
				);
			} else {
				this.doUpload("yes", null, null, data, loadingMask);
			}
		}
	},
	
	/**
	 * Actually uploads the file to the server.
	 *
	 * @private
	 * @param {String} button
	 * @param {String} value Unused
	 * @param {Object} options Unused
	 * @param {FormData} data
	 * @param {Ext.LoadMask} loadingMask
	 */
	doUpload : function (button, value, options, data, loadingMask) {
		if(!Ext.isDefined(button) || button === "yes") {
			var xhr = new XMLHttpRequest();
			xhr.open("POST", "plugins/files/php/upload_file.php", true);
			xhr.addEventListener('load',this.uploadDone.createDelegate(xhr, [loadingMask], true), false);
			xhr.upload.addEventListener('progress',this.updateUploadProgress.createDelegate(this, [loadingMask], true), false);
			xhr.send(data);
		} else {
			loadingMask.hide();
		}
	},
	
	/**
	 * Functionc called on progress update of the XMLHttpRequest
	 *
	 * @private
	 * @param {Object} evt
	 * @param {Ext.LoadMask} loadingMask
	 */
	updateUploadProgress : function(evt, loadingMask){
	   if (evt.lengthComputable) {  
			//evt.loaded the bytes browser receive
			//evt.total the total bytes seted by the header
			var percentComplete = Math.round((evt.loaded / evt.total)*100);
			loadingMask.hide();
			if(percentComplete < 100) {
				loadingMask.msg = dgettext('plugin_files', 'Uploaded') + " " + percentComplete + "%";
			} else {
				loadingMask.msg = dgettext('plugin_files', 'Storing file on backend. Please wait') + "...";
			}
			loadingMask.show();
	   } 
	},
	
	/**
	 * Called after the file has been uploaded.
	 *
	 * @private
	 * @param {Object} event
	 * @param {Ext.LoadMask} loadingMask
	 */
	uploadDone : function(event, loadingMask) {
		if (this.status == 200) {
			Zarafa.plugins.files.data.Actions.clearCache();
		}
		loadingMask.hide();
	},
	
	/**
	 * Returns a download link for the client.
	 *
	 * @param {Zarafa.plugins.files.data.FilesRecord} record a file record
	 * @param {Boolean} inline (optional)
	 * @return {String}
	 */
	getDownloadLink : function(record, inline) {
		return (Ext.isDefined(inline) && inline == false) ? record.getAttachmentUrl() : record.getInlineImageUrl();
	},
	
	/**
	 * Returns a download link for the client to download multiple items.
	 *
	 * @param {Array} records a array of {Zarafa.plugins.files.data.FilesRecord}
	 * @return {String}
	 */
	getDownloadLinkForMultipleFiles : function(records) {
		var link = "";
		
		var url = document.URL;
		link = url.substring(0, url.lastIndexOf('/') + 1); // we need the absolute url for jwplayer...
		
		var ids = [];
		
		link += "plugins/files/php/proxy.php"; 
		Ext.each(records, function(record, index) {
			link = Ext.urlAppend(link, "ids[" + index + "]=" + encodeURIComponent(record.get("id")));
		});
		
		link = Ext.urlAppend(link, "inline=false");

		return link;
	},
	
	/**
	 * This will display a messagebox with warning icons to the user.
	 *
	 * @param {String} errorMessage The error message to display
	 */
	msgWarning : function (errorMessage) {
		Zarafa.common.dialogs.MessageBox.show({
			title   : dgettext('plugin_files', 'Warning'),
			msg     : errorMessage,
			icon    : Zarafa.common.dialogs.MessageBox.WARNING,
			buttons : Zarafa.common.dialogs.MessageBox.OK
		});
	}
};
Ext.namespace('Zarafa.plugins.files.data');

/**
 * @class Zarafa.plugins.files.FilesRecordFields
 * Array of {@link Ext.data.Field field} configurations for the
 * {@link Zarafa.core.data.IPMRecord IPMRecord} object.
 * These fields will be available in all 'IPM.Files' type messages.
 */
Zarafa.plugins.files.data.FilesRecordFields = [
	{name: 'id'},
	{name: 'path'},
	{name: 'type', type: 'int', defaultValue: Zarafa.plugins.files.data.FileTypes.FOLDER},
	{name: 'filename'},
	{name: 'lastmodified', type: 'int', defaultValue: null},
	{name: 'message_size', type: 'int', defaultValue: 0}
];

/**
 * @class Zarafa.core.data.IPMAttachmentRecord
 * @extends Ext.data.Record
 */
Zarafa.plugins.files.data.FilesRecord = Ext.extend(Zarafa.core.data.IPMRecord, {
	/**
	 * Sets the current record to disabled state
	 */
	disabled : false,
	
	/**
	 * Applies all data from an {@link Zarafa.plugins.files.data.FilesRecord FilesRecord}
	 * to this instance. This will update all data.
	 * 
	 * @param {Zarafa.plugins.files.data.FilesRecord} record The record to apply to this
	 * @return {Zarafa.plugins.files.data.FilesRecord} this
	 */
	applyData : function(record) {
		this.beginEdit();

		Ext.apply(this.data, record.data);
		Ext.apply(this.modified, record.modified);
		
		this.dirty = record.dirty;

		this.endEdit(false);

		return this;
	},

	/**
	 * Builds and returns inline image URL to download inline images,
	 * it uses {@link Zarafa.core.data.IPMRecord IPMRecord} to get store and message entryids.
	 * @return {String} URL for downloading inline images.
	 */
	getInlineImageUrl : function() {
		var link = "";
		
		link += "plugins/files/php/proxy.php?" + Ext.urlEncode({id: this.get('id'), inline: true});

		return link;
	},

	/**
	 * Builds and returns attachment URL to download attachment,
	 * it uses {@link Zarafa.core.data.IPMRecord IPMRecord} to get store and message entryids.
	 * @return {String} URL for downloading attachment.
	 */
	getAttachmentUrl : function() {
		var link = "";
		
		var url = document.URL;
		link = url.substring(0, url.lastIndexOf('/') + 1); // we need the absolute url for jwplayer...
		
		link += "plugins/files/php/proxy.php?" + Ext.urlEncode({id: this.get('id'), inline: false});

		return link;
	},
	
	/**
	 * Builds and returns inline thumbnail image URL to download show images,
	 * it uses {@link Zarafa.core.data.IPMRecord IPMRecord} to get store and message entryids.
	 * @param {Integer} width Width of the thumbnail
	 * @param {Integer} height Height of the thumbnail
	 * @return {String} URL for downloading inline images.
	 */
	getThumbnailImageUrl : function(width, height) {
		var link = "";
		
		link += "plugins/files/php/proxy.php?" + Ext.urlEncode({id: this.get('id'), inline: false, thumb: true, width: width, height: height});

		return link;
	},
	
	/**
	 * Set the disabled flag
	 * @param {Boolean} state
	 */
	setDisabled : function (state) {
		this.disabled = state;
	},
	
	/**
	 * Get the disabled flag
	 * @return {Boolean}
	 */
	getDisabled : function () {
		return this.disabled;
	}
});

Zarafa.core.data.RecordCustomObjectType.addProperty('ZARAFA_FILES');

Zarafa.core.data.RecordFactory.addFieldToMessageClass('IPM.Files', Zarafa.plugins.files.data.FilesRecordFields);
Zarafa.core.data.RecordFactory.setBaseClassToMessageClass('IPM.Files', Zarafa.plugins.files.data.FilesRecord);

Zarafa.core.data.RecordFactory.addFieldToCustomType(Zarafa.core.data.RecordCustomObjectType.ZARAFA_FILES, Zarafa.plugins.files.data.FilesRecordFields);
Zarafa.core.data.RecordFactory.setBaseClassToCustomType(Zarafa.core.data.RecordCustomObjectType.ZARAFA_FILES, Zarafa.plugins.files.data.FilesRecord);
Ext.namespace('Zarafa.plugins.files.data');

/**
 * @class Zarafa.plugins.files.data.FilesStore
 * @extends Zarafa.core.data.ListModuleStore
 * 
 * The FilesStore class provides a way to connect the 'fileslistmodule' in the server back-end to an 
 * Ext.grid.GridPanel object. It provides a means to retrieve files listings asynchronously.
 * The store has to be initialised with a store Id, which corresponds (somewhat confusingly) to
 * a MAPI store id. The FilesStore object, once instantiated, will be able to retrieve and list
 * filess from a single specific store only.
 * 
 * @constructor
 * @param {String} storeId a MAPI id that corresponds with a MAPI store on the server.
 */
Zarafa.plugins.files.data.FilesStore = Ext.extend(Zarafa.core.data.ListModuleStore, {

	/**
	 * The root path which is loaded
	 * @private
	 */
	rootID : undefined,
	
	/**
	 * @constructor
	 */
	constructor : function() {
		this.rootID = "/";
		
		Zarafa.plugins.files.data.FilesStore.superclass.constructor.call(this, {
			preferredMessageClass : 'IPM.Files',
			autoSave: true,
			actionType : Zarafa.core.Actions['list'],
			defaultSortInfo : {
				field : 'filename',
				direction : 'asc'
			},
			baseParams : {
				id : this.rootID
			}
		});
	},
	
	/**
	 * Triggers the loading of the specified path.
	 * @param {String} path to load
	 */
	loadPath : function(path) {
		this.rootID = path;
		var params = {
			id : this.rootID
		};
		this.load({params : params});
	},
	
	/**
	 * Returns the current root directory
	 * @return {String} the current root directory
	 */
	getPath : function() {
		return this.rootID;
	}
});
Ext.namespace('Zarafa.plugins.files.dialogs');

/**
 * @class Zarafa.plugins.files.dialogs.ShowFilesFileContentPanel
 * @extends Zarafa.core.ui.ContentPanel
 * @xtype zarafa.showfilescontentpanel
 */
Zarafa.plugins.files.dialogs.ShowFilesFileContentPanel = Ext.extend(Zarafa.core.ui.ContentPanel, {

	/**
 	 * @constructor
	 * @param config Configuration structure
	 */
	constructor : function(config) {
		config = config || {};

		// Add in some standard configuration data.
		Ext.applyIf(config, {
			// Override from Ext.Component
			xtype : 'zarafa.showfilescontentpanel',
			// Override from Ext.Panel
			layout : 'fit',
			title : dgettext('plugin_files', 'File information'),
			items: [ this.createPanel(config) ]
		});
		
		// Call parent constructor
		Zarafa.plugins.files.dialogs.ShowFilesFileContentPanel.superclass.constructor.call(this, config);
	},

	/**
	 * Add the main Window Panel to the content panel. This will contain
	 * a {@link Zarafa.core.ui.ContentPanelToolbar} and a {@link Zarafa.plugins.files.ui.FilesFileInfo}.
	 * @return {Object} The configuration object for the panel.
	 * @private
	 */
	createPanel : function(config) {	
		// Create a new panel and add it.
		return {
			xtype: 'zarafa.filesfileinfo',
			record : config.record
		};
	}
});

Ext.reg('zarafa.showfilescontentpanel', Zarafa.plugins.files.dialogs.ShowFilesFileContentPanel);Ext.namespace('Zarafa.plugins.files.dialogs');

/**
 * @class Zarafa.plugins.files.dialogs.FilesUploadContentPanel
 * @extends Zarafa.core.ui.ContentPanel
 * @xtype zarafa.filesuploadcontentpanel
 */
Zarafa.plugins.files.dialogs.FilesUploadContentPanel = Ext.extend(Zarafa.core.ui.ContentPanel, {

	/**
	 * Target folder for uploaded files
	 *
	 */
	targetFolder : undefined,
	
	/**
	 * @cfg {Object} task to check if file was selected
	 */
	updateTask : undefined,
	
	/**
 	 * @constructor
	 * @param {Object} config Configuration structure
	 */
	constructor : function(config) {
		config = config || {};

		// Add in some standard configuration data.
		Ext.applyIf(config, {
			// Override from Ext.Component
			xtype : 'zarafa.filesuploadcontentpanel',
			// Override from Ext.Panel
			layout : 'fit',
			title : dgettext('plugin_files', 'Upload file'),
			items: [{
				xtype : 'form',
				ref : 'mainuploadform',
				layout: {
					type : 'vbox',
					align : 'stretch',
					pack : 'start'
				},
				fileUpload : true,
				padding : 5,				
				items : [
					this.createFolderSelector(),
					this.createUploadField()					
				],
				buttons : this.createActionButtons()
			}]
		});
		
		// Call parent constructor
		Zarafa.plugins.files.dialogs.FilesUploadContentPanel.superclass.constructor.call(this, config);
		
		// run a background task to check if a file was selected.
		// We have to do this because the onChange handler is only executed
		// if the textfield looses focus.
		// Start a simple clock task that updates a div once per second
		this.updateTask = {
			run: function() {
				this.onUploadFieldChanged(null, this.mainuploadfield.getValue(),null);
			},
			interval: 1000, //1 second
			scope: this
		}
		
		Ext.TaskMgr.start(this.updateTask);
	},

	/**
	 * Creates a panel that includes a inputfield of type file.
	 * Every current browser will render a button to choose files.
	 * @return {Array}
	 * @private
	 */
	createUploadField : function() {
		return {
			xtype : 'panel',
			title : dgettext('plugin_files', 'Select a file') + ' (' + dgettext('plugin_files', 'Maximum upload size') + ': ' + Zarafa.plugins.files.data.Helper.Format.fileSize(Zarafa.plugins.files.data.Dynamics.getMaxUploadFilesize()) + '):',
			layout : 'form',
			height : 62,
			items : [{
				xtype : 'textfield',
				inputType : 'file',
				style : {
					border: 'none!important'
				},
				autoCreate : {tag: 'input', type: 'text', size: '20', autocomplete: 'off', multiple: 'multiple' },
				name : 'attachments[]',
				hideLabel : true,
				anchor : '100%',
				ref : '../../mainuploadfield',
				disabled : true,
				listeners : {
					change : this.onUploadFieldChanged,
					scope : this
				}
			}]
		};
	},
	
	/**
	 * Creates a treepanel where users could select the destination dir.
	 * @return {Array}
	 * @private
	 */
	createFolderSelector : function() {
		return {
			xtype : 'treepanel',
			anchor : '0, 0',
			flex : 1,
			title : dgettext('plugin_files', 'Select upload folder') + ':',
			root : {
				nodeType : 'async',
				text : '/',
				id : '/',
				expanded : true
			},
			autoScroll : true,
			viewConfig : {
				style :	{ overflow: 'auto', overflowX: 'hidden' }
			},
			maskDisabled : true,
			listeners : {
				click : function(n) {
					this.targetFolder = n.attributes.id;
					this.mainuploadfield.enable();
				},
				scope : this
			},
			loader : new Zarafa.plugins.files.data.DirectoryLoader({loadfiles: false})
		};
	},
	
	/**
	 * Creates action button for uploading the file
	 * @return {Array}
	 * @private
	 */
	createActionButtons : function() {
		return[{
			xtype   : 'button',
			ref : '../../mainuploadbutton',
			disabled : true,
			text    : '&nbsp;&nbsp;' + dgettext('plugin_files', 'Upload'),
			tooltip : {
				title   : dgettext('plugin_files', 'Store selected file'),
				text    : dgettext('plugin_files', String.format('Upload file to the selected {0} folder', container.getSettingsModel().get('zarafa/v1/plugins/files/button_name')))
			},
			iconCls : 'icon_files',
			handler : this.uploadFile,
			scope   : this
		},
		{
			xtype   : 'button',
			text    : dgettext('plugin_files', 'Cancel'),
			tooltip : {
				title   : dgettext('plugin_files', 'Cancel'),
				text    : dgettext('plugin_files', 'Close this window')
			},
			handler : this.onClose,
			scope   : this
		}];
	},
	
	/**
	 * This function is called on the upload button click.
	 * It checks the files for duplicates.
	 * @private
	 */
	uploadFile : function () {
		var fileStore = Zarafa.plugins.files.data.ComponentBox.getStore();
		
		fileStore.on('load', this.checkForDuplicate , this, {single: true});
		fileStore.loadPath(this.targetFolder);
	},
	
	/**
	 * This function is called after the {@Zarafa.plugins.files.data.FilesStore} has loaded the target folder.
	 * It will check if one of the selected files already exists in the store. If there is a duplicate file
	 * a warning will be shown.
	 *
	 * @param {Ext.data.Store} store
	 * @param {Ext.data.Record|Array} records The Records that were loaded
	 * @param {Object} options The loading options that were specified (see {@link #load} for details)
	 */
	checkForDuplicate : function(store, records, options) {
		// check if the selected file already exists
		var files = this.mainuploadfield.getEl().dom.files;
		var duplicateFiles = [];
		
		Ext.each(files, function(file){
			var recId = store.findExact("id", store.getPath() + file.name);
			
			if(recId != -1) {
				duplicateFiles.push(store.getById(recId));
			}
		});
		
		if(duplicateFiles.length > 0) {
			// Store already contains file - warn user.
			Ext.MessageBox.confirm(
				dgettext('plugin_files', 'Confirm overwrite'), 
				dgettext('plugin_files', 'File already exists. Do you want to overwrite it?'),
				this.doFormSubmit,
				this
			);
		} else {
			this.doFormSubmit();
		}
	},
	
	/**
	 * This function finally submits the upload form and destroyes the upload dialog.
	 * @param {String} button
	 * @private
	 */
	doFormSubmit : function(button) {
		if(!Ext.isDefined(button) || button === "yes") {
			var form = this.mainuploadform.getForm();
			
			if (form.isValid() && Ext.isDefined(this.targetFolder)) {
				form.submit({
					waitMsg: dgettext('plugin_files', 'Uploading files') + '...',
					url: 'plugins/files/php/upload_file.php',
					params: {
						"parentID" : this.targetFolder
					},
					failure: function(file, action) {
						Zarafa.common.dialogs.MessageBox.show({
							title : dgettext('plugin_files', 'Error'),
							msg : action.result.message,
							icon : Zarafa.common.dialogs.MessageBox.ERROR,
							buttons : Zarafa.common.dialogs.MessageBox.OK
						});
					},
					success: function(file, action) {
						var ocontext = container.getContextByName('filescontext'); // dont use ComponentBox ... we need the files context
						Zarafa.plugins.files.data.Actions.clearCache(false);
						ocontext.model.store.loadPath(action.result.parent);
					},
					scope : this
				});
			} 

			form.on('actioncomplete', this.onClose, this, { delay : 5 });
			form.on('actionfailed', this.onClose, this, { delay : 5 });
		}
	},
	
	/**
	 * Function is called on change of the textfield.
	 * @param {Object} field The textfield
	 * @param {String} newValue
	 * @param {String} oldValue
	 */
	onUploadFieldChanged : function(field, newValue, oldValue) {
		if(!Ext.isEmpty(newValue)) {
			// check if the filesize is under the limit
			var files = this.mainuploadfield.getEl().dom.files;
			var filesTooLarge = false;
			Ext.each(files, function(file){
				if(file.size > Zarafa.plugins.files.data.Dynamics.getMaxUploadFilesize()) {
					// reset the upload field
					this.mainuploadfield.reset();
					
					// show a warning to the user
					Zarafa.common.dialogs.MessageBox.show({
						title : dgettext('plugin_files', 'Error'),
						msg : String.format(dgettext('plugin_files', 'File "{0}" is too large! Maximum allowed filesize: {1}.'), file.name, Zarafa.plugins.files.data.Helper.Format.fileSize(Zarafa.plugins.files.data.Dynamics.getMaxUploadFilesize())),
						icon : Zarafa.common.dialogs.MessageBox.ERROR,
						buttons : Zarafa.common.dialogs.MessageBox.OK
					});
					
					// disable upload button
					this.mainuploadbutton.setDisabled(true);
					filesTooLarge = true;
					return false; // break loop
				} else {
					if(!filesTooLarge) {
						this.mainuploadbutton.setDisabled(false);
					}
				}
			}, this);
			
		} else {
			this.mainuploadbutton.setDisabled(true);
		}
	},
	
	/**
	 * Function is called on close of this dialog
	 */
	onClose : function() {
		Ext.TaskMgr.stop(this.updateTask);
		this.close();
	}
});

Ext.reg('zarafa.filesuploadcontentpanel', Zarafa.plugins.files.dialogs.FilesUploadContentPanel);
Ext.namespace('Zarafa.plugins.files.ui');

/**
 * @class Zarafa.plugins.files.ui.UploadButton
 * @extends Ext.SplitButton
 * @xtype zarafa.filesuploadbutton
 *
 * Special button which can be used for attaching items to a {@link Zarafa.core.data.IPMRecord IPMRecord}.
 * This utilizes the {@link #main.attachment.method} insertion point to allow plugins to register
 * alternative methods for attaching items to the record. These options will be shown inside the dropdown
 * list, while the default button action will be opening the Browsers File Selection dialog
 *
 * If the {@link Zarafa.core.plugins.RecordComponentUpdaterPlugin} is installed
 * in the {@link #plugins} array of this component, this component will automatically
 * load the {@link Zarafa.core.data.MAPIRecord record} into the component.
 * Otherwise the user of this component needs to call {@link #bindRecord}.
 */
Zarafa.plugins.files.ui.UploadButton = Ext.extend(Ext.SplitButton, {
	/**
	 * @insert main.attachment.method
	 * Provide a new method for attaching files to a {@link Zarafa.core.data.IPMRecord IPMRecord}.
	 * This can be used by 3rd party plugins to insert a new MenuItem into the dropdown
	 * box for the {@link Zarafa.common.attachment.ui.AttachmentButton AttachmentButton}.
	 * This insertion point should return a {@link Ext.menu.Item item} instance of configuration
	 * @param {Zarafa.plugins.files.ui.UploadButton} button This button
	 */
	 
	/**
	 * The {@link Zarafa.plugins.files.FilesContextModel} which is obtained from the {@link #context}.
	 * @property
	 * @type Zarafa.mail.MailContextModel
	 */
	model : undefined,

	/**
	 * @constructor
	 * @param {Object} config Configuration object
	 */
	constructor : function(config) {
		config = config || {};
		if (!Ext.isDefined(config.model) && Ext.isDefined(config.context))
			config.model = config.context.getModel();

		Ext.applyIf(config, {
			menu : {
				items : [{
					text : dgettext('plugin_files', 'Upload file'),
					iconCls : 'icon_files_category',
					handler : function() { 
						Zarafa.plugins.files.data.Actions.createUploadDialog(this.model);
					},
					scope: this
				},
				{
					text: dgettext('plugin_files', 'Create folder'),
					iconCls : 'icon_folder_create',
					action:'folder', 
					handler: function() { 
						Zarafa.plugins.files.data.Actions.createFolder(this.model); 
					}, 
					scope : this
				}]
			},
			handler : function() {
					this.showMenu();
			},
			scope : this
		});
		Zarafa.plugins.files.ui.UploadButton.superclass.constructor.call(this, config);
	},

	/**
	 * Event handler for opening the Browser's file selection dialog.
	 * See {@link #onFileInputChange} for the handling of the selected files.
	 * @private
	 */
	onFileUpload : function(field, event) {
		Zarafa.plugins.files.data.Actions.createUploadDialog({
			parentID : "myroot",
			scope : this
		});
	}	
});

Ext.reg('zarafa.filesuploadbutton', Zarafa.plugins.files.ui.UploadButton);
Ext.namespace('Zarafa.plugins.files.ui');

/**
 * @class Zarafa.plugins.files.ui.UploadPanel
 * @extends Zarafa.core.ui.ContentPanel
 * @xtype zarafa.plugins.files.uploadpanel
 */
Zarafa.plugins.files.ui.UploadPanel = Ext.extend(Zarafa.core.ui.ContentPanel, {
	/**
	 * @cfg {Function} callback The callback function which must be called when the
	 * {@link Ext.ux.form.FileUploadField File Input field} has been changed. It will
	 * receive the {@link Ext.form.BasicForm BasicForm} in which the input field is located
	 * as argument.
	 */
	callback : Ext.emptyFn,

	/**
	 * @cfg {Object} scope The scope for the {@link #callback} function
	 */
	scope : undefined,
	
	/**
	 * @cfg {String} parentID
	 */
	parentID : "/",
	
	/**
	 * @cfg {Object} task to check if file was selected
	 */
	updateTask : undefined,
	
	/**
	 * @constructor
	 * @param {Object} config Configuration object
	 */
	constructor : function(config) {
		config = config || {};

		Ext.applyIf(config, {
			title : dgettext('plugin_files', 'Select file'),
			layout : 'fit',
			width : 500,
			height : 75,
			items : [{
				xtype : 'form',
				layout: 'fit',
				fileUpload : true,
				ref : 'filesUploadform',
				buttonAlign: 'left',
				padding : 5,
				items : [{
					xtype : 'textfield',
					inputType : 'file',
					ref : 'uploadField',
					style : {
						border: 'none!important'
					},
					autoCreate : {tag: 'input', type: 'text', size: '20', autocomplete: 'off', multiple: 'multiple' },
					name : 'attachments[]',
					listeners : {
						change : this.onUploadFieldChanged,
						scope : this
					}
				}],
				buttons : [{
					xtype : 'displayfield',
					value : dgettext('plugin_files', 'Maximum upload size') + " : "+ Zarafa.plugins.files.data.Helper.Format.fileSize(Zarafa.plugins.files.data.Dynamics.getMaxUploadFilesize()),
					htmlEncode : true
				},
				{
					xtype: 'tbfill'
				},
				{
					text : dgettext('plugin_files', 'Upload'),
					ref : '../uploadButton',
					iconCls : 'icon_files',
					handler : this.onUpload,
					disabled: true,
					scope : this
				},
				{
					text : dgettext('plugin_files', 'Cancel'),
					handler : this.onClose,
					scope : this
				}]
			}]
		});

		Zarafa.plugins.files.ui.UploadPanel.superclass.constructor.call(this, config);
		
		// run a background task to check if a file was selected.
		// We have to do this because the onChange handler is only executed
		// if the textfield looses focus.
		// Start a simple clock task that updates a div once per second
		this.updateTask = {
			run: function() {
				this.onUploadFieldChanged(null, this.filesUploadform.uploadField.getValue(),null);
			},
			interval: 1000, //1 second
			scope: this
		}
		
		Ext.TaskMgr.start(this.updateTask);
	},

	/**
	 * Event which is fired when the {@link Ext.ux.form.FileUploadField#fileselected fileselected} was fired.
	 * @private
	 */
	onUpload : function() {		
		// check if the selected file already exists
		var files = this.filesUploadform.uploadField.getEl().dom.files;
		var store = Zarafa.plugins.files.data.ComponentBox.getStore();
		var duplicateFiles = [];
		
		// Immediately hide the dialog, we will close
		// it (destroying the HTML elements) once the
		// upload has completed.
		this.hide();
		
		Ext.each(files, function(file){
			var recId = store.findExact("id", store.getPath() + file.name);
			
			if(recId != -1) {
				duplicateFiles.push(store.getById(recId));
			}
		});
		
		if(duplicateFiles.length > 0) {
			// Store already contains file - warn user.
			Ext.MessageBox.confirm(
				dgettext('plugin_files', 'Confirm overwrite'), 
				dgettext('plugin_files', 'File already exists. Do you want to overwrite it?'),
				function(button) {
					if(button === "yes") {
						this.doFormSubmit();
					} else {
						this.onClose();
					}
				},
				this
			);
		} else {
			this.doFormSubmit();
		}
	},
	
	/**
	 * This function finally submits the upload form and destroyes the upload dialog.
	 * @private
	 */
	doFormSubmit : function() {
		var form = this.filesUploadform.getForm();
		
		if (form.isValid()) {
			form.submit({
				waitMsg: dgettext('plugin_files', 'Uploading files') + '...',
				url: 'plugins/files/php/upload_file.php',
				params: {
					"parentID" : this.parentID
				},
				failure: this.uploadDone.createDelegate(this, [false], true),
				success: this.uploadDone.createDelegate(this, [true], true),
				scope : this
			});
		}

		form.on('actioncomplete', this.onClose, this, { delay : 5 });
		form.on('actionfailed', this.onClose, this, { delay : 5 });
	},
	
	/**
	 * Called after form submit is complete.
	 *
	 * @param {Ext.form.BasicForm} form
	 * @param {Ext.form.Action} action
	 * @param {Boolean} success
	 * @private
	 */
	uploadDone : function (form, action, success) {
		if(!success) {
			Zarafa.common.dialogs.MessageBox.show({
				title : dgettext('plugin_files', 'Error'),
				msg : action.result.message,
				icon : Zarafa.common.dialogs.MessageBox.ERROR,
				buttons : Zarafa.common.dialogs.MessageBox.OK
			});
		} else {
			Zarafa.plugins.files.data.Actions.clearCache();
			Zarafa.plugins.files.data.ComponentBox.getStore().loadPath(action.result.parent);
		}
	},
	
	/**
	 * Function is called on change of the textfield.
	 * @param {Object} field The textfield
	 * @param {String} newValue
	 * @param {String} oldValue
	 */
	onUploadFieldChanged : function(field, newValue, oldValue) {
		if(!Ext.isEmpty(newValue)) {
			// check if the filesize is under the limit
			var files = this.filesUploadform.uploadField.getEl().dom.files;
			var filesTooLarge = false;
			Ext.each(files, function(file){
				if(file.size > Zarafa.plugins.files.data.Dynamics.getMaxUploadFilesize()) {
					// reset the upload field
					this.filesUploadform.uploadField.reset();
					
					// show a warning to the user
					Zarafa.common.dialogs.MessageBox.show({
						title : dgettext('plugin_files', 'Error'),
						msg : String.format(dgettext('plugin_files', 'File "{0}" is too large! Maximum allowed filesize: {1}.'), file.name, Zarafa.plugins.files.data.Helper.Format.fileSize(Zarafa.plugins.files.data.Dynamics.getMaxUploadFilesize())),
						icon : Zarafa.common.dialogs.MessageBox.ERROR,
						buttons : Zarafa.common.dialogs.MessageBox.OK
					});
					
					// disable upload button
					this.filesUploadform.uploadButton.setDisabled(true);
					filesTooLarge = true;
					return false; // break loop
				} else {
					if(!filesTooLarge) {
						this.filesUploadform.uploadButton.setDisabled(false);
					}
				}
			}, this);
		} else {
			this.filesUploadform.uploadButton.setDisabled(true);
		}
	},
	
	/**
	 * Function is called on close of this dialog
	 */
	onClose : function() {
		Ext.TaskMgr.stop(this.updateTask);
		this.close();
	}
});

Ext.reg('zarafa.plugins.files.uploadpanel', Zarafa.plugins.files.ui.UploadPanel);
Ext.namespace('Zarafa.plugins.files.ui');

/**
 * @class Zarafa.plugins.files.ui.NavigatorTreePanel
 * @extends Ext.tree.TreePanel
 * @xtype zarafa.filestreepanel
 * Shows tree of all user files from Files
 */
Zarafa.plugins.files.ui.NavigatorTreePanel = Ext.extend(Ext.tree.TreePanel, {

	/**
	 * @constructor
	 * @param {Object} config
	 */
	constructor : function(config) {
		config = config || {};
		Ext.applyIf(config, {
			xtype : 'zarafa.filestreepanel',
			enableDD : true,
			ddGroup : 'dd.filesrecord',
			root: {
				nodeType: 'async',
				text: '/',
				id: '/',
				expanded : true
			},
			autoScroll: true,
			listeners: {
				click: this.onNodeClick,
				beforenodedrop: {fn: function(e) {
				
					// e.data.selections is the array of selected records
					if(Ext.isArray(e.data.selections)) {
						// reset cancel flag
						e.cancel = false;
						
						Ext.each(e.data.selections, function(record) {
							record.setDisabled(true);
						});
						
						// we want Ext to complete the drop, thus return true
						return Zarafa.plugins.files.data.Actions.moveRecords(e.data.selections,e.target.id);
					}
					// if we get here the drop is automatically cancelled by Ext
				}},
				afterrender : function() {
					this.dragZone.lock(); // disable dragging from treepanel
				},
				expandnode : this.OnExpandNode,
				scope: this
			},
			viewConfig: {
				style : { overflow: 'auto', overflowX: 'hidden' }
			},
			maskDisabled: true,
			loader : new Zarafa.plugins.files.data.DirectoryLoader({loadfiles: false})
		});
		Zarafa.plugins.files.ui.NavigatorTreePanel.superclass.constructor.call(this, config);
	},
	
	/**
	 * eventhandler that handles the click on a node
	 * @param {Object} node
	 */
	onNodeClick : function(node) {
		Zarafa.plugins.files.data.ComponentBox.getStore().loadPath(node.attributes.id);
		var n = this.getNodeById(node.attributes.id);

		// Remove the icon class to show loading mask while user click on expandable node.
		if (node.isExpandable()) {
			var ui = node.getUI();
			var iconNode = Ext.get(ui.iconNode);
			iconNode.removeClass('icon_folder_note');
		}
		if(Ext.isDefined(n) && !n.isLeaf()) {
			n.reload();
		}
	},

	/**
	 * Event handler which is fires when a node is expanded in {@Link Zarafa.plugins.files.ui.NavigatorTreePanel}
	 * This will update the icon of root node as well as its all child's node
	 * @param {Ext.tree.TreeNode} rootNode The node which is expanded
	 */
	OnExpandNode: function (rootNode)
	{
		this.updateIcon(rootNode);
		if (rootNode.hasChildNodes()) {
			var childNodes = rootNode.childNodes;
			Ext.each(childNodes, function (node) {
				this.updateIcon(node);
			}, this)
		}
	},

	/**
	 * Function which is use to update the icon of {@Link Ext.tree.TreeNode}
	 * @param {Ext.tree.TreeNode} node The node which is need to update icon.
	 */
	updateIcon: function (node)
	{
		var ui = node.getUI();
		var iconNode = Ext.get(ui.iconNode);
		iconNode.addClass('icon_folder_note');
	}
});

Ext.reg('zarafa.filestreepanel',Zarafa.plugins.files.ui.NavigatorTreePanel); 
Ext.namespace('Zarafa.plugins.files.ui');

/**
 * @class Zarafa.plugins.files.ui.FilesViewPanel
 * @extends Ext.Panel
 * @xtype zarafa.filesviewpanel
 * 
 * Panel that shows the contents of mail messages.
 */
Zarafa.plugins.files.ui.FilesViewPanel = Ext.extend(Ext.Panel, {
	/**
	 * @constructor
	 * @param {Object} config configuration object.
	 */
	constructor : function(config) {
		config = config || {};
		
		Ext.applyIf(config, {
			xtype: 'zarafa.filesviewpanel',
			border : false,
			cls: 'zarafa-filesviewpanel',
			layout: 'zarafa.collapsible',
			items : [{
				xtype: 'zarafa.filesfileinfo'
			}]
		});

		Zarafa.plugins.files.ui.FilesViewPanel.superclass.constructor.call(this, config);
	}
});

Ext.reg('zarafa.filesviewpanel', Zarafa.plugins.files.ui.FilesViewPanel);
Ext.namespace('Zarafa.plugins.files.ui');

/**
 * @class Zarafa.plugins.files.ui.FilesFileInfo
 * @extends Ext.Panel
 * @xtype zarafa.filesfileinfo
 */
Zarafa.plugins.files.ui.FilesFileInfo = Ext.extend(Ext.form.FormPanel, {

	/**
	 * The default preview image url
	 */
	defaultPreviewImage : 'plugins/files/resources/images/no-preview.jpg',
	
	/**
	 * The record that will be shown
	 * only used in the dialog
	 */
	record : undefined,
	
	/**
	 * @constructor
	 * @param {Object} config configuration object.
	 */
	constructor : function(config) {
		config = config || {};
		var context = Zarafa.plugins.files.data.ComponentBox.getContext();
		var viewMode = context.getCurrentViewMode();		
		
		var layout = {
			type : 'vbox',
			align : 'stretch',
			pack : 'start'
		};
		switch(viewMode) {
			case Zarafa.plugins.files.data.ViewModes.RIGHT_PREVIEW:
				break;
			case Zarafa.plugins.files.data.ViewModes.BOTTOM_PREVIEW:
				layout = {
					type : 'hbox',
					align : 'stretch',
					pack : 'start'
				};
				break;
			default:
				break;
		}

		config = Ext.applyIf(config, {
			xtype : 'zarafa.filesfileinfo',
			ref : '../fileinfo',
			autoDestroy : true,
			layout : layout,
			border : false,
			items: [
				this.fieldSetFileInfo(),
				this.fieldSetFilePreview()
			]
		});
		
		if(Ext.isDefined(config.record)) {
			this.record = config.record;
			config = Ext.applyIf(config, {
				listeners : {
					afterlayout : function (cmp) {
						this.update(this.record);
					}
				}
			});
		}

		Zarafa.plugins.files.ui.FilesFileInfo.superclass.constructor.call(this, config);
	},
	
	/**
	 * clear the whole ui and redraw it
	 * 
	 */
	refresh : function() {
		this.removeAll();
		this.add(this.fieldSetFileInfo());
		this.add(this.fieldSetFilePreview());
	},
	
	/**
	 * The fieldset for the file infos
	 * @return {Object}
	 */
	fieldSetFileInfo: function() {
		return {
			xtype : 'fieldset',
			title : dgettext('plugin_files', 'File information'),
			height : 150,
			width : 300,
			defaults: {
				anchor: '-3' // leave a litte space
			},
			items : [{
				xtype : 'textfield',
				fieldLabel : dgettext('plugin_files', 'Filename'),
				ref : '../filename',
				value : "unknown",
				readOnly: true
			},
			{
				xtype : 'textfield',
				fieldLabel : dgettext('plugin_files', 'Filesize'),
				ref : '../filesize',
				value : "unknown",
				readOnly: true
			},
			{
				xtype : 'textfield',
				fieldLabel : dgettext('plugin_files', 'Last modified'),
				ref : '../lastmodified',
				value : "unknown",
				readOnly : true
			},
			{
				xtype : 'textfield',
				fieldLabel : dgettext('plugin_files', 'Type'),
				ref : '../type',
				value : "unknown",
				readOnly : true
			}]
		};
	},
	
	/**
	 * The fieldset for the file preview
	 * @return {Object}
	 */
	fieldSetFilePreview : function() {
		var context = Zarafa.plugins.files.data.ComponentBox.getContext();
		var viewMode = context.getCurrentViewMode();
		
		var css = "width: 100%;";
		switch(viewMode) {
			case Zarafa.plugins.files.data.ViewModes.RIGHT_PREVIEW:
				css = "width: 100%;";
				break;
			case Zarafa.plugins.files.data.ViewModes.BOTTOM_PREVIEW:
				css = "height: 100%;";
				break;
			default:
				break;
		}
		
		return {
			xtype : 'fieldset',
			title : dgettext('plugin_files', 'File preview'),
			ref : 'filepreview',
			flex : 1,
			//defaults : {anchor: '0, 0'},
			defaultType : 'textfield',
			items : [{
				xtype : 'component',
				id : 'previewimage',
				autoEl : { tag: 'img', src: this.defaultPreviewImage, style: css}
			}]
		};
	},
	
	/**
	 * Initialises the file preview panel with the given record
	 * @param {Zarafa.plugins.files.data.FilesRecord} record
	 * @param {String} extension File extension.
	 */
	setPreviewPanel : function (record, extension) {
		var context = Zarafa.plugins.files.data.ComponentBox.getContext();
		var viewMode = context.getCurrentViewMode();
		var mediaEnabled = Ext.ComponentMgr.isRegistered('mediapanel');
		
		var css = "width: 100%;";
		switch(viewMode) {
			case Zarafa.plugins.files.data.ViewModes.RIGHT_PREVIEW:
				css = "width: 100%;";
				break;
			case Zarafa.plugins.files.data.ViewModes.BOTTOM_PREVIEW:
				css = "height: 100%;";
				break;
			default:
				break;
		}
		
		var component = {};
		
		// check extension and decide which preview to show
		if(!Ext.isEmpty(extension) && (/\.(gif|jpg|jpeg|tiff|png)$/i).test(extension)) {
			component = {
				xtype : 'component',
				autoEl : { tag: 'img', src: Zarafa.plugins.files.data.Actions.getDownloadLink(record), style: css}
			}
		} else if (mediaEnabled && !Ext.isEmpty(extension) && (/\.(pdf)$/i).test(extension)) {
			component = {
				xtype : 'mediapanel',
				anchor: '0, 0',
				mediaCfg : {
					mediaType : 'PDF',
					url : Zarafa.plugins.files.data.Actions.getDownloadLink(record),
					unsupportedText : dgettext('plugin_files', 'Sorry - no preview for this PDF file!')
				}
			}
		} else if (!Ext.isEmpty(extension) && (/\.(txt|html|php|js|c|cpp|h|java|sh|bat|log|cfg|conf|tex|py|pl)$/i).test(extension)) {
			component = {
				xtype: 'textarea',
				hideLabel : true,
				readOnly : true,
				anchor: '0, 0',
				listeners : {
					'afterrender' : function () {
						Ext.Ajax.request({
							method : 'GET',
							url : Zarafa.plugins.files.data.Actions.getDownloadLink(record),
							success: function( result, request ){
								var responsetext = result.responseText;
								
								this.setRawValue(responsetext);
							},
							scope : this
						});
					}
				}
			}
		} else if (mediaEnabled && !Ext.isEmpty(extension) && (/\.(mp3|aac|ogg)$/i).test(extension)) {
			component = {
				xtype : 'mediapanel', // could be replaced by Ext.FlashComponent
				anchor: '0, 0',
				mediaCfg : {
					mediaType : 'JWP',
					url : 'plugins/files/resources/flash/player.swf',
					width : '100%',
					height: 100,
					start : false,
					loop : false,
					unsupportedText : dgettext('plugin_files', 'JW FLV Player is not installed/available.'),
					params : {
						wmode : 'transparent',
						allowscriptaccess : 'always',
						allowfullscreen : 'false', // fullscreen wont work in flash
						flashVars : {
							width      : '@width',
							height     : '@height',
							autostart  : '@start',
							file       : Zarafa.plugins.files.data.Actions.getDownloadLink(record,false),
							skin       : 'plugins/files/resources/flash/jwskin/lightrv5/lightrv5.xml',
							type	   : 'sound',
							showdigits : true,
							volume     : 15,
							repeat     : '@loop'
						}
					}
				}
			}
		} else if (mediaEnabled && !Ext.isEmpty(extension) && (/\.(mp4|flv|mov|webm)$/i).test(extension)) {
			component = {
				xtype : 'mediapanel', // could be replaced by Ext.FlashComponent
				anchor: '0, 0',
				mediaCfg : {
					mediaType : 'JWP',
					url : 'plugins/files/resources/flash/player.swf',
					width : '100%',
					start : false,
					loop : false,
					unsupportedText : dgettext('plugin_files', 'JW FLV Player is not installed/available.'),
					params : {
						wmode : 'transparent',
						allowscriptaccess : 'always',
						allowfullscreen : 'false', // fullscreen wont work in flash
						flashVars : {
							width      : '@width',
							height     : '@height',
							autostart  : '@start',
							file       : Zarafa.plugins.files.data.Actions.getDownloadLink(record,false),
							skin       : 'plugins/files/resources/flash/jwskin/lightrv5/lightrv5.xml',
							type	   : 'video',
							showdigits : true,
							volume     : 15,
							repeat     : '@loop'
						}
					}
				}
			}
		} else {
			component = {
				xtype : 'component',
				autoEl : { tag: 'img', src: this.defaultPreviewImage, style: css}
			}
		}
		
		this.filepreview.removeAll(true);
		this.filepreview.add(component);
		this.filepreview.doLayout();    
	},
	
	/**
	 * Updates the container by loading data from the record data into the {@link #template}
	 * 	
	 * @param {Zarafa.core.data.IPMRecord} record The record to update the header panel with
	*/	
	update : function(record) {	
		//TODO: change layout of parent container!		
		var extension = this.getExtension(record.get('filename'));
		
		this.filename.setValue(record.get('filename'));
		if(record.get('type') == Zarafa.plugins.files.data.FileTypes.FILE) {
			this.filesize.show();
			this.filesize.setValue(Zarafa.plugins.files.data.Helper.Format.fileSize(record.get('message_size')));
		} else {
			this.filesize.hide();
		}
		this.lastmodified.setValue(Ext.util.Format.date(new Date(record.get('lastmodified')), dgettext('plugin_files', 'd.m.Y G:i')));
		this.type.setValue(record.get('type') == Zarafa.plugins.files.data.FileTypes.FILE ? String.format(dgettext('plugin_files', 'File ({0})'), extension) : dgettext('plugin_files', 'Folder'));
		
		this.setPreviewPanel(record, extension);
	},

	/**
	 * Called when this component is being rendered into a container.
	 * This will create a {@link #wrap} element around the iframe for
	 * better organize the scrolling.
	 *
	 * @param {Ext.Container} ct The container into which this component is being rendered
	 * @param {Number} position The position inside the container where this component is being rendered
	 * @private
	 */
	onRender : function(ct, position) {
		Zarafa.plugins.files.ui.FilesFileInfo.superclass.onRender.call(this, ct, position);
		this.wrap = this.el.wrap({cls: 'preview-body'});
		this.resizeEl = this.positionEl = this.wrap;
	},
	
	/**
	 * Get the extension from the filename
	 *
	 * @param {String} Filename
	 * @return {String} Extension string
	 */
	getExtension : function(filename) {
		var i = filename.lastIndexOf('.');
		return (i < 0) ? '' : filename.substr(i);
	}
});

Ext.reg('zarafa.filesfileinfo', Zarafa.plugins.files.ui.FilesFileInfo);
Ext.namespace('Zarafa.plugins.files.ui');

/**
 * @class Zarafa.plugins.files.ui.FilesPreviewPanelToolbarButtons
 * @extends Object
 *
 * Contains special toolbar buttons for the previewpanel of the files context.
 */
Zarafa.plugins.files.ui.FilesPreviewPanelToolbarButtons = Ext.extend(Object, {
	/**
	 * @cfg {@link Zarafa.plugins.files.context.FilesContextModel}
	 */
	model : undefined,

	/**
	 * @constructor
	 * @param config Configuration structure
	 */
	constructor : function(config) {
		Ext.apply(this, config);
	},

	/**
	 * Function called when insertion point previewpanel.toolbar.right is called,
	 * Function returns configuration object for Copy/Move, Delete and Print buttons
	 * which are added on the right side of previewpanels toolbar.
	 * 
	 * @return {Object} Configuration object containing buttons
	 * which are added in the {@link Ext.Toolbar Toolbar}.
	 */
	getToolbarButtons : function() {
		return [{
			xtype: 'tbfill'
		},
		{
			xtype: 'zarafa.toolbarbutton',
			tooltip: dgettext('plugin_files', 'Delete'),
			overflowText: dgettext('plugin_files', 'Delete'),
			iconCls : 'icon_delete',
			nonEmptySelectOnly: true,
			handler: this.onDelete,
			model: this.model
		},
		{
			xtype: 'zarafa.toolbarbutton',
			tooltip: dgettext('plugin_files', 'Rename'),
			overflowText: dgettext('plugin_files', 'Rename'),
			iconCls : 'icon_rename',
			nonEmptySelectOnly: true,
			handler: this.onRename,
			model: this.model
		}];
	},
	
	/**
	 * Rename the item
	 * @private
	 */
	onRename : function() {
		var records = this.model.getSelectedRecords();
		
		if(records.length != 1) {
			Zarafa.common.dialogs.MessageBox.show({
				title   : dgettext('plugin_files', 'Warning'),
				msg     : dgettext('plugin_files', 'You can only rename one file!'),
				icon    : Zarafa.common.dialogs.MessageBox.WARNING,
				buttons : Zarafa.common.dialogs.MessageBox.OK
			});
		} else {
			Zarafa.plugins.files.data.Actions.openRenameDialog(this.model, records[0]);
		}
	},
	
	/**
	 * Delete the item
	 * @private
	 */
	onDelete : function() {
		var allowDelete = true;
		var records = this.model.getSelectedRecords();
		
		Ext.each(records, function(record) {
			if(record.get('id') === (container.getSettingsModel().get('zarafa/v1/contexts/files/files_path') + "/") || record.get('filename') === "..") {
				allowDelete = false;
			}
		}, this);
		
		var askOnDelete = container.getSettingsModel().get('zarafa/v1/contexts/files/ask_before_delete');
		
		if(allowDelete) {
			if(askOnDelete) {
				Ext.MessageBox.confirm(dgettext('plugin_files', 'Confirm deletion'), dgettext('plugin_files', 'Are you sure?'), function showResult(btn) {
					if(btn == 'yes') {
						Zarafa.plugins.files.data.ComponentBox.getStore().on('remove', function handleRemove(store, batch, data) {
								if(container.getCurrentContext().getCurrentView() === Zarafa.plugins.files.data.Views.ICON) {
								Zarafa.plugins.files.data.Actions.clearCache();
							} else {
								Zarafa.plugins.files.data.Actions.refreshNavigatorTree();
							}
						}, null, {single: true});
						
						Zarafa.common.Actions.deleteRecords(records);
					}
				}, this);
			} else {
				Zarafa.plugins.files.data.ComponentBox.getStore().on('remove', function handleRemove(store, batch, data) {
					if(container.getCurrentContext().getCurrentView() === Zarafa.plugins.files.data.Views.ICON) {
						Zarafa.plugins.files.data.Actions.clearCache();
					} else {
						Zarafa.plugins.files.data.Actions.refreshNavigatorTree();
					}
				}, null, {single: true});
						
				Zarafa.common.Actions.deleteRecords(records);
			}
		} else {
			Zarafa.common.dialogs.MessageBox.show({
				title   : dgettext('plugin_files', 'Warning'),
				msg     : dgettext('plugin_files', 'You cannot delete the parent folder!'),
				icon    : Zarafa.common.dialogs.MessageBox.WARNING,
				buttons : Zarafa.common.dialogs.MessageBox.OK
			});
		}
	}
});
Ext.namespace('Zarafa.plugins.files.ui');

/**
 * @class Zarafa.plugins.files.ui.FilesToolbar
 * @extends Ext.Toolbar
 * The toolbar shown in the files context
 */
Zarafa.plugins.files.ui.FilesToolbar = Ext.extend(Ext.Toolbar, {

	/**
	 * @constructor
	 * @param {Object} config
	 */
	constructor : function(config) {
		config = config || {};
		
		config.plugins = Ext.value(config.plugins, []);
		config.plugins.push('zarafa.recordcomponentupdaterplugin');

		Ext.applyIf(config, {
			items: [{
				xtype : 'zarafa.filesuploadbutton',
				ref : 'uploadbutton',
				plugins : [ 'zarafa.recordcomponentupdaterplugin' ],
				model : config.context.getModel(),
				overflowText : dgettext('plugin_files', 'Create something new') + '...',
				tooltip : {
					title : dgettext('plugin_files', 'New'),
					text : dgettext('plugin_files', 'Upload file / Create folder')
				},
				iconCls : 'icon_attachment'
			},
			{
				xtype: 'zarafa.toolbarbutton',
				tooltip : {
					title : dgettext('plugin_files', 'Up'),
					text : dgettext('plugin_files', 'Go to parent directory')
				},
				overflowText: dgettext('plugin_files', 'Go to parent directory'),
				iconCls: 'icon_up',
				handler: this.onMoveUp,
				model: config.context.getModel()
			},
			{
				xtype: 'tbfill'
			},
			{
				xtype: 'zarafa.toolbarbutton',
				tooltip: dgettext('plugin_files', 'Clear cache'),
				overflowText: dgettext('plugin_files', 'Clear cache'),
				iconCls: 'icon_cache',
				hidden: !container.getSettingsModel().get('zarafa/v1/contexts/files/enable_caching'),
				handler: this.onClearCache,
				model: config.context.getModel()
			},
			container.populateInsertionPoint('context.filescontext.toolbar.item', this),
			{
				xtype: 'tbseparator'
			},
			{
				xtype: 'tbtext', 
				text: 'Version: ' + Zarafa.plugins.files.data.Version.getFilesVersion()
			}]
		});
		Zarafa.plugins.files.ui.FilesToolbar.superclass.constructor.call(this, config);
	},
	
	/**
	 * Clear the webdav request cache!
	 * @private
	 */
	onClearCache : function() {
		Zarafa.plugins.files.data.Actions.clearCache();
	},
	
	/**
	 * Move one directory up
	 * @private
	 */
	onMoveUp : function() {
		var currentDir = Zarafa.plugins.files.data.ComponentBox.getStore().getPath();
		
		if(currentDir === "/")
			return;
		
		// remove trailing slash
		if(currentDir.substring(currentDir.length - 1) === '/') {
			currentDir = currentDir.substring(0, currentDir.length - 1);
		}
		
		var parentDir = currentDir.substring( 0, currentDir.lastIndexOf( "/" ) + 1);

		Zarafa.plugins.files.data.ComponentBox.getStore().loadPath(parentDir);
		Zarafa.plugins.files.data.Actions.reloadCurrentDir();
	}
});

Ext.reg('zarafa.filestoolbar',Zarafa.plugins.files.ui.FilesToolbar);
Ext.namespace('Zarafa.plugins.files.ui');

/**
 * @class Zarafa.plugins.files.ui.FilesPreviewPanel
 * @extends Zarafa.core.ui.PreviewPanel
 * @xtype zarafa.filespreviewpanel
 */
Zarafa.plugins.files.ui.FilesPreviewPanel = Ext.extend(Ext.Panel, {
	/**
	 * @constructor
	 * @param config Configuration structure
	 */
	constructor : function(config) {
		config = config || {};

		if (!Ext.isDefined(config.model) && Ext.isDefined(config.context))
			config.model = config.context.getModel();
		
		var toolbarButtons = new Zarafa.plugins.files.ui.FilesPreviewPanelToolbarButtons({model: config.model});
		var tbarItems = [
			container.populateInsertionPoint('filespreviewpanel.toolbar.left', this, config.model),
			{xtype: 'tbfill'},
			toolbarButtons.getToolbarButtons(), // Default items in toolbar should be right aligned.
			container.populateInsertionPoint('filespreviewpanel.toolbar.right', this, config.model)
		]
		
		var toolbar = Ext.applyIf(config.tbar || {}, {
			cls: 'zarafa-previewpanel-toolbar',
			xtype : 'zarafa.toolbar',
			height : 33,
			hidden : false,
			items : Ext.flatten(tbarItems)
		});
		
		Ext.applyIf(config, {
			xtype : 'zarafa.filespreviewpanel',
			layout : 'fit',
			stateful : true,
			cls : 'zarafa-previewpanel zarafa-context-mainpanel',
			width : 300, // default values
			height : 300, // default values
			tbar : toolbar			
		});

		Zarafa.plugins.files.ui.FilesPreviewPanel.superclass.constructor.call(this, config);
	}
});

Ext.reg('zarafa.filespreviewpanel', Zarafa.plugins.files.ui.FilesPreviewPanel);

Ext.namespace('Zarafa.plugins.files.ui');

/**
 * @class Zarafa.plugins.files.ui.FilesFileGridColumnModel
 * @extends Zarafa.common.ui.grid.ColumnModel
 *
 * The {@link Zarafa.plugins.files.ui.FilesFileGridColumnModel FilesFileGridColumnModel}
 * is the default {@link Ext.grid.ColumnModel ColumnModel} containing two
 * different sets of {@link Ext.grid.Column columns}. The first set contains
 * all {@link Ext.grid.Column columns} which should be available in the
 * {@link Zarafa.plugins.files.ui.FilesFileGrid FilesFileGrid} (either hidden by default,
 * or directly visible). For a more compact view, a more compact set is
 * provided. Switching between the two sets can be done using
 * {@link Zarafa.plugins.files.ui.FilesFileGridColumnModel.useCompactView useCompactView}
 * during configuration, or {@link Zarafa.plugins.files.ui.FilesFileGridColumnModel.setCompactView setCompactView}
 * when the {@link Zarafa.plugins.files.ui.FilesFileGridColumnModel FilesFileGridColumnModel} is already active.
 */
Zarafa.plugins.files.ui.FilesFileGridColumnModel = Ext.extend(Zarafa.common.ui.grid.ColumnModel, {
	/**
	 * @cfg {Boolean} useCompactView If true the compact column model will be
	 * used by default. Otherwise the default column model will be used which
	 * contains all possible columns.
	 */
	useCompactView : false,
	
	/**
	 * @constructor
	 * @param config Configuration structure
	 */
	constructor : function(config) {
		config = config || {};

		this.defaultColumns = this.createDefaultColumns();
		this.compactColumns = this.createCompactColumns();

		Ext.applyIf(config, {
			columns: this.defaultColumns,
			defaults: {
				sortable: true
			}
		});

		// Switch to compact view if needed
		if (config.useCompactView === true)
			config.columns = this.compactColumns;

		Ext.apply(this, config);

		Zarafa.plugins.files.ui.FilesFileGridColumnModel.superclass.constructor.call(this, config);
	},

	/**
	 * Create an array of {@link Ext.grid.Column columns} which must be visible within
	 * the default view of this {@link Ext.grid.ColumnModel ColumnModel}.
	 *
	 * @return {Ext.grid.Column|Array} The array of columns
	 * @private
	 */
	createDefaultColumns : function() {
		return [{
			id : 'type',
			dataIndex : 'type',
			header : '<p class="icon_index">&nbsp;</p>',
			headerCls: 'zarafa-icon-column icon',
			renderer : Zarafa.plugins.files.data.Helper.Renderer.typeRenderer,
			width: 24,
			fixed : true,
			tooltip : dgettext('plugin_files', 'Sort by: Type')
		},
		{
			header : 'ID',
			dataIndex : 'id',
			width: 50,
			hidden: true,
			tooltip : dgettext('plugin_files', 'Sort by: ID')
		},
		{
			header : 'Path',
			dataIndex : 'path',
			width: 100,
			hidden: true,
			tooltip : dgettext('plugin_files', 'Sort by: Path')
		},
		{
			header : dgettext('plugin_files', 'Filename'),
			dataIndex : 'filename',
			width : 160,
			tooltip : dgettext('plugin_files', 'Sort by: Filename')
		},
		{
			header : dgettext('plugin_files', 'Last modified'),
			dataIndex : 'lastmodified',
			width : 160,
			renderer : Zarafa.plugins.files.data.Helper.Renderer.datetimeRenderer,
			tooltip : dgettext('plugin_files', 'Sort by: Last modified')
		},
		{
			header : dgettext('plugin_files', 'Size'),
			dataIndex : 'message_size',
			css: 'text-align:right;', // only align column content to the right
			width : 80,
			renderer : Zarafa.plugins.files.data.Helper.Format.fileSizeList,
			tooltip : dgettext('plugin_files', 'Sort by: Size')
		}];
	},	

	/**
	 * Create an array of {@link Ext.grid.Column columns} which must be visible within
	 * the compact view of this {@link Ext.grid.ColumnModel ColumnModel}.
	 *
	 * @return {Ext.grid.Column|Array} The array of columns
	 * @private
	 */
	createCompactColumns : function() {
		return [{
			id : 'column_type',
			dataIndex : 'type',
			header : '<p class="icon_index">&nbsp;</p>',
			headerCls: 'zarafa-icon-column icon',
			renderer : Zarafa.plugins.files.data.Helper.Renderer.typeRenderer,
			width: 24,
			fixed : true,
			tooltip : dgettext('plugin_files', 'Sort by: Type')
		},
		{
			header : dgettext('plugin_files', 'Filename'),
			dataIndex : 'filename',
			width : 160,
			tooltip : dgettext('plugin_files', 'Sort by: Filename')
		},
		{
			header : dgettext('plugin_files', 'Last modified'),
			dataIndex : 'lastmodified',
			width : 100,
			renderer : Zarafa.plugins.files.data.Helper.Renderer.datetimeRenderer,
			tooltip : dgettext('plugin_files', 'Sort by: Last modified')
		},
		{
			header : dgettext('plugin_files', 'Size'),
			dataIndex : 'message_size',
			css: 'text-align:right;', // only align column content to the right
			width : 80,
			hidden: true,
			renderer : Zarafa.plugins.files.data.Helper.Format.fileSizeList,
			tooltip : dgettext('plugin_files', 'Sort by: Size')
		}];
	},

	/**
	 * This will switch the {@link Zarafa.plugins.files.ui.FilesFileGridColumnModel columnmodel}
	 * configuration to either the compact or extended configuration.
	 *
	 * @param {Boolean} compact True to enable the compact view
	 */
	setCompactView : function(compact) {
		if (this.useCompactView !== compact) {
			this.useCompactView = compact;

			if (compact) {
				this.name = 'compact';
				// Extjs will store the this.columns into this.config after it has constructed
				// all the columns. At that point this.columns consists of the configuration objects,
				// while this.columns consists of all the allocated columns.
				this.defaultColumns = this.config;
				this.columns = this.compactColumns;
			} else {
				this.name = 'default';
				this.compactColumns = this.config;
				this.columns = this.defaultColumns;
			}

			this.setConfig(this.columns, false);
		}
	}
});
Ext.namespace('Zarafa.plugins.files.ui');

/**
 * @class Zarafa.plugins.files.ui.FilesFileGridContextMenu
 * @extends Zarafa.core.ui.menu.ConditionalMenu
 * @xtype zarafa.filesfilegridcontextmenu
 *
 * Extend {@link Zarafa.core.ui.menu.ConditionalMenu ConditionalMenu} to add the
 * {@link Zarafa.core.ui.menu.ConditionalItems ConditionalItems} for the
 * FilesContext.
 */
Zarafa.plugins.files.ui.FilesFileGridContextMenu = Ext.extend(Zarafa.core.ui.menu.ConditionalMenu, {
	// Insertion points for this class
	/**
	 * @insert context.files.contextmenu.actions
	 * Insertion point for adding actions menu items into the context menu
	 * @param {Zarafa.plugins.files.ui.FilesGridContextMenu} contextmenu This contextmenu
	 */
	/**
	 * @insert context.files.contextmenu.options
	 * Insertion point for adding options menu items into the context menu
	 * @param {Zarafa.plugins.files.ui.FilesGridContextMenu} contextmenu This contextmenu
	 */

	/**
	 * @cfg {Zarafa.plugins.files.context.FilesContext} context The context to which this panel belongs
	 */
	context : undefined,

	/**
	 * The {@link Zarafa.plugins.files.FilesContextModel} which is obtained from the {@link #context}.
	 * @property
	 * @type Zarafa.plugins.files.context.FilesContextModel
	 */
	model : undefined,
	
	/**
	 * The {@link Zarafa.plugins.files.ui.FilesFileGrid} which is obtained from the {@link #config}.
	 * @property
	 * @type Zarafa.plugins.files.ui.FilesFileGrid
	 */
	grid : undefined,

	/**
	 * @constructor
	 * @param {Object} config Configuration object
	 */
	constructor : function(config) {
		config = config || {};

		if (!Ext.isDefined(config.model) && Ext.isDefined(config.context))
			config.model = config.context.getModel();
		
		Ext.applyIf(config, {
			items: [
				this.createContextActionItems(),
				{ xtype: 'menuseparator' },
				container.populateInsertionPoint('context.filescontext.contextmenu.actions', this),
				{ xtype: 'menuseparator' },
				container.populateInsertionPoint('context.filescontext.contextmenu.options', this)
			]
		});

		Zarafa.plugins.files.ui.FilesFileGridContextMenu.superclass.constructor.call(this, config);
	},
	
	/**
	 * Apply the {@link #emptySelectOnly}, {@link #nonEmptySelectOnly}, {@link #singleSelectOnly}
	 * and {@link #multiSelectOnly} filters to determine if the item must be {@link #setDisabled disabled}
	 * or not.
	 * @private
	 */
	applyItemFilter : function(records, singleSelectOnly, fileOnly, noRoot) {
		var visible = true;
		
		if (singleSelectOnly) {
			if (!Ext.isDefined(records) || (Ext.isArray(records) && records.length != 1))
				visible = false;
		}
		
		if (fileOnly) {
			for (var i = 0; i < records.length; i++) {
				var record = records[i];
				if(record.get('type') == Zarafa.plugins.files.data.FileTypes.FOLDER) {
					visible = false;
					break;
				}
			}
		}
		
		if (noRoot) {
			for (var i = 0; i < records.length; i++) {
				var record = records[i];
				if(record.get('id') === (container.getSettingsModel().get('zarafa/v1/contexts/files/files_path') + "/") || record.get('filename') === "..") {
					visible = false;
					break;
				}
			}
		}
		
		return visible;
	},

	/**
	 * Create the Action context menu items
	 * @return {Zarafa.core.ui.menu.ConditionalItem|Array} The list of Action context menu items
	 * @private
	 */
	createContextActionItems : function() {
		return [{
			xtype: 'zarafa.conditionalitem',
			text : dgettext('plugin_files', 'Open'),
			iconCls : 'icon_open',
			handler: this.onContextItemOpen,
			beforeShow : function(item, records) {
				var visible = this.applyItemFilter(records, false, true, false);
				var visibleFolders = this.applyItemFilter(records, true, false, false);
				
				item.setVisible(visible || visibleFolders);
			},
			scope: this
		},
		{
			xtype: 'zarafa.conditionalitem',
			text : dgettext('plugin_files', 'Rename'),
			iconCls : 'icon_rename',
			handler: this.onContextItemRename,
			beforeShow : function(item, records) {
				item.setVisible(this.applyItemFilter(records, true, false, true));
			},
			scope: this
		},
		{
			xtype: 'zarafa.conditionalitem',
			text : dgettext('plugin_files', 'Attach to mail'),
			iconCls : 'icon_replyEmail',
			handler: this.onContextItemAttach,
			beforeShow : function(item, records) {
				var visible = this.applyItemFilter(records, false, true, true);
				
				var max_file_size = container.getSettingsModel().get('zarafa/v1/main/attachments/max_attachment_size');
				for (var i = 0; i < records.length; i++) {
					var record = records[i];
					if(record.get('message_size') > max_file_size) {
						visible = false;
						break;
					}
				}
				
				item.setVisible(visible);
			},
			scope: this
		},
		{
			xtype: 'zarafa.conditionalitem',
			text : dgettext('plugin_files', 'Delete'),
			iconCls : 'icon_delete',
			handler: this.onContextItemDelete,
			beforeShow : function(item, records) {
				item.setVisible(this.applyItemFilter(records, false, false, true));
			},
			scope: this
		},
		{
			xtype: 'zarafa.conditionalitem',
			text : dgettext('plugin_files', 'Info'),
			iconCls : 'icon_info',
			disabled : Zarafa.plugins.files.data.ComponentBox.getContext().getCurrentViewMode() == Zarafa.plugins.files.data.ViewModes.NO_PREVIEW ? false : true,
			handler: this.onContextItemInfo,
			beforeShow : function(item, records) {
				item.setVisible(this.applyItemFilter(records, true, false, true));
			},
			scope: this
		}];
	},

	/**
	 * Event handler which is called when the user selects the 'Open'
	 * item in the context menu. This will open the item in a new panel.
	 * @private
	 */
	onContextItemOpen : function() {
		Zarafa.plugins.files.data.Actions.openFilesContent(this.records);
	},
	
	/**
	 * Event handler which is called when the user selects the 'Delete'
	 * item in the context menu. This will delete all selected records.
	 * @private
	 */
	onContextItemDelete : function() {
		var allowDelete = true;
		
		Ext.each(this.records, function(record) {
			if(record.get('id') === (container.getSettingsModel().get('zarafa/v1/contexts/files/files_path') + "/") || record.get('filename') === "..") {
				allowDelete = false;
			}
		}, this);
		
		var askOnDelete = container.getSettingsModel().get('zarafa/v1/contexts/files/ask_before_delete');
		
		if(allowDelete) {
			if(askOnDelete) {
				Ext.MessageBox.confirm(dgettext('plugin_files', 'Confirm deletion'), dgettext('plugin_files', 'Are you sure?'), this.doDelete, this);
			} else {
				this.doDelete();
			}
		}
		
	},
	
	/**
	 * Delete the selected files.
	 *
	 * @param {String} button The value of the button
	 * @private
	 */
	doDelete : function (button) {
		if(!Ext.isDefined(button) || button === 'yes') {
			Zarafa.plugins.files.data.ComponentBox.getStore().on('remove', this.deleteDone, null, {single: true});
			Zarafa.common.Actions.deleteRecords(this.records);
		}
	},
	
	/**
	 * Function gets called after files were removed.
	 * @private
	 */
	deleteDone : function () {
		if(container.getCurrentContext().getCurrentView() === Zarafa.plugins.files.data.Views.ICON) {
			Zarafa.plugins.files.data.Actions.clearCache();
		} else {
			Zarafa.plugins.files.data.Actions.refreshNavigatorTree();
		}
	},
	
	/**
	 * Event handler which is called when the user selects the 'Info'
	 * item in the context menu. This will load the preview panel with infos about the file
	 * @private
	 */
	onContextItemInfo : function() {
		var count = this.records.length;
		var record = undefined;
		
		if (count == 1)
			record = this.records[0];
	
		var config = Ext.applyIf({}, {
			modal : true,
			record : record
		});
		
		var componentType = Zarafa.core.data.SharedComponentType['zarafa.plugins.files.fileinfopanel'];
		Zarafa.core.data.UIFactory.openLayerComponent(componentType, undefined, config);
	},
	
	/**
	 * Event handler which is called when the user selects the 'Rename'
	 * item in the context menu. This will load the preview panel with infos about the file
	 * @private
	 */
	onContextItemRename : function() {
		Zarafa.plugins.files.data.Actions.openRenameDialog(this.model, this.records[0]);
	},
	
	/**
	 * Event handler which is called when the user selects the 'Attach to Mail'
	 * item in the context menu. 
	 * @private
	 */
	onContextItemAttach : function() {
		var emailRecord = container.getContextByName("mail").getModel().createRecord();
		var idsList = [];
		var attachmentStore = emailRecord.getAttachmentStore();

		Ext.each(this.records, function(record) {
			idsList.push(record.get('id'));
		}, this);
		
		container.getNotifier().notify('info.files', dgettext('plugin_files', 'Attaching'), dgettext('plugin_files', 'Creating email... Please wait!'));
		
		try {
			container.getRequest().singleRequest(
				'filesmodule',
				'download-to-tmp',
				{
					ids : idsList,
					dialog_attachments: attachmentStore.getId()
				},
				new Zarafa.plugins.files.data.ResponseHandler({
					successCallback : this.attachToMail.createDelegate(this, [emailRecord], true)
				})
			);
		} catch (e) {
			Zarafa.plugins.files.data.Actions.msgWarning(e.message);
		}
	},
	
	/**
	 * Attach a file to an email.
	 *
	 * @param {Array} responseItems
	 * @param {Object} response Server response
	 * @param {IPMRecord} emailRecord
	 */
	attachToMail : function(responseItems, response, emailRecord) {
		Zarafa.plugins.files.data.Actions.openCreateMailContent(emailRecord,responseItems);
	}
});

Ext.reg('zarafa.filesfilegridcontextmenu', Zarafa.plugins.files.ui.FilesFileGridContextMenu);
Ext.namespace('Zarafa.plugins.files.ui');

/**
 * @class Zarafa.plugins.files.ui.FilesFileTable
 * @extends Ext.grid.GridPanel
 * @xtype zarafa.filesfilegrid
 * The main gridpanel for our data
 */
Zarafa.plugins.files.ui.FilesFileGrid = Ext.extend(Zarafa.common.ui.grid.GridPanel, {
	/**
	 * @cfg {Zarafa.plugins.files.context.FilesContext} context The context to which this panel belongs
	 */
	context : undefined,
	
	/**
	 * The {@link Zarafa.plugins.files.context.FilesContextModel} which is obtained from the {@link #context}.
	 * @property
	 * @type Zarafa.plugins.files.context.FilesContextModel
	 */
	model : undefined,
	
	/**
	 * The dropZone used by this grid if drop is enabled
	 * @property
	 */
	dropTarget : undefined,
		
	/**
	 * @constructor
	 * @param {Object} config
	 */
	constructor : function(config) {
		config = config || {};
		
		if (!Ext.isDefined(config.model) && Ext.isDefined(config.context))
			config.model = config.context.getModel();

		if (!Ext.isDefined(config.store) && Ext.isDefined(config.model))
			config.store = config.model.getStore();
			
		config.store = Ext.StoreMgr.lookup(config.store);
		
		Ext.applyIf(config, {
			xtype : 'zarafa.filesfilegrid',
			ddGroup : 'dd.filesrecord',
			id : 'files-gridview',
			enableDragDrop: true,
			border : false,
			stateful : true,
			statefulRelativeDimensions : false,
			loadMask : this.initLoadMask(),
			viewConfig : this.initViewConfig(),
			sm : this.initSelectionModel(),
			cm : this.initColumnModel(),
			keys : {
				key : Ext.EventObject.DELETE,
				handler : this.onKeyDelete,
				scope : this
			}
		});
		Zarafa.plugins.files.ui.FilesFileGrid.superclass.constructor.call(this, config);
		
	},
	
	/**
	 * Initialize event handlers
	 * @private
	 */
	initEvents : function() {
		Zarafa.mail.ui.MailGrid.superclass.initEvents.call(this);

		this.mon(this, 'cellcontextmenu', this.onCellContextMenu, this);
		this.mon(this, 'rowbodycontextmenu', this.onRowBodyContextMenu, this);
		this.mon(this, 'rowdblclick', this.onRowDblClick, this);
		this.mon(this, 'afterrender', this.initDropTarget, this);
		
		// Add a buffer to the following 2 event handlers. These are influenced by Extjs when a record
		// is removed from the store. However removing of records isn't performed in batches. This means
		// that wee need to offload the event handlers attached to removing of records in case that
		// a large batch of records is being removed.
		this.mon(this.getSelectionModel(), 'beforerowselect', this.onBeforeRowSelect, this, { buffer : 1 });
		this.mon(this.getSelectionModel(), 'rowselect', this.onRowSelect, this, { buffer : 1 });
		this.mon(this.getSelectionModel(), 'selectionchange', this.onSelectionChange, this, { buffer : 1 });

		this.mon(this.context, 'viewmodechange', this.onContextViewModeChange, this);
		this.onContextViewModeChange(this.context, this.context.getCurrentViewMode());
	},

	/**
	 * Initialize the {@link Ext.grid.GridPanel.loadMask} field
	 *
	 * @return {Ext.LoadMask} The configuration object for {@link Ext.LoadMask}
	 * @private
	 */
	initLoadMask : function() {
		return {
			msg : dgettext('plugin_files', 'Loading files') + '...'
		};
	},

	/**
	 * Initialize the {@link Ext.grid.GridPanel#viewConfig} field
	 *
	 * @return {Ext.grid.GridView} The configuration object for {@link Ext.grid.GridView}
	 * @private
	 */
	initViewConfig : function() {
		return {
			// enableRowBody is used for enabling the rendering of
			// the second row in the compact view model. The actual
			// rendering is done in the function getRowClass.
			//
			// NOTE: Even though we default to the extended view,
			// enableRowBody must be enabled here. We disable it
			// later in onContextViewModeChange(). If we set false
			// here, and enable it later then the row body will never
			// be rendered. So disabling after initializing the data
			// with the rowBody works, but the opposite will not.
			enableRowBody : false,
			
			// We need a rowselector depth of 15 because of the nested
			// table in the rowBody.
			rowSelectorDepth : 15
		};
	},

	/**
	 * Initialize the {@link Ext.grid.GridPanel.sm SelectionModel} field
	 *
	 * @return {Ext.grid.RowSelectionModel} The subclass of {@link Ext.grid.AbstractSelectionModel}
	 * @private
	 */
	initSelectionModel : function() {
		return new Ext.grid.RowSelectionModel();
	},

	/**
	 * Initialize the {@link Ext.grid.GridPanel.cm ColumnModel} field.
	 *
	 * @return {Ext.grid.ColumnModel} The {@link Ext.grid.ColumnModel} for this grid
	 * @private
	 */
	initColumnModel : function() {
		return new Zarafa.plugins.files.ui.FilesFileGridColumnModel();
	},
	
	/**
	 * Initialize the {@link Ext.dd.DropTarget dropTarget}
	 *
	 * @return {Ext.grid.ColumnModel} The {@link Ext.dd.DropTarget dropTarget} for this grid
	 * @private
	 */
	initDropTarget : function () {
		var gridDropTargetEl = this.getView().el.dom.childNodes[0].childNodes[1];
		
		// init browser drag & drop events
		gridDropTargetEl.addEventListener("dragstart", function(e) {
			e.dataTransfer.effectAllowed="copy";
			e.preventDefault(); // Necessary. Allows us to drop.
			e.stopPropagation(); // stops the browser from redirecting.
		}, false);
		
		gridDropTargetEl.addEventListener("dragenter", function(e) {
			e.preventDefault(); // Necessary. Allows us to drop.
			e.stopPropagation(); // stops the browser from redirecting.
		}, false);
		
		gridDropTargetEl.addEventListener("dragover", function(e) {
			e.dataTransfer.dropEffect = "copy";
			e.preventDefault(); // Necessary. Allows us to drop.
			e.stopPropagation(); // stops the browser from redirecting.
		}, false);
		
		gridDropTargetEl.addEventListener("dragleave", function(e) {
			e.preventDefault(); // Necessary. Allows us to drop.
			e.stopPropagation(); // stops the browser from redirecting.
		}, false);
		
		gridDropTargetEl.addEventListener("drop", function(e) {
			e.preventDefault(); // Necessary. Allows us to drop.
			e.stopPropagation(); // stops the browser from redirecting.

			var dt = e.dataTransfer;
			var files = dt.files;

			Zarafa.plugins.files.data.Actions.uploadItem(files, Zarafa.plugins.files.data.ComponentBox.getStore());
			
			return false;
		}, false);
		
		// init internal drag & drop
		this.dropTarget = new Ext.dd.DropTarget(gridDropTargetEl, {
			ddGroup    : 'dd.filesrecord',
			copy       : false,
			gridStore  : this.getStore(),
			gridSM     : this.getSelectionModel(),
			notifyDrop : function(ddSource, e, data){
				var cellindex = ddSource.getDragData(e).rowIndex;
				
				if(Ext.isDefined(cellindex) && this.gridStore.getAt(cellindex).get('type') === Zarafa.plugins.files.data.FileTypes.FOLDER) {
					// Disable all selected records
					Ext.each(data.selections, function(record) {
						record.setDisabled(true);
					});
					
					return Zarafa.plugins.files.data.Actions.moveRecords(data.selections,this.gridStore.getAt(cellindex));
				} else 
					return false;
			},
			notifyOver : function(ddSource, e, data){
				var cellindex = ddSource.getDragData(e).rowIndex;
				
				if(Ext.isDefined(cellindex)) {
					// check if we are over a folder - if so, allow drop
					if(this.gridStore.getAt(cellindex).get('type') === Zarafa.plugins.files.data.FileTypes.FOLDER)
						 return this.dropAllowed;
				}
				return this.dropNotAllowed;
			},
			notifyEnter : function(ddSource, e, data){
				var cellindex = ddSource.getDragData(e).rowIndex;
				
				if(Ext.isDefined(cellindex)) {
					// check if we are over a folder - if so, allow drop
					if(this.gridStore.getAt(cellindex).get('type') === Zarafa.plugins.files.data.FileTypes.FOLDER)
						 return this.dropAllowed;
				}
				return this.dropNotAllowed;
			}
		});
		
		this.getView().dragZone.onBeforeDrag = function (data, e){
			return !data.grid.getStore().getAt(data.rowIndex).getDisabled();
		}
	},
	
	/**
	 * Event handler which is fired when the {@link Zarafa.core.Context} fires the
	 * {@link Zarafa.core.Context#viewmodechange viewmodechange} event. This will check
	 * where the preview panel is located, and if needed change the
	 * {@link Ext.grid.Column columns} inside the {@link Ext.grid.ColumnModel ColumnModel}
	 * of the {@link Zarafa.plugins.files.ui.FilesFileGrid FilesFileGrid}. Either use the extended (and more flexible)
	 * set or the more compact set.
	 *
	 * @param {Zarafa.core.Context} context The context which fired the event
	 * @param {Zarafa.plugins.files.data.ViewModes} newViewMode The new active mode
	 * @param {Zarafa.plugins.files.data.ViewModes} oldViewMode The previous mode
	 * @private
	 */
	onContextViewModeChange : function(context, newViewMode, oldViewMode) {
		var compact = newViewMode === Zarafa.plugins.files.data.ViewModes.RIGHT_PREVIEW;

		this.getColumnModel().setCompactView(compact);
	},
	
	/**
	 * Event handler which is triggered when the user opens the context menu.
	 *
	 * There are some selection rules regarding the context menu. If no rows where
	 * selected, the row on which the context menu was requested will be marked
	 * as selected. If there have been rows selected, but the context menu was
	 * requested on a different row, then the old selection is lost, and the new
	 * row will be selected. If the row on which the context menu was selected is
	 * part of the previously selected rows, then the context menu will be applied
	 * to all selected rows.
	 *
	 * @param {Zarafa.plugins.files.ui.FilesFile} grid The grid which was right clicked
	 * @param {Number} rowIndex The index number of the row which was right clicked
	 * @param {Number} cellIndex The index number of the column which was right clicked
	 * @param {Ext.EventObject} event The event structure
	 * @private
	 */
	onCellContextMenu : function(grid, rowIndex, cellIndex, event) {
		var sm = this.getSelectionModel();
		var cm = this.getColumnModel();

		if (sm.hasSelection()) {
			// Some records were selected...
			if (!sm.isSelected(rowIndex)) {
				// But none of them was the record on which the
				// context menu was invoked. Reset selection.
				sm.clearSelections();
				sm.selectRow(rowIndex);
			}
		} else {
			// No records were selected,
			// select row on which context menu was invoked
			sm.selectRow(rowIndex);
		}

		var column = {};
		// Take into account that the function onRowBodyContextMenu passes -1 as the column index.
		if(cellIndex >= 0)
			column = cm.getColumnById(cm.getColumnId(cellIndex));
			
		var records = sm.getSelections();
		
		var show = true;
		Ext.each(records, function (record) {
			if(record.getDisabled() === true) {
				show = false;
				return;
			}
		});

		if(show) {
			Zarafa.core.data.UIFactory.openDefaultContextMenu(records, { position : event.getXY(), context : this.context, grid : this });
		}
	},

	/**
	 * Event handler which is triggered when the user opems the context menu.
	 *
	 * This will call {@link onCellContextMenu} and pass -1 for the column index to prevent it 
	 * showing a special context menu if one would be set for specific columns.

	 *
	 * @param {Zarafa.plugins.files.ui.FilesFileGrid} grid The grid which was right clicked
	 * @param {Number} rowIndex The index number of the row which was right clicked
	 * @param {Ext.EventObject} event The event structure
	 * @private
	 */
	onRowBodyContextMenu : function(grid, rowIndex, event) {
		this.onCellContextMenu(grid, rowIndex, -1, event);
	},
	
	/**
	 * Event handler which is triggered when the user double-clicks on a particular item in the
	 * grid. This will update the store which 
	 * contains the selected item.
	 *
	 * @param {Grid} grid The Grid on which the user double-clicked
	 * @param {Number} rowIndex The Row number on which was double-clicked.
	 * @param {Ext.EventObject} e The event object
	 * @private
	 */
	onRowDblClick : function(grid, rowIndex, e) {
		var record = grid.store.getAt(rowIndex);
		var navpanel = Zarafa.plugins.files.data.ComponentBox.getNavigatorTreePanel();
		
		if(record.get('type') === Zarafa.plugins.files.data.FileTypes.FOLDER) {
			this.store.loadPath(record.get('id'));
			var node = navpanel.getNodeById(record.get('id'));
			
			if(Ext.isDefined(node) && !node.isLeaf()) {
				node.reload();
			}
		} else
			Zarafa.plugins.files.data.Actions.downloadItem([record]);
	},
	
	/**
	 * Event handler which is triggered when the user uses the delete button on a particular item in the
	 * grid. This will update the store which 
	 * contains the selected item.
	 *
	 * @param {Number} key The key code
	 * @param {Ext.EventObject} e The event object
	 * @private
	 */
	onKeyDelete : function(key, event) {
		var selections = this.getSelectionModel().getSelections();
		var allowDelete = true;
		
		if (!Ext.isEmpty(selections)) {
			Ext.each(selections, function(record) {
				if(record.get('id') === (container.getSettingsModel().get('zarafa/v1/contexts/files/files_path') + "/") || record.get('filename') === ".." || record.getDisabled() === true)
					allowDelete = false;
			}, this);
			
			var askOnDelete = container.getSettingsModel().get('zarafa/v1/contexts/files/ask_before_delete');
			
			if(allowDelete) {
				if(askOnDelete) {
					Ext.MessageBox.confirm('Confirm deletion', 'Are you sure?',  this.doDelete.createDelegate(this, [selections], true), this);
				} else {
					this.doDelete("yes", null, null, selections);
				}
			}
		}
	},
	
	/**
	 * Delete the selected files.
	 *
	 * @param {String} button The value of the button
	 * @param {String} text Unused
	 * @param {Object} options Unused
	 * @param {Array} records (@Zarafa.plugins.files.data.FilesRecord)
	 * @private
	 */
	doDelete : function (button, value, options, selections) {
		if(!Ext.isDefined(button) || button === 'yes') {
			Zarafa.common.Actions.deleteRecords(selections);
			Zarafa.plugins.files.data.Actions.refreshNavigatorTree();
		}
	},
	
	/**
	 * Event handler which is trigggerd before the user selects a row from the {@link Ext.grid.GridPanel}.
	 * This will updates the {@link Zarafa.files.FilesContextModel FilesContextModel} with the record which 
	 * was selected in the grid for preview
	 *
	 * @param {Ext.grid.RowSelectionModel} selectionModel The selection model used by the grid.
	 * @param {Integer} rowNumber The row number which is selected in the selection model
	 * @param {Boolean} False if other selections will be cleared
	 * @param {Ext.data.Record} record The record which is selected for preview.
	 * @private
	 */
	onBeforeRowSelect: function (sm, rowIndex, keepExisting, record) {
		return !record.getDisabled();
	},
	
	/**
	 * Event handler which is trigggerd when the user selects a row from the {@link Ext.grid.GridPanel}.
	 * This will updates the {@link Zarafa.files.FilesContextModel FilesContextModel} with the record which 
	 * was selected in the grid for preview
	 *
	 * @param {Ext.grid.RowSelectionModel} selectionModel The selection model used by the grid.
	 * @param {Integer} rowNumber The row number which is selected in the selection model
	 * @param {Ext.data.Record} record The record which is selected for preview.
	 * @private
	 */
	onRowSelect : function(selectionModel, rowNumber, record) {
		var viewMode = this.context.getCurrentViewMode();
		
		var count = selectionModel.getCount();

		if(viewMode != Zarafa.plugins.files.data.ViewModes.NO_PREVIEW) {
			if (count == 0)
				this.model.setPreviewRecord(undefined);
			else if (count == 1 && selectionModel.getSelected() === record) {
				if(record.get('id') !== (container.getSettingsModel().get('zarafa/v1/contexts/files/files_path') + "/") && record.get('filename') !== "..")
					this.model.setPreviewRecord(record);
				else
					this.model.setPreviewRecord(undefined);
			}
		}
	},
	
	/**
	 * Event handler which is triggered when the {@link Ext.grid.GridPanel grid}
	 * {@link Zarafa.core.data.IPMRecord record} selection is changed. This will inform
	 * the {@link Zarafa.files.FilesContextModel contextmodel} about the change.
	 *
	 * @param {Ext.grid.RowSelectionModel} selectionModel The selection model used by the grid.
	 * @private
	 */
	onSelectionChange : function(selectionModel) {
		var selections = selectionModel.getSelections();
		var viewMode = this.context.getCurrentViewMode();

		this.model.setSelectedRecords(selections);
		if(viewMode !== Zarafa.plugins.files.data.ViewModes.NO_PREVIEW) {
			if (Ext.isEmpty(selections))
				this.model.setPreviewRecord(undefined);
		}
	}
	
	// TODO: more eventhandlers...
});

Ext.reg('zarafa.filesfilegrid',Zarafa.plugins.files.ui.FilesFileGrid);
Ext.namespace('Zarafa.plugins.files.ui');

/**
 * @class Zarafa.plugins.files.ui.FilesIconView
 * @extends Zarafa.common.ui.DraggableDataView
 * @xtype zarafa.filesiconview
 */
Zarafa.plugins.files.ui.FilesIconView = Ext.extend(Zarafa.common.ui.DraggableDataView, {
	/**
	 * @cfg {Zarafa.plugins.files.context.FilesContext} context The context to which this panel belongs
	 */
	context : undefined,

	/**
	 * The {@link Zarafa.plugins.files.context.FilesContextModel} which is obtained from
	 * the {@link #context}.
	 *
	 * @property
	 * @type Zarafa.plugins.files.context.FilesContextModel
	 */
	model : undefined,
	
	/**
	 * The dropZone used by this grid if drop is enabled
	 * @property
	 */
	dropTarget : undefined,
	
	/**
	 * Keymap ({@link Ext.KeyMap})for handling keyboard events.
	 * @property
	 */
	keyMap : undefined,

	/**
	 * @constructor
	 * @param {object} configuration object
	 */
	constructor : function(config) {
		config = config || {};

		if (!Ext.isDefined(config.model) && Ext.isDefined(config.context)) {
			config.model = config.context.getModel();
		}
		if (!Ext.isDefined(config.store) && Ext.isDefined(config.model)) {
			config.store = config.model.getStore();
		}

		config.store = Ext.StoreMgr.lookup(config.store);

		config.plugins = Ext.value(config.plugins, []);
		config.plugins.push('zarafa.icondragselectorplugin');

		Ext.applyIf(config, {
			xtype		:'zarafa.filesiconview',
			//id : 'files-iconview',
			cls : 'zarafa-files-iconview',
			loadingText : dgettext('plugin_files', 'Loading files') + '...',
			deferEmptyText: false,
			autoScroll: true,
			emptyText	: '<div class="emptytext">' + _('There are no items to show in this view') + '</div>',
			overClass	:'zarafa-files-iconview-over',
			tpl			: this.initTemplate(),
			multiSelect	: true,
			selectedClass:'zarafa-files-iconview-selected',
			itemSelector:'div.zarafa-files-iconview-thumb',
			enableDragDrop: true,
			ddGroup : 'dd.filesrecord'
		});

		Zarafa.plugins.files.ui.FilesIconView.superclass.constructor.call(this, config);

		this.initEvents();
	},

	/*
	 * Initialize html template by setting file type icon and file name
	 * @private
	 */
	initTemplate : function() {
		return new Ext.XTemplate(
			'<div style="height: 100%; width: 100%; overflow: auto;">',
				'<tpl for=".">',
					'<div class="zarafa-files-iconview-container {.:this.getHidden}">',
						'<div class="zarafa-files-iconview-thumb {.:this.getTheme} {.:this.getHidden}">',
							'{.:this.getImage}',
						'</div>',
						'<span class="zarafa-files-iconview-subject">{filename:htmlEncode}</span>',
					'</div>',
				'</tpl>',
			'</div>',
			{
				/**
				 * @param {Object} the record data
				 * @return {String}
				 */
				getHidden : function(record) {
					if(record.filename === "..") {
						return "files_type_hidden";
					}
					
					return "";
				},
				
				/**
				 * @param {Object} the record data
				 * @return {String}
				 */
				getTheme : function(record) {
					
					switch (record.type) {
						case Zarafa.plugins.files.data.FileTypes.FOLDER:
							return Zarafa.plugins.files.data.Helper.File.getIconClass("folder");
							break;
						case Zarafa.plugins.files.data.FileTypes.FILE:
							return Zarafa.plugins.files.data.Helper.File.getIconClass(record.filename);
							break;
						default:
							return 'files48icon_blank';
							break;
					}
				},
				
				/**
				 * @param {Object} the record data
				 * @return {String}
				 */
				getImage : function(record) {
					var extension = Zarafa.plugins.files.data.Helper.File.getExtension(record.filename).toLowerCase();
					var imageExtension = ["jpg", "gif", "png", "bmp"];
					
					var cls = "";
					var src = "";
					var img = "";
					if(Ext.isEmpty(extension) || imageExtension.indexOf(extension) === -1) {
						cls = "files_type_hidden ";
					} else {
						var store = Zarafa.plugins.files.data.ComponentBox.getStore();
						var rec = store.getById(record.id);
						if(Ext.isDefined(rec)) {
							src = rec.getThumbnailImageUrl(40, 50);
						}
					}
					
					switch (record.type) {
						case Zarafa.plugins.files.data.FileTypes.FOLDER:
							cls = "files_image files_type_hidden";
							break;
						case Zarafa.plugins.files.data.FileTypes.FILE:
							cls = cls + "files_image";
							break;
						default:
							cls = 'files_image_hidden';
							break;
					}
					
					if(!Ext.isEmpty(src)) {
						img = '<img class="' + cls + '" src="' + src + '" />';
					}
					
					return img;
				}
			}
		);
	},

	/**
	 * Returns {@link Zarafa.note.ui.NoteMainPanel NoteMainPanel} object which instantiated all the views
	 * @return {Zarafa.note.ui.NoteMainPanel} note main panel
	 */
	getMainPanel : function() {
		return this.ownerCt;
	},

	/**
	 * initialize events for the grid panel
	 * @private
	 */
	initEvents : function() {
		this.on({
			'contextmenu': this.onFilesIconContextMenu,
			'dblclick': this.onIconDblClick,
			'selectionchange': this.onSelectionChange,
			'afterrender': this.onAfterRender,
			scope : this
		});
	},
	
	/**
	 * Called after this component was rendered
	 *
	 * @private
	 */
	onAfterRender : function () {
		// init keyboard functions
		this.keyMap = new Ext.KeyMap(this.getEl(),{                
            key: Ext.EventObject.DELETE,
            fn: this.onKeyDelete.createDelegate(this)
		});
	
		// init drop targets
		this.initDropTarget();
	},
	
	/**
	 * Event handler which is triggered when the user uses the delete button on a particular item in the
	 * grid. This will update the store which 
	 * contains the selected item.
	 *
	 * @param {Number} key The key code
	 * @param {Ext.EventObject} e The event object
	 * @private
	 */
	onKeyDelete : function(key, event) {
		var selections = this.getSelectedRecords();
		var allowDelete = true;
		
		if (!Ext.isEmpty(selections)) {
			Ext.each(selections, function(record) {
				if(record.get('id') === (container.getSettingsModel().get('zarafa/v1/contexts/files/files_path') + "/") || record.get('filename') === ".." || record.getDisabled() === true)
					allowDelete = false;
			}, this);
			
			var askOnDelete = container.getSettingsModel().get('zarafa/v1/contexts/files/ask_before_delete');
			
			if(allowDelete) {
				if(askOnDelete) {
					Ext.MessageBox.confirm('Confirm deletion', 'Are you sure?', this.doDelete.createDelegate(this, [selections], true), this);
				} else {
					this.doDelete("yes", null, null, selections);
				}
			}
		}
	},
	
	/**
	 * Delete the selected files.
	 *
	 * @param {String} button The value of the button
	 * @param {String} text Unused
	 * @param {Object} options Unused
	 * @param {Array} records (@Zarafa.plugins.files.data.FilesRecord)
	 * @private
	 */
	doDelete : function (button, value, options, selections) {
		if(!Ext.isDefined(button) || button === 'yes') {
			Zarafa.common.Actions.deleteRecords(selections);
			
			// refresh
			Zarafa.plugins.files.data.Actions.clearCache();
		}
	},
	
	/**
	 * Initialize the {@link Ext.dd.DropTarget dropTarget}
	 *
	 * @private
	 */
	initDropTarget : function () {
		var iconViewDropTargetEl = this.getEl();
		
		// init browser drag & drop events
		iconViewDropTargetEl.dom.addEventListener("dragstart", function(e) {
			e.dataTransfer.effectAllowed="copy";
			e.preventDefault(); // Necessary. Allows us to drop.
			e.stopPropagation(); // stops the browser from redirecting.
		}, false);
		
		iconViewDropTargetEl.dom.addEventListener("dragenter", function(e) {
			e.preventDefault(); // Necessary. Allows us to drop.
			e.stopPropagation(); // stops the browser from redirecting.
		}, false);
		
		iconViewDropTargetEl.dom.addEventListener("dragover", function(e) {
			e.dataTransfer.dropEffect = "copy";
			e.preventDefault(); // Necessary. Allows us to drop.
			e.stopPropagation(); // stops the browser from redirecting.
		}, false);
		
		iconViewDropTargetEl.dom.addEventListener("dragleave", function(e) {
			e.preventDefault(); // Necessary. Allows us to drop.
			e.stopPropagation(); // stops the browser from redirecting.
		}, false);
		
		iconViewDropTargetEl.dom.addEventListener("drop", function(e) {
			e.preventDefault(); // Necessary. Allows us to drop.
			e.stopPropagation(); // stops the browser from redirecting.

			var dt = e.dataTransfer;
			var files = dt.files;

			Zarafa.plugins.files.data.Actions.uploadItem(files, Zarafa.plugins.files.data.ComponentBox.getStore());
			
			return false;
		}, false);
		
		// init internal drag & drop
		this.dropTarget = new Ext.dd.DropTarget(iconViewDropTargetEl, {
			ddGroup    : 'dd.filesrecord',
			copy       : false,
			fileStore  : this.getStore(),
			notifyDrop : function(ddSource, e, data){
				var dragData = ddSource.getDragData(e);
				
				if(Ext.isDefined(dragData)) {
					var cellindex = dragData.index;
					if(Ext.isDefined(cellindex) && this.fileStore.getAt(cellindex).get('type') === Zarafa.plugins.files.data.FileTypes.FOLDER) {
						// Disable all selected records
						Ext.each(data.selections, function(record) {
							record.setDisabled(true);
						});
						
						return Zarafa.plugins.files.data.Actions.moveRecords(data.selections,this.fileStore.getAt(cellindex));
					}
				}
				
				return false;
			},
			notifyOver : function(ddSource, e, data){
				var dragData = ddSource.getDragData(e);
				
				if(Ext.isDefined(dragData)) {
					var cellindex = dragData.index;
					
					if(Ext.isDefined(cellindex)) {
						// check if we are over a folder - if so, allow drop
						if(this.fileStore.getAt(cellindex).get('type') === Zarafa.plugins.files.data.FileTypes.FOLDER)
							 return this.dropAllowed;
					}
				}
				return this.dropNotAllowed;
			},
			notifyEnter : function(ddSource, e, data){
				var dragData = ddSource.getDragData(e);
				
				if(Ext.isDefined(dragData)) {
					var cellindex = dragData.index;
				
					if(Ext.isDefined(cellindex)) {
						// check if we are over a folder - if so, allow drop
						if(this.fileStore.getAt(cellindex).get('type') === Zarafa.plugins.files.data.FileTypes.FOLDER)
							 return this.dropAllowed;
					}
				}
				return this.dropNotAllowed;
			}
		});
		
		this.dragZone.onBeforeDrag = function (data, e){
			return !this.view.getStore().getAt(data.index).getDisabled();
		}
	},

	/*
	 * Event handler which is triggered when user opens context menu
	 * @param {Ext.DataView} dataview dataview object
	 * @param {Number} rowIndex	index of row
	 * @param {node} target html node
	 * @param {Ext.event} eventObj eventObj object of the event
	 * @private
	 */
	onFilesIconContextMenu: function(dataview, index, node, eventObj) {
		// check row is already selected or not, if its not selected then select it first
		if (!dataview.isSelected(node)) {
			dataview.select(node);
		}
		
		var records = dataview.getSelectedRecords();
		
		var show = true;
		Ext.each(records, function (record) {
			if(record.getDisabled() === true) {
				show = false;
				return;
			}
		});

		if(show) {
			Zarafa.core.data.UIFactory.openDefaultContextMenu(records, { position : eventObj.getXY(), context : this.context });
		}
	},

	/**
	 * Display open dialog on mouse double click
	 * @param {object} dataview object
	 * @param {Number} integer index number of selected record
	 * @param {node} target html node
	 * @param {object} event object
	 * @private
	 */
	onIconDblClick:function(dataview,index,node,event) {
		var record = this.getStore().getAt(index);
		var navpanel = Zarafa.plugins.files.data.ComponentBox.getNavigatorTreePanel();
		
		if(record.get('type') === Zarafa.plugins.files.data.FileTypes.FOLDER) {
			this.store.loadPath(record.get('id'));
			var navnode = navpanel.getNodeById(record.get('id'));
			
			if(Ext.isDefined(navnode) && !navnode.isLeaf()) {
				navnode.reload();
			}
		} else
			Zarafa.plugins.files.data.Actions.downloadItem([record]);
	},

	/**
	 * Event handler which is triggered when the {@link Zarafa.plugins.files.ui.FilesIconView FilesIconView}
	 * {@link Zarafa.plugins.files.data.FilesRecord record} selection is changed. This will inform
	 * the {@link Zarafa.plugins.files.context.FilesContextModel contextmodel} about the change.
	 *
	 * @param {Zarafa.plugins.files.ui.FilesIconView} dataView The view object.
	 * @param {HTMLElement|Array} selection Array of selected nodes.
	 * @private
	 */
	onSelectionChange : function(dataView, selections) {
		this.model.setSelectedRecords(dataView.getSelectedRecords());
		
		var viewMode = this.context.getCurrentViewMode();
		
		var records = dataView.getSelectedRecords();
		var count = records.length;
		
		if(viewMode != Zarafa.plugins.files.data.ViewModes.NO_PREVIEW) {
			if (count != 1)
				this.model.setPreviewRecord(undefined);
			else if (count == 1) {
				if(records[0].get('id') !== (container.getSettingsModel().get('zarafa/v1/contexts/files/files_path') + "/") && records[0].get('filename') !== "..")
					this.model.setPreviewRecord(records[0]);
				else
					this.model.setPreviewRecord(undefined);
			}
		}
	}
});
//register xtype filesiconview
Ext.reg('zarafa.filesiconview', Zarafa.plugins.files.ui.FilesIconView);
Ext.namespace('Zarafa.plugins.files.ui');

/**
 * @class Zarafa.plugins.files.ui.FilesMainPanel
 * @extends Zarafa.common.ui.ContextMainPanel
 * @xtype zarafa.filesmainpanel
 *
 * this class will be containing all the views that will be created for filess folder
 * main panel for the files content context
 */
Zarafa.plugins.files.ui.FilesMainPanel = Ext.extend(Zarafa.common.ui.ContextMainPanel, {
	// Insertion points for this class
	/**
	 * @insert context.files.toolbar.item
	 * Insertion point for populating Files context's main toolbar.
	 * This item is only visible when this context is active.
	 * @param {Zarafa.plugins.files.ui.FilesMainPanel} panel This panel
	 */
	/**
	 * @insert context.files.toolbar.paging
	 *
	 * Insertion point for populating files context's toolbar with extra
	 * pagination buttons. This can be used to replace the default {@link Ext.PagingToolbar}
	 * with an alternative. Files that by default all paging toolbars will be visible, and
	 * hiding a particular toolbar is the responsibility of the new pagers.
	 * @param {Zarafa.plugins.files.ui.FilesMainPanel} panel This panel
	 */
	/**
	 * @insert context.files.views
	 * Insertion point for adding views within the main panel of files context.
	 * This insertion point should be used in combination with 'main.maintoolbar.view.files'
	 * insertion point, and also view should set its store in the config object, the reference of
	 * {@link Zarafa.plugins.files.FilesContextModel FilesContextModel} is passed as parameter of this
	 * insertion point.
	 * @param {Zarafa.plugins.files.ui.FilesMainPanel} mainpanel This mainpanel
	 * @param {Zarafa.plugins.files.FilesContext} context The context for this panel
	 */
	 
	/**
	 * The main panel in which the various views are located.
	 * @property
	 * @type Zarafa.core.ui.SwitchViewContentContainer
	 */
	viewPanel : undefined,
	
	/**
	 * @constructor
	 * @param filescontext
	 */
	constructor : function(config) {
		config = config || {};
		
		Ext.applyIf(config, {
			xtype : 'zarafa.filesmainpanel',
			layout : 'zarafa.switchborder',
			
			items : [
				this.initMainItems(config),
				this.initPreviewPanel(config.context)
			]
		});
		
		Zarafa.plugins.files.ui.FilesMainPanel.superclass.constructor.call(this,config);
	},
	
	/**
	 * Initializes the the views for the mainpanel
	 *
	 * @param {Object} config Configuration object
	 * @return {Ext.panel}
	 * @private
	 */
	initMainItems : function(config) {
		return {
			xtype: 'panel',
			ref: 'filesViewPanel',
			layout: 'zarafa.collapsible',
			cls : 'zarafa-context-mainpanel',
			minWidth : 200,
			minHeight: 200,
			region : 'center',
			collapsible : false,
			split : true,
			items: [{
				xtype: 'zarafa.switchviewcontentcontainer',
				ref: '../viewPanel',
				layout : 'card',
				lazyItems : this.initViews(config.context)
			}],			
			tbar : {
				xtype: 'zarafa.filestoolbar',
				defaultTitle : dgettext('plugin_files', 'Files'),
				height:33,
				context : config.context
			}
		};
	},
	
	/**
	 * Function will initialize all views associated with files context
	 * it will also get views added through 3rd party plugins and add it here
	 * @param {Zarafa.plugins.files.FilesContextModel} model data part of files context
	 * @return {Array} array of config objects of different views
	 * @private
	 */
	initViews : function(context) {
		// add the standard available views
		var allViews = [{
			xtype: 'zarafa.filesfilegrid',
			flex: 1,
			id : 'files-gridview',
			anchor: '100%',
			context : context
		}, {
			xtype: 'zarafa.filesiconview',
			flex: 1,
			id : 'files-iconview',
			anchor: '100%',
			context : context
		}];

		var additionalViewItems = container.populateInsertionPoint('context.files.views', this, context);
		allViews = allViews.concat(additionalViewItems);

		return allViews;
	},

	/**
	 * Initializes the {@link Zarafa.core.ui.PreviewPanel PreviewPanel}
	 *
	 * @param {Zarafa.mail.FilesContext} context The Files Context
	 * @return {Zarafa.core.ui.PreviewPanel}
	 * @private
	 */
	initPreviewPanel : function(context) {
		return {
			xtype: 'zarafa.filespreviewpanel',
			ref: 'filesPreview',
			region : 'south',
			split : true,
			context: context
		};
	},

	/**
	 * Function called by Extjs when the panel has been {@link #render rendered}.
	 * At this time all events can be registered.
	 * @private
	 */
	initEvents : function() {
		if (Ext.isDefined(this.context)) {
			this.mon(this.context, 'viewchange', this.onViewChange, this);
			this.mon(this.context, 'viewmodechange', this.onViewModeChange, this);

			this.onViewChange(this.context, this.context.getCurrentView());
			this.onViewModeChange(this.context, this.context.getCurrentViewMode());
		}
	},

	/**
	 * Event handler which is fired when the currently active view inside the {@link #context}
	 * has been updated. This will update the call
	 * {@link #viewPanel}#{@link Zarafa.core.ui.SwitchViewContentContainer#switchView}
	 * to make the requested view active.
	 *
	 * @param {Zarafa.core.Context} context The context which fired the event.
	 * @param {Zarafa.plugins.files.data.Views} newView The ID of the selected view.
	 * @param {Zarafa.plugins.files.data.Views} oldView The ID of the previously selected view.
	 */
	onViewChange : function(context, newView, oldView) {
		switch (newView) {
			case Zarafa.plugins.files.data.Views.LIST:
				this.viewPanel.switchView('files-gridview');
				break;
			case Zarafa.plugins.files.data.Views.ICON:
				this.viewPanel.switchView('files-iconview');
				break;
		}
	},

	/**
	 * Event handler which is fired when the {@link Zarafa.core.Context} fires the
	 * {@link Zarafa.core.Context#viewmodechange viewmodechange} event. This will
	 * convert the configured {@link Zarafa.plugins.files.data.ViewModes mode} to a
	 * {@link Zarafa.common.ui.layout.SwitchBorderLayout.Orientation orientation}
	 * to be {@link Zarafa.common.ui.layout.SwitchBorderLayout.setOrientation applied}
	 * to the {@link #layout}.
	 * @param {Zarafa.core.Context} context The context which fired the event
	 * @param {Zarafa.plugins.files.data.ViewModes} newViewMode The new active mode
	 * @param {Zarafa.plugins.files.data.ViewModes} oldViewMode The previous mode
	 * @private
	 */
	onViewModeChange : function(context, newViewMode, oldViewMode) {
		var orientation;

		switch (newViewMode) {
			case Zarafa.plugins.files.data.ViewModes.NO_PREVIEW:
				orientation = Zarafa.common.ui.layout.SwitchBorderLayout.Orientation.OFF;
				break;
			case Zarafa.plugins.files.data.ViewModes.RIGHT_PREVIEW:
				orientation = Zarafa.common.ui.layout.SwitchBorderLayout.Orientation.HORIZONTAL;
				break;
			case Zarafa.plugins.files.data.ViewModes.BOTTOM_PREVIEW:
				orientation = Zarafa.common.ui.layout.SwitchBorderLayout.Orientation.VERTICAL;
				break;
			case Zarafa.plugins.files.data.ViewModes.SEARCH:
				return;
		}

		// This function could be called when the layout has not yet
		// been instantiated. In that case we update the layoutConfig
		// so it will be automatically picked up by the layout when
		// it needs it.
		var layout = this.getLayout();
		if (!Ext.isFunction(layout.setOrientation)) {
			if (Ext.isString(layout))
				this.layoutConfig = Ext.apply(this.layoutConfig || {}, { orientation : orientation });
			else
				this.layout.orientation = orientation;
		} else
			layout.setOrientation(orientation);
	}
});
//register xtype of files main panel
Ext.reg('zarafa.filesmainpanel',Zarafa.plugins.files.ui.FilesMainPanel);
Ext.tree.TreeNodeUI.prototype.updateExpandIcon = Ext.tree.TreeNodeUI.prototype.updateExpandIcon.createSequence(function() {    
	/* This is called after the Ext.tree.TreeNodeUI.updateExpandIcon method has finished and adds  
		the following process to that method. 
		If we have flagged that this node is to remain a folder whether or not is has children, 
		and it has just been made into a leaf (as indicated by wasLeaf now being true), 
		then reverse what the updateExpandIcon method just did and turn it back into a closed (collapsed) folder. 
	*/ 
	
	if (this.node.attributes.isFolder && this.wasLeaf) { 
		this.removeClass("x-tree-node-leaf"); 
		this.addClass("x-tree-node-collapsed"); 
		this.c1 = "x-tree-node-expanded"; 
		this.c2 = "x-tree-node-collapsed"; 
		this.wasLeaf = false;     
	} 
});


Ext.tree.TreeNodeUI.prototype.ecClick = Ext.tree.TreeNodeUI.prototype.ecClick.createSequence(function (e) {
	/*  This is called after the Ext.tree.TreeNodeUI.ecClick method has finished and remove the
	 	icon class to show loading mask while user click on expand button.
	 */
	var node = this.node;
	if(node.ownerTree instanceof Zarafa.plugins.files.ui.NavigatorTreePanel){
		if(!node.isLoaded()) {
			var iconNode = Ext.get(this.iconNode);
			iconNode.removeClass('icon_folder_note');
		}
	}
});Ext.namespace('Zarafa.plugins.files.ui');

/**
 * @class Zarafa.plugins.files.ui.QuotaBar
 * @extends Ext.BoxComponent
 * @xtype zarafa.plugins.files.quotabar
 *
 * Quotabar shows information about user's store size,
 * and denotes warning-quota and hard-quota information.
 *
 */
Zarafa.plugins.files.ui.QuotaBar = Ext.extend(Ext.BoxComponent, {
	/**
	 * @cfg {number} storeSize
	 * Current store size.
	 */
	storeSize : undefined,
	
	/**
	 * @cfg {number} warnQuota
	 * Quota warning.
	 */
	warnQuota : undefined,
	
	/**
	 * @cfg {number} hardQuota
	 * Quota limit.
	 */
	hardQuota : undefined,

	/**
	 * @cfg {String} quotaTemplate
	 * Template for quota bar.
	 */
	quotaTemplate :'<div class="zarafa-quotabar">' +
						'<div class="zarafa-quotabar-normal"></div>' +
						'<div class="zarafa-quotabar-warn"></div>' +
						'<div class="zarafa-quotabar-hard"></div>' +
					'</div>',

	/**
	 * @constructor
	 * @param {Object} config Configuration object
	 */
	constructor : function(config)
	{
		config = config || {};

		Zarafa.plugins.files.ui.QuotaBar.superclass.constructor.call(this, config);

		this.quotaTemplate = new Ext.XTemplate(this.quotaTemplate, {
			compiled: true
		});

		this.on('afterrender', this.onQuotaBarRender, this);
	},

	/**
	 * Function will overwrites the quotaTemplate the content of el with the new node(s).
	 * @private
	 */
	onQuotaBarRender : function() {
		this.quotaTemplate.overwrite(Ext.get(this.el));
		this.updateQuotaBar();
	},
	
	/**
	 * Set store size.
	 *
	 * @param {Number} size
	 */
	setStoreSize : function (size) {
		this.storeSize = size;
	},
	
	/**
	 * Set warn quota.
	 *
	 * @param {Number} size
	 */
	setWarnQuota : function (size) {
		this.warnQuota = size;
	},
	
	/**
	 * Set hard quota.
	 *
	 * @param {Number} size
	 */
	setHardQuota : function (size) {
		this.hardQuota = size;
	},

	/**
	 * Function will count the quota size from the user store,
	 * and will update/show the quotabar accordingly.
	 * @private
	 */
	updateQuotaBar : function() {
		if(this.el && this.el.child('div.zarafa-quotabar')) {

			// If quota information is not set then return.
			if(!this.hardQuota) {
				return;
			}

			// calculate warn quota
			if(!this.warnQuota) {
				this.warnQuota = this.hardQuota - 100 * 1024; // Warnquota is 100MB below hard Quota.
			}
			
			var quota = [];
			if(this.warnQuota && (!this.hardQuota || this.warnQuota < this.hardQuota)) {
				quota.push({size : this.warnQuota, element : 'div.zarafa-quotabar-warn'});
			}
			
			if(this.hardQuota) {
				quota.push({size : this.hardQuota, element : 'div.zarafa-quotabar-hard'});
			}


			var maxLimit = this.hardQuota || this.warnQuota;

			if(this.storeSize > maxLimit) {
				// If store size has exceeded the hard_quota then set it as maxLimit
				maxLimit = this.storeSize;
				quota.push({size : this.storeSize});
			}

			// Count the factor by 'total width of qouta bar'/'max qouta limit'
			var maxAvailableWidth = this.el.child('div.zarafa-quotabar').getWidth(true);
			var factor = maxAvailableWidth/maxLimit;

			// Set blockSize
			var blockSize, totalSize = 0;
			var element = 'div.zarafa-quotabar-normal';
			for (var i = 0; i < quota.length ; i++)
			{
				blockSize = quota[i].size;
				if(this.storeSize <= blockSize) {
					blockSize = this.storeSize;
					this.storeSize = 0;
				}

				/*
				 * get absolute difference between qouta levels in blockSize
				 *
				 * |--------|                           first
				 * |-------------------|                second
				 * |------------------------------|     third
				 *
				 * absolute difference
				 * |--------|                           first
				 *          |----------|                second
				 *                     |----------|     third
				 */
				blockSize -= totalSize;
				totalSize += blockSize;

				if(element) {
					// Set width of the current block.
					var elementWidth = Math.round(blockSize*factor);
					elementWidth = Math.max(elementWidth, 0);

					/*
					 * Math.round sometime gives extra 1 pixel while setting width
					 * of the quotabar elements, because of the layouting is spoiled,
					 * so checked whether it doesn't exceed max limit.
					 */
					if(maxAvailableWidth < elementWidth) {
						elementWidth = maxAvailableWidth;
					}

					this.el.child(element).setWidth(elementWidth);
					maxAvailableWidth -= elementWidth;
				}

				/*
				 * Update element according to which quota is started in quotabar.
				 * This variable will maintain that which quota is till now displayed,
				 * e.g. we have set soft quota and hard quota only, then first it will
				 * draw noraml green block till soft-quota limit, then it will get
				 * element of soft quota i.e. orange element, then it will draw ornage
				 * element till hard-quota and now it reached hard quota so it will draw
				 * red element.
				 */
				element = quota[i].element;

				// set default size of every block to zero so that previous block size calculation is cleared.
				if (element) {
					this.el.child(element).setWidth(0);
				}
			}
		}
	}
});
Ext.reg('zarafa.plugins.files.quotabar', Zarafa.plugins.files.ui.QuotaBar);
Ext.namespace('Zarafa.plugins.files.context');

/**
 * @class Zarafa.plugins.files.context.FilesContextModel
 * @extends Zarafa.core.ContextModel
 * class will instantiate {@link Zarafa.plugins.files.FilesStore FilesStore} object
 */
Zarafa.plugins.files.context.FilesContextModel = Ext.extend(Zarafa.core.ContextModel, {
	/**
	 * @constructor
	 * @param {Object} config Configuration object
	 */
	constructor : function(config) {
		config = config || {};
		
		if(!Ext.isDefined(config.store))
			config.store = new Zarafa.plugins.files.data.FilesStore();
		
		Zarafa.plugins.files.context.FilesContextModel.superclass.constructor.call(this, config);
	},
	
	/**
	 * Create a new {@link Zarafa.core.data.IPMRecord IPMRecord}.
	 * @param {String} parentid id of the parent folder
	 * @return {Zarafa.core.data.IPMRecord} The new {@link Zarafa.core.data.IPMRecord IPMRecord}.
	 */
	createRecord : function(parentid) {
		parentid = parentid || "root";
		
		var record = Zarafa.core.data.RecordFactory.createRecordObjectByMessageClass('IPM.Files', {
			store_entryid: "files",
			parent_entryid: parentid
		});
		
		return record;
	},
	
	/**
	 * Update the current preview {@link Zarafa.core.data.IPMRecord}
	 * This will fire the event {@link #previewrecordchange}.
	 *
	 * @param {mixed} record The record which is set as preview or false to refresh the old record
	 * @param {Boolean} refresh (optinal) true to just refresh the old record
	 * in the {@link #lastPreviewedRecord}.
	 */
	setPreviewRecord : function(record, refresh) {
		if(container.getCurrentContext().getName() === "filescontext") { // otherwhise getContentPanel() will return the wrong panel the first time...
			var previewPanel = Zarafa.plugins.files.data.ComponentBox.getPreviewPanel();
			var panelConstructor;
			
			if(refresh && this.previewRecord) {
				// Just do a complete refresh, clearing all UI components
				// which might be active inside the panel.
				panelConstructor = container.getSharedComponent(Zarafa.core.data.SharedComponentType['common.preview'], this.previewRecord);
				
				previewPanel.removeAll();
				if (Ext.isDefined(panelConstructor)) {
					previewPanel.add(new panelConstructor());
					previewPanel.doLayout();
					previewPanel.fileinfo.update(this.previewRecord);
				}
				
			} else if (this.previewRecord !== record) {
				this.previewRecord = record;
				
				if (Ext.isDefined(record)) {
					panelConstructor = container.getSharedComponent(Zarafa.core.data.SharedComponentType['common.preview'], record);
					
					if (Ext.isDefined(panelConstructor) && previewPanel.fileinfo instanceof panelConstructor) {
						previewPanel.fileinfo.update(record); // panel exists... just update
					} else {
						// Do a complete refresh, clearing all UI components
						// which might be active inside the panel.
						previewPanel.removeAll();
						if (panelConstructor) {
							previewPanel.add(new panelConstructor());
							previewPanel.doLayout();
							previewPanel.fileinfo.update(record);
						}
					}
				}
			}
		}
	},
	
	/**
	 * Returns the default {@link Zarafa.hierarchy.data.MAPIFolderRecord folder} which is
	 * used within the current selection of folders. If this {@link Zarafa.core.ContextModel ContextModel} is not enabled
	 * then this function will return default folder of this context, and if not enabled then it will return
	 * currently selected folder in the ContextModel.
	 * @return {Zarafa.hierarchy.data.MAPIFolderRecord} The default folder
	 */
	getDefaultFolder : function() {
		var pseudoFolder;
		var icon_id = container.getSettingsModel().get('zarafa/v1/contexts/files/iconid');
		var name = container.getSettingsModel().get('zarafa/v1/plugins/files/button_name');
		
		// this is a workaround to get the initial name and icon loading of the context tab working
		// FIXME: this should really be improved!
		pseudoFolder = {
			get : function(item) {
				if(item == "icon_index") {
					return icon_id;
				} 
				return undefined;
			},
			
			getDisplayName : function () {
				return name + " - " + dgettext('plugin_files', 'Files');
			},
			
			getFullyQualifiedDisplayName : function () {
				return name + " - " + dgettext('plugin_files', 'Files');
			},
			
			getParentFolder : function () {
				return undefined;
			},
			
			set : function (item, value) {
			}
		};
		
		// ContextModel is not enabled so return default folder
		return pseudoFolder;
	}
});
Ext.namespace('Zarafa.plugins.files.context');

/**
 * @class Zarafa.plugins.files.FilesContext
 * @extends Zarafa.core.Context
 *
 * This class will be used as a controller between {@link Zarafa.plugins.files.FilesContextModel FilesContextModel}
 * and {@link Zarafa.plugins.files.ui.FilesMainPanel FilesMainPanel}
 * Context that handles displaying files type messages.
 */
Zarafa.plugins.files.context.FilesContext = Ext.extend(Zarafa.core.Context, {
	// Insertion points for this class
	/**
	 * @insert main.maintoolbar.view.files
	 * Insertion point for populating the main toolbar with a View button. This item is only visible
	 * when this context is active.
	 * @param {Zarafa.mail.FilesContext} context This context
	 */

	/**
	 * When searching, this property marks the {@link Zarafa.core.Context#getCurrentView view}
	 * which was used before {@link #onSearchStart searching started} the view was switched to
	 * {@link Zarafa.mail.data.Views#SEARCH}.
	 * @property
	 * @type Mixed
	 * @private
	 */
	oldView : undefined,

	/**
	 * When searching, this property marks the {@link Zarafa.core.Context#getCurrentViewMode viewmode}
	 * which was used before {@link #onSearchStart searching started} the viewmode was switched to
	 * {@link Zarafa.mail.data.ViewModes#SEARCH}.
	 * @property
	 * @type Mixed
	 * @private
	 */
	oldViewMode : undefined,
	 
	/**
	 * @constructor
	 * @param {Object} config configuration object
	 */
	constructor : function(config) {
		config = config || {};

		Ext.applyIf(config, {
			current_view : Zarafa.plugins.files.data.Views.LIST,
			current_view_mode : Zarafa.plugins.files.data.ViewModes.RIGHT_PREVIEW
		});
				
		// register module names...
		this.registerModules();

		// The tab in the top tabbar
		this.registerInsertionPoint('main.maintabbar.left', this.createMainTab, this);

		// The "New Files" button which is available in all contexts
		this.registerInsertionPoint('main.maintoolbar.new.item', this.createNewFilesButton, this);
		
		// Add buttons to the MainToolbar
		this.registerInsertionPoint('main.toolbar.actions.last', this.createMainToolbarButtons, this);
		
		// Add a tree control showing a list of files folders to the navigation panel.
		// The control will be shown when the user selects the files context from the button panel.
		this.registerInsertionPoint('navigation.center', this.createFilesNavigationPanel, this);
		
		// Extend the Contact and AddressBook context with email buttons
		this.registerInsertionPoint('context.addressbook.contextmenu.actions', this.createSendEmailContextItem, this);
		this.registerInsertionPoint('context.contact.contextmenu.actions', this.createSendEmailContextItem, this);
		this.registerInsertionPoint('context.contact.contactcontentpanel.toolbar.actions', this.createSendEmailButton, this);
		this.registerInsertionPoint('context.contact.distlistcontentpanel.toolbar.actions', this.createSendEmailButton, this);

		Zarafa.plugins.files.context.FilesContext.superclass.constructor.call(this, config);

		// add shared components
		Zarafa.core.data.SharedComponentType.addProperty('zarafa.plugins.files.uploadpanel');
		Zarafa.core.data.SharedComponentType.addProperty('zarafa.plugins.files.attachdialog');
		Zarafa.core.data.SharedComponentType.addProperty('zarafa.plugins.files.fileinfopanel');
	},

	/**
	 * Returns the context model
	 * @return {Zarafa.plugins.files.context.FilesContextModel} the files context model
	 */
	getModel : function() {
		if (!Ext.isDefined(this.model)) {
			this.model = new Zarafa.plugins.files.context.FilesContextModel();
		}
		return this.model;
	},

	/**
	 * Bid for the given {@link Zarafa.hierarchy.data.MAPIFolderRecord folder}
	 * This will bid on any folder of container class 'IPF.Note'.
	 *
	 * @param {Zarafa.hierarchy.data.MAPIFolderRecord} folder The folder for which the context is bidding
	 * @return {Number} 1 when the contexts supports the folder, -1 otherwise
	 */
	bid : function(folder) {
		// Bid 1 when the folder is of the IPF.Files type.
		if (folder.isContainerClass('IPF.Files', true))
			return 1;

		return -1;
	},

	/**
	 * Bid for the type of shared component and the given record.
	 * @param {Zarafa.core.data.SharedComponentType} type Type of component a context can bid for.
	 * @param {Ext.data.Record} record Optionally passed record.
	 * @return {Number} The bid for the shared component
	 */
	bidSharedComponent: function(type, record) {
		var bid = -1;

		if (Ext.isArray(record))
			record = record[0];
		
		switch (type) {
			case Zarafa.core.data.SharedComponentType['zarafa.plugins.files.uploadpanel']:
			case Zarafa.core.data.SharedComponentType['zarafa.plugins.files.attachdialog']:
			case Zarafa.core.data.SharedComponentType['zarafa.plugins.files.fileinfopanel']:
				bid = 1;
				break;
			case Zarafa.core.data.SharedComponentType['common.create']:
			case Zarafa.core.data.SharedComponentType['common.view']:
			case Zarafa.core.data.SharedComponentType['common.preview']:
				if (record instanceof Zarafa.core.data.IPMRecord && record.isMessageClass('IPM.Files', true))
					bid = 1;
				break;
			case Zarafa.core.data.SharedComponentType['common.contextmenu']:
				if (record instanceof Zarafa.core.data.IPMRecord && record.isMessageClass('IPM.Files', true))
					bid = 1;
				break;
			default : break;
		}
		return bid;
	},

	/**
	 * Will return the reference to the shared component.
	 * Based on the type of component requested a component is returned.
	 * @param {Zarafa.core.data.SharedComponentType} type Type of component a context can bid for.
	 * @param {Ext.data.Record} record Optionally passed record.
	 * @return {Ext.Component} Component
	 */
	getSharedComponent: function(type, record) {
		var component;
		switch (type) {
			case Zarafa.core.data.SharedComponentType['zarafa.plugins.files.uploadpanel']:
				component = Zarafa.plugins.files.ui.UploadPanel;
				break;
			case Zarafa.core.data.SharedComponentType['zarafa.plugins.files.attachdialog']:
				component = Zarafa.plugins.files.dialogs.AttachFromFilesContentPanel;
				break;
			case Zarafa.core.data.SharedComponentType['zarafa.plugins.files.fileinfopanel']:
				component = Zarafa.plugins.files.dialogs.ShowFilesFileContentPanel;
				break;
			case Zarafa.core.data.SharedComponentType['common.create']:
				component = Zarafa.plugins.files.dialogs.FilesUploadContentPanel;
				break;
			case Zarafa.core.data.SharedComponentType['common.view']:
				component = Zarafa.plugins.files.ui.FilesViewPanel;
				break;
			case Zarafa.core.data.SharedComponentType['common.preview']:
				component = Zarafa.plugins.files.ui.FilesViewPanel;
				break;
			case Zarafa.core.data.SharedComponentType['common.contextmenu']:
				component = Zarafa.plugins.files.ui.FilesFileGridContextMenu;
				break;
		}
		return component;
	},

	/**
	 * Creates the files tree that is shown when the user selects the files context from the
	 * button panel. It shows a tree of available files folders that can be checked and unchecked.
	 * @private
	 */
	createFilesNavigationPanel : function() {
		return {
			xtype : 'zarafa.contextnavigation',
			context : this,
			items : [{
				xtype : 'panel',
				cls: 'zarafa-context-navigation-block',
				title : container.getSettingsModel().get('zarafa/v1/plugins/files/button_name'),
				items : [{ 
					xtype: 'zarafa.filestreepanel',
					ref : '../../../filesTreepanel'
				}]
			}]
		};
	},

	/**
	 * creates a context panel
	 * @return configuration for files context
	 * @private
	 */
	createContentPanel: function() {
		return {
			xtype : 'zarafa.filesmainpanel',
			context : this
		};
	},

	/**
	 * Create "New File" {@link Ext.menu.MenuItem item} for the "New item"
	 * {@link Ext.menu.Menu menu} in the {@link Zarafa.core.ui.MainToolbar toolbar}.
	 * This button should be shown in all {@link Zarafa.core.Context contexts} and
	 * is used to create a new Sticky Files.
	 *
	 * @return {Object} The menu item for creating a new Sticky Files item
	 */
	createNewFilesButton: function() {
		return {
			xtype: 'menuitem',
			text: dgettext('plugin_files', 'Upload file'),
			iconCls: 'icon_files_category',
			newMenuIndex: 6,
			context: this.getName(),
			handler: function() {
				Zarafa.plugins.files.data.Actions.openCreateFilesContent(this.getModel());
			},
			scope: this
		};
	},

	/**
	 * Handler for the insertion points for extending the Contacts and AddressBook context menus
	 * with buttons to send a mail to the given Contact and Address Book.
	 * @private
	 */
	createSendEmailContextItem : function() {
		return {
			text : dgettext('plugin_files', 'Send file'),
			iconCls : 'icon_attachment',
			scope : this,
			handler : function(item) {
				Zarafa.plugins.files.data.Actions.openCreateMailContentForContacts(this.getModel(), item.parentMenu.records);
			},
			beforeShow : function(item, records) {
				var visible = false;

				for (var i = 0, len = records.length; i < len; i++) {
					var record = records[i];
					if (this.isSendEmailButtonVisible(record)) {
						visible = true;
						break;
					}
				}

				item.setVisible(visible);
			}
		};
	},

	/**
	 * Handler for the insertion points for extending the Contacts and Distribution Dialogs
	 * with buttons to send a mail to the given Contact or Distribution list.
	 * @private
	 */
	createSendEmailButton : function() {
		return {
			xtype : 'button',
			plugins : [ 'zarafa.recordcomponentupdaterplugin' ],
			iconCls : 'icon_attachment',
			overflowText : dgettext('plugin_files', 'Send file'),
			tooltip : {
				title : dgettext('plugin_files', 'Send file'),
				text : dgettext('plugin_files', 'Create a new email message with some files attached.')
			},
			handler : function(btn) {
				Zarafa.plugins.files.data.Actions.openCreateMailContentForContacts(this.getModel(), btn.record);
			},
			scope : this,
			update : function(record, resetContent) {
				this.record = record;
				if (resetContent) {
					// Small workaround, update is called from the btn scope,
					// but the handler from the Context scope. So access
					// isSendEmailButtonVisible from the scope.
					if (!this.scope.isSendEmailButtonVisible(record)) {
						this.hide();
					}
				}
			}
		}
	},
	
	/**
	 * Check if the given record (which represents a Contact or Distribution list
	 * can be mailed (this requires the record not to be a {@link Ext.data.Record#phantom}
	 * and the Contact should {@link Zarafa.contact.ContactRecord#hasEmailAddress have an email address}.
	 * @param {Zarafa.core.data.MAPIRecord} record The record to check
	 * @return {Boolean} True if we can send an email to this contact/distlist
	 * @private
	 */
	isSendEmailButtonVisible : function(record) {
		if (record.phantom) {
			return false;
		} else if (record.isMessageClass('IPM.Contact')) {
			if (!record.hasEmailAddress()) {
				return false;
			}
		}

		return true;
	},
	
	/**
	 * Returns the buttons for the dropdown list of the VIEW-button in the main toolbar. It will use the 
	 * main.maintoolbar.view.files insertion point to allow other plugins to add their items at the end.
	 * 
	 * @return {Ext.Component|Array} an array of components
	 */
	getMainToolbarViewButtons : function() {
		var items = container.populateInsertionPoint('main.maintoolbar.view.files', this) || [];
		
		var defaultItems = [{
			overflowText: dgettext('plugin_files', 'No preview'),
			iconCls: 'icon_previewpanel_off',
			text: dgettext('plugin_files', 'No preview'),
			valueViewMode : Zarafa.plugins.files.data.ViewModes.NO_PREVIEW,
			valueDataMode : Zarafa.plugins.files.data.DataModes.ALL,
			handler: this.onContextSelectView,
			scope: this
		},{
			overflowText: dgettext('plugin_files', 'Right preview'),
			iconCls: 'icon_previewpanel_right',
			text: dgettext('plugin_files', 'Right preview'),
			valueViewMode : Zarafa.plugins.files.data.ViewModes.RIGHT_PREVIEW,
			valueDataMode : Zarafa.plugins.files.data.DataModes.ALL,
			handler: this.onContextSelectView,
			scope: this
		},{
			overflowText: dgettext('plugin_files', 'Bottom preview'),
			iconCls: 'icon_previewpanel_bottom',
			text: dgettext('plugin_files', 'Bottom preview'),
			valueViewMode : Zarafa.plugins.files.data.ViewModes.BOTTOM_PREVIEW,
			valueDataMode : Zarafa.plugins.files.data.DataModes.ALL,
			handler: this.onContextSelectView,
			scope: this
		}];
		
		defaultItems.push();

		return defaultItems.concat(items);
	},
	
	/**
	 * Adds buttons to the maintoolbar like the view switcher button.
	 * @return {Array}
	 * @private
	 */
	createMainToolbarButtons: function() {
		return [{
			xtype : 'splitbutton',
			tooltip: dgettext('plugin_files', 'Switch view'),
			scale: 'large',
			iconCls: 'icon_viewswitch',
			handler: function () {
				this.showMenu();
			},
			listeners: {
				afterrender: this.onAfterRenderMainToolbarButtons,
				scope: this
			},
			menu: new Ext.menu.Menu({
				items: [{
					text : dgettext('plugin_files', 'List'),
					overflowText : dgettext('plugin_files', 'List'),
					tooltip : dgettext('plugin_files', 'List'),
					iconCls : 'icon_contact_list',
					valueView : Zarafa.plugins.files.data.Views.LIST,
					handler : this.onSwitchView,
					scope: this
				}, {
					text : dgettext('plugin_files', 'Icons'),
					overflowText : dgettext('plugin_files', 'Icons'),
					tooltip : dgettext('plugin_files', 'Icons'),
					iconCls : 'icon_note_icon_view',
					valueView : Zarafa.plugins.files.data.Views.ICON,
					handler : this.onSwitchView,
					scope: this
				}]
			})
		}]
	},
	
	/**
	 * Registers to the {@link Zarafa.core.Container#contextswitch contextswitch} event on the 
	 * {@link Zarafa.core.Container container} so the visiblity of the button can be toggled 
	 * whenever the context is switched. We do this after the button is rendered.
	 * @param {Ext.Button} btn The button
	 * @private
	 */
	onAfterRenderMainToolbarButtons: function(btn) {
		btn.mon(container, 'contextswitch', function(parameters, oldContext, newContext){
			this.setVisiblityMainToolbarButton(btn, newContext);
		}, this);

		btn.mon(this, 'viewchange', function(context, newView, oldView ){
			this.setVisiblityMainToolbarButton(btn, context);
		}, this);

		this.setVisiblityMainToolbarButton(btn);
	},

	/**
	 * Determines whether the passed button has to be shown or not based on what 
	 * {@link Zarafa.core.Context Context} is active. If no Context is supplied as an argument it 
	 * will get that from the {@link Zarafa.core.Container container}.
	 * @param {Ext.Button} btn The button
	 * @param {Zarafa.core.Context} activeContext (Optionial} The active Context
	 * @private
	 */
	setVisiblityMainToolbarButton: function(btn, activeContext) {
		activeContext = activeContext || container.getCurrentContext();
		if(activeContext === this){
			btn.show();
		}else{
			btn.hide();
		}
	},
	
	/**
	 * Event handler which is fired when one of the view buttons has been pressed.
	 * @param {Ext.Button} button The button which was pressed
	 * @private
	 */
	onSwitchView : function(button) {
		var viewMode = this.getCurrentViewMode();
		this.switchView(button.valueView, viewMode);
	},

	/**
	 * Event handler which is fired when one of the View buttons
	 * has been pressed. This will call {@link #setView setView}
	 * to update the view.
	 * @param {Ext.Button} button The button which was pressed
	 * @private
	 */
	onContextSelectView : function(button) {
		this.getModel().setDataMode(button.valueDataMode);
		
		var view = button.valueView;
		var viewMode = button.valueViewMode;
		
		if(!Ext.isDefined(button.valueView))
			view = this.getCurrentView();
		if(!Ext.isDefined(button.valueViewMode))
			viewMode = this.getCurrentViewMode();
		
		this.switchView(view, viewMode);
		
		// update the preview panel (redo layout)
		this.getModel().setPreviewRecord(undefined,true);
	},
	
	/**
	 * Adds a button to the top tab bar for this context.
	 * @return {Object} The button for the top tabbar 
	 * @private
	 */
	createMainTab: function() {
		return {
			text: this.getDisplayName(),
			tabOrderIndex: 7,
			context: this.getName()
		};
	},
	
	/**
	 * Registeres the php models for this context
	 * @private
	 */
	registerModules: function() {
		Zarafa.core.ModuleNames['IPM.FILES'] = {
			list : 'filesbrowsermodule',
			item : 'filesbrowsermodule'
		}
	}
});

/**
 * register the context
 */
Zarafa.onReady(function() {	
	if(Ext.isDefined(container.getSettingsModel().get('zarafa/v1/plugins/files/button_name'))) { // check if user store is initialised
		if(container.getSettingsModel().get('zarafa/v1/plugins/files/enable') === true && container.getSettingsModel().get('zarafa/v1/plugins/filescontext/enable') === true) { // make sure that the master plugin is enabled
			container.registerContext(new Zarafa.core.ContextMetaData({
				name : 'filescontext',
				displayName : container.getSettingsModel().get('zarafa/v1/plugins/files/button_name'),
				allowUserVisible : false,
				pluginConstructor : Zarafa.plugins.files.context.FilesContext
			}));
		}
	}
});
Ext.namespace('Zarafa.plugins.files');

/**
 * @class Zarafa.plugins.files.FilesPlugin
 * @extends Zarafa.core.Plugin
 * This cplugin is used to load the settings widget!
 */
Zarafa.plugins.files.FilesPlugin = Ext.extend(Zarafa.core.Plugin, {
	/**
	 * @constructor
	 * @param {Object} config
	 */
	constructor : function(config) {
		config = config || {};
		
		Zarafa.plugins.files.FilesPlugin.superclass.constructor.call(this, config);
	},

	/**
	 * initialises insertion point for plugin
	 * @protected
	 */
	initPlugin : function() {
		Zarafa.plugins.files.FilesPlugin.superclass.initPlugin.apply(this, arguments);
		
		// Initialise Version Manager
		Zarafa.plugins.files.data.Version.init();
		
		// Initialise dynamic server values
		Zarafa.plugins.files.data.Dynamics.init();
		
		// settingswidget
		// Register the Mail category for the settings
		this.registerInsertionPoint('context.settings.categories', this.createSettingCategories, this);
		// use zarafa user as default user
		if(container.getSettingsModel().get('zarafa/v1/contexts/files/username') == "defaultusername")
			container.getSettingsModel().set('zarafa/v1/contexts/files/username', container.getUser().getUserName());
			
		// some init for the context
		var files_icon = Zarafa.core.mapi.IconIndex.addProperty("files");
		container.getSettingsModel().set('zarafa/v1/contexts/files/iconid', files_icon);

		this.updateSesion();
	},
	
	/**
	 * Create the files {@link Zarafa.settings.ui.SettingsCategory Settings Category}
	 * to the {@link Zarafa.settings.SettingsContext}. This will create new
	 * {@link Zarafa.settings.ui.SettingsCategoryTab tabs} for the
	 * {@link Zarafa.plugins.files.settings.SettingsFilesCategory Files} and the 
	 * in the {@link Zarafa.settings.ui.SettingsCategoryWidgetPanel Widget Panel}.
	 * @return {Array} configuration object for the categories to register
	 * @private
	 */
	createSettingCategories: function() {
		return {
			xtype : 'Zarafa.plugins.files.settingsfilescategory'
		}
	},
	
	/**
	 * Update the php session variables
	 * Load them from settings
	 * @private
	 */
	updateSesion: function() {
		// also update the session to make sure we use the actual data
		container.getRequest().singleRequest(
			'filesmodule',
			'updatesession',
			{},
			null
		);
	}
});

/**
 * registers plugin
 */
Zarafa.onReady(function() {
	if(Ext.isDefined(container.getSettingsModel().get('zarafa/v1/plugins/files/button_name'))) { // check if user store is initialised
		container.registerPlugin(new Zarafa.core.PluginMetaData({
			name : 'files',
			displayName : String.format(dgettext('plugin_files', '{0} Plugin'), container.getSettingsModel().get('zarafa/v1/plugins/files/button_name')),
			about : Zarafa.plugins.files.ABOUT,
			allowUserDisable : true,
			pluginConstructor : Zarafa.plugins.files.FilesPlugin
		}));
	}
});
