Ext.namespace('Zarafa.common.ui');

/**
 * @class Zarafa.common.ui.BoxField
 * @extends Ext.form.ComboBox
 * @xtype zarafa.boxfield
 *
 * A special input field which displays all contents inside special {@link Zarafa.common.ui.Box}
 * components which are rendered inside this {@link #el}. This makes the user interface nicer,
 * and allows the user to perform extra actions on each box.
 *
 * The contents of the field is based on the contents of the {@link #boxStore} which contains
 * the {@link Ext.data.Record records} which must be rendered as {@link Zarafa.common.ui.Box box}.
 */
Zarafa.common.ui.BoxField = Ext.extend(Ext.form.ComboBox, {
	/**
	 * @cfg {String} boxType The xtype of the component which is used as box.
	 * This defaults to {@link Zarafa.common.ui.Box 'zarafa.box'}.
	 */
	boxType: 'zarafa.box',
	/**
	 * @cfg {Ext.data.Store} boxStore The store which contains all {@link Ext.data.Record records}
	 * which must be rendered as {@link Zarafa.common.ui.Box}. Before rendering, the contents
	 * will be filtered by {@link #filterRecords}.
	 */
	boxStore: undefined,
	/**
	 * @cfg {Object} boxConfig A configuration object which must be applied to all
	 * {@link Zarafa.common.ui.Box box} components which are rendered into this component
	 * by default.
	 */
	boxConfig: undefined,
	/**
	 * The collection of all {@link Zarafa.common.ui.Box Box} components which have been
	 * rendered inside the component.
	 * @property
	 * @type Ext.util.MixedCollection
	 */
	items: undefined,
	/**
	 * @cfg {Number|Char} handleInputKey The input key which must be pressed before the
	 * {@link #handleInput} function is being called. This is normally used to indicate
	 * that the current input is ready to be converted into {@link #items boxes}.
	 * This can be given as a charCode directly, or as a character,
	 * in which case it will be converted to the corresponding code using charCodeAt().
	 */
	handleInputKey: ';',
	/***
	 * @cfg {Boolean} enableComboBox True to enable all combobox functionality on this field.
	 * When this is true, all required fields from the {@link Ext.from.ComboBox Ext.form.ComboBox}
	 * must be configured.
	 */
	enableComboBox : true,
	/**
	 * The {@link Zarafa.common.ui.Box box} which currently has the userfocus.
	 * @property
	 * @type Zarafa.common.ui.Box
	 */
	currentFocus: false,
	/**
	 * A dummy 'a' element which is created as child of the {@link #wrap}. This element is
	 * not hidden, but instead has the dimensions 0x0, otherwise the browser is not able to
	 * put the focus on the element. By using this focus element, we can capture {@link #keyMap} events
	 * and control the different {@link #items boxes}.
	 * @property
	 * @type Ext.Element
	 */
	boxFocusEl : undefined,
	/**
	 * The 'ul' element which contains all rendered {@link #items} and the {@link #inputEl}.
	 * @property
	 * @type Ext.Element
	 */
	wrapBoxesEl : undefined,
	/**
	 * The 'li' element which has been wrapped around {@link #el}, and is to make sure the
	 * input element is positioned correctly within the list. This should always be the
	 * last element inside the {@link #wrapBoxesEl}.
	 * @property
	 * @type Ext.Element
	 */
	inputEl : undefined,
	/**
	 * The {@link Ext.KeyMap} which is used on the {@link #boxFocusEl} to add keyboard
	 * control over the current {@link #items box} selection. This will only be enabled
	 * when this field is {@link #editable editable}.
	 *
	 * @property
	 * @type Ext.KeyMap
	 */
	boxKeyMap : undefined,

	/**
	 * The {@link Ext.KeyMap} which is used on the {@link #el} to add keyboard
	 * control over the input field. This will only be enabled
	 * when this field is {@link #editable editable}.
	 * This KeyMap is currently only used for the handleInputKey,
	 * which causes the BoxField to evaluate its input and convert it to boxes.
	 * This is separated from {@link #specialInputKeyMap} because it needs reliable
	 * character code detection, which can only happen on a 'keypress' event.
	 *
	 * @property
	 * @type Ext.KeyMap
	 */
	inputKeyMap : undefined,

	/**
	 * The {@link Ext.KeyMap} which is used on the {@link #el} to add keyboard
	 * control over the input field. This will only be enabled
	 * when this field is {@link #editable editable}.
	 * This KeyMap is used only for special keys
	 * that do not insert characters (e.g. arrow keys, page up/down, enter, etc.).
	 * These keys are separated from {@link #inputKeyMap} because they have to be caught on
	 * a 'keydown' event.
	 *
	 * @property
	 * @type Ext.KeyMap
	 */
	specialInputKeyMap : undefined,

	/**
	 * The {@link Ext.KeyMap} which is used on the {@link #el} to add keyboard control
	 * for DELETE key. This will only be enabled when {@link #enableComboBox} is configured true.
	 *
	 * @property
	 * @type Ext.KeyMap
	 */
	listKeyMap : undefined,

	/**
	 * @cfg {Number} minInputFieldWidth The minimum number of pixels which must be available
	 * for the {@link #el input field}, to type in the text. The number of pixels should be
	 * sufficient to at least contain 1 character (in any characterset).
	 */
	minInputFieldWidth : 25,

	/**
	 * @cfg {Number} inputFieldHeight The default height for the {@link #el input field}.
	 */
	inputFieldHeight: 20,

	/**
	 * @cfg {Boolean} enableAnim Enable special {@link Ext.Fx FX} effects for
	 * this this field and all container {@link #items boxes}.
	 */
	enableAnim : true,

	/**
	 * @cfg {String} wrapCls The CSS classes which must be applied to the {@link #wrap} element.
	 */
	wrapCls : 'x-form-text x-zarafa-boxfield',

	/**
	 * Instance of the {@link Ext.util.TextMetrics TextMetrics} which is bound to the {@link #innerList}.
	 * This is used to calculate the desired width of text inside the {@link #innerList}. This field
	 * should only be obtained by the {@link #getListTextMetric} function.
	 * @property
	 * @type Ext.util.TextMetrics
	 */
	listTextMetric : undefined,

	/**
	 * Instance of the {@link Ext.util.TextMetrics TextMetrics} which is bound to the {@link #el}.
	 * This is used to calculate the desired width of text inside the {@link #el}. This field
	 * should only be obtained by the {@link #getInputTextMetric} function.
	 * @property
	 * @type Ext.util.TextMetrics
	 */
	inputTextMetric : undefined,

	/**
	 * @cfg {Boolean} listMode True to show all boxes in a list rather then side-by-side.
	 * When enabled, all boxes (and input field) will get the full width of the component.
	 */
	listMode : false,

	/**
	 * @cfg {Number} boxLimit If set, this number will limit the number of boxes which will
	 * be rendered into the field. It will also disable the {@link #inputEl} when the limit
	 * has been reached.
	 */
	boxLimit : undefined,

	/**
	 * @cfg {String}
	 * A simple CSS selector (e.g. div.some-class or span:first-child) that will be used to
	 * determine what extra nodes are required to be added into each of the dropdown-list item.
	 */
	extraItemSelector : undefined,

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

		if (config.readOnly === true) {
			config.editable = false;
		}

		Ext.applyIf(config, {
			// Override from Ext.Component
			xtype : 'zarafa.boxfield',
			cls : 'x-zarafa-boxfield-input',
			hideTrigger : true,

			autoHeight: true,
			autoScroll: true,
			
			/*
			 * Override value of Ext.form.TriggerField
			 * Because we don't want TAB-key to blur the element
			 */
			monitorTab: false
		});
		config.wrapCls = config.wrapCls ? config.wrapCls + ' '  + this.wrapCls : this.wrapCls;

		this.addEvents(
			/**
			 * @event boxfocus
			 * Fired when a box receives focus
			 * @param {Zarafa.common.ui.BoxField} boxField Parent of the box
			 * @param {Zarafa.common.ui.Box} box The box that has been focussed
			 * @param {Ext.data.Record} record The record that belongs to the box
			 */
			'boxfocus',
			/**
			 * @event boxblur
			 * Fired when a box looses focus
			 * @param {Zarafa.common.ui.BoxField} boxField Parent of the box
			 * @param {Zarafa.common.ui.Box} box The box that has been blurred
			 * @param {Ext.data.Record} record The record that belongs to the box
			 */
			'boxblur',
			/**
			 * @event boxclick
			 * Fires when the user clicked on a box
			 * @param {Zarafa.common.ui.BoxField} boxField Parent of the box
			 * @param {Zarafa.common.ui.Box} box The box that has been clicked
			 * @param {Ext.data.Record} record The record that belongs to the box
			 */
			'boxclick',
			/**
			 * @event boxdblclick
			 * Fires when the user doubleclicked on a box
			 * @param {Zarafa.common.ui.BoxField} boxField Parent of the box
			 * @param {Zarafa.common.ui.Box} box The box that has been doubleclicked
			 * @param {Ext.data.Record} record The record that belongs to the box
			 */
			'boxdblclick',
			/**
			 * @event boxcontextmenu
			 * Fires when the user requested the contextmenu for a box
			 * @param {Zarafa.common.ui.BoxField} boxField Parent of the box
			 * @param {Zarafa.common.ui.Box} box The box for which the contextmenu was requested
			 * @param {Ext.data.Record} record The record that belongs to the box
			 */
			'boxcontextmenu',
			/**
			 * @event boxadd
			 * Fires when a box has been added
			 * @param {Zarafa.common.ui.BoxField} boxField Parent of the to be added box
			 * @param {Zarafa.common.ui.Box} box The box that has been added
			 * @param {Ext.data.Record} record The record that belongs to the box
			 */
			'boxadd',
			/**
			 * @event boxremove
			 * Fires when a box will be removed.
			 * @param {Zarafa.common.ui.BoxField} boxField Parent of the to be removed box
			 * @param {Zarafa.common.ui.Box} box The box that will be removed
			 * @param {Ext.data.Record} record The record that belongs to the box
			 */
			'boxremove'
		);

		Zarafa.common.ui.BoxField.superclass.constructor.call(this, config);

		this.on('boxremove', this.onBoxRemove, this);
		this.on('boxadd', this.onBoxAdd, this);
	},

	/**
	 * Called by the superclass to initialize the component
	 * @private
	 */
	initComponent : function()
	{
		Zarafa.common.ui.BoxField.superclass.initComponent.call(this);
		this.items = new Ext.util.MixedCollection();

		// Convert input key to character code if necessary
		if (Ext.isString(this.handleInputKey)) {
			this.handleInputKey = this.handleInputKey.charCodeAt(0);
		}
		
		this.previousHeight = this.height;
	},

	/**
	 * Called by the superclass to initialize all events for this component.
	 * This is called on {@link #afterrender}.
	 * @private
	 */
	initEvents : function()
	{
		this.mon(this.el, {
			keydown : this.onKeyDownHandler,
			scope   : this
		});

		this.mon(this.getContentTarget(), 'click', this.onContainerClick, this);

		// Initialize keyboard control
		if (this.editable !== false) {
			this.boxKeyMap = this.createBoxKeyMap(this.boxFocusEl);
			this.specialInputKeyMap = this.createSpecialInputKeyMap(this.el);
			this.inputKeyMap = this.createInputKeyMap(this.el);

			// Initialize keyboard control for suggestion list, only
			// if {@link #enableComboBox} configured to true.
			if (this.enableComboBox === true) {
				this.listKeyMap = this.createListKeyMap(this.el);
			}

			/*
			 * Register the event handler for paste events. This will ensure
			 * the input element will be resized when pasting.
			 * Use the Zarafa.core.Event function to ensure compatibility
			 * with all browsers and support for drag & dropping text.
			 */
			Zarafa.core.Events.addPasteEventHandler(this, this.el, this.onPaste, this);
		}

		// Register event handler when listMode is enabled,
		// this will force the boxes to be resized when the parent
		// has been layed out.
		if (this.listMode === true) {
			this.mon(this.ownerCt, 'afterlayout', this.onParentLayout, this);
		}

		// Listen to select events in order to convert them to boxes.
		this.on('select', this.onSelect, this);

		Zarafa.common.ui.BoxField.superclass.initEvents.call(this);
	},

	/**
	 * Overridden to relay the value of {@link #extraItemSelector} to respective {@link Ext.DataView#extraItemSelector}
	 * and start listening to the {@link Ext.DataView#extraitemclick}, {@link Ext.DataView#mouseenter}
	 * and {@link Ext.DataView#mouseleave} event.
	 */
	initList : function()
	{
		Zarafa.common.ui.BoxField.superclass.initList.call(this);

		if(Ext.isDefined(this.extraItemSelector)) {
			this.view.extraItemSelector = this.extraItemSelector;

			this.view.on('extraitemclick', this.onExtraItemClick, this);
		}
	},

	/**
	 * Sets a new {@link boxStore boxStore}. It will first unregister all events from the old one.
	 * Then the new store will be set, the recipient field will be refreshed and after that the
	 * event listeners will be registered again.
	 * @param {Ext.data.Store} boxStore The store that will be applied to this field.
	 * @param {Boolean} initial True if this function is called from the constructor.
	 */
	setBoxStore: function(boxStore, initial)
	{
		if (this.boxStore === boxStore && initial !== true) {
			return;
		}

		if (this.boxStore) {
			this.mun(this.boxStore, {
				'datachanged': this.onBoxStoreDataChanged,
				'add': this.onBoxStoreAdd,
				'remove': this.onBoxStoreRemove,
				'update': this.onBoxStoreUpdate,
				'clear': this.onBoxStoreClear,
				scope: this
			});
			this.clearBoxes();
		}

		this.boxStore = Ext.StoreMgr.lookup(boxStore);

		if (this.boxStore) {
			this.loadBoxes(this.boxStore);
			this.mon(this.boxStore, {
				'datachanged': this.onBoxStoreDataChanged,
				'add': this.onBoxStoreAdd,
				'remove': this.onBoxStoreRemove,
				'update': this.onBoxStoreUpdate,
				'clear': this.onBoxStoreClear,
				scope: this
			});
		}
	},

	/**
	 * Returns the {@link boxStore boxStore}.
	 * @return {Ext.data.Store} The set {@link boxStore boxStore}.
	 */
	getBoxStore: function()
	{
		return this.boxStore;
	},

	/**
	 * Obtain (and create if required) the {@link #listTextMetric} instance.
	 * @return {Ext.util.TextMetrics} The textmetrics for {@link #innerList}.
	 * @private
	 */
	getListTextMetric : function()
	{
		if (!this.listTextMetric) {
			this.listTextMetric = Ext.util.TextMetrics.createInstance(this.innerList);
		}

		return this.listTextMetric;
	},

	/**
	 * Obtain (and create if required) the {@link #listTextMetric} instance.
	 * @return {Ext.util.TextMetrics} The textmetrics for {@link #el}.
	 * @private
	 */
	getInputTextMetric : function()
	{
		if (!this.inputTextMetric) {
			this.inputTextMetric = Ext.util.TextMetrics.createInstance(this.el);
		}

		return this.inputTextMetric;
	},

	/**
	 * The function that should handle the trigger's click event.
	 *
	 * This method is disabled if {@link #enableComboBox} is set to false.
	 *
	 * @param {EventObject} e
	 * @private
	 */
	onTriggerClick : function()
	{
		if (this.enableComboBox === true) {
			Zarafa.common.ui.BoxField.superclass.onTriggerClick.apply(this, arguments);
		}
	},

	/**
	 * Execute a query to filter the dropdown list.  Fires the {@link #beforequery} event prior to performing the
	 * query allowing the query action to be canceled if needed.
	 *
	 * This method is disabled if {@link #enableComboBox} is set to false.
	 *
	 * @param {String} query The SQL query to execute
	 * @param {Boolean} forceAll <tt>true</tt> to force the query to execute even if there are currently fewer
	 * characters in the field than the minimum specified by the <tt>{@link #minChars}</tt> config option.  It
	 * also clears any filter previously saved in the current store (defaults to <tt>false</tt>)
	 * @private
	 */
	doQuery : function()
	{
		if (this.enableComboBox === true) {
			Zarafa.common.ui.BoxField.superclass.doQuery.apply(this, arguments);
		}
	},

	/**
	 * Check if the value typed into the field matches a record from the store.
	 *
	 * This method is disabled if {@link #enableComboBox} is set to false.
	 *
	 * @private
	 */
	assertValue : function()
	{
		if (this.enableComboBox === true) {
			Zarafa.common.ui.BoxField.superclass.assertValue.apply(this, arguments);
		}
	},

	/**
	 * Event handler which is called when any key related to navigation (arrows, tab, enter, esc,
	 * etc.) is pressed.
	 * @param {Ext.data.Record} record
	 * @private
	 */
	onSelect: function(record)
	{
		this.hideSuggestionList();
		this.handleSelection(record);
		this.lastQuery = '';
	},

	/**
	 * Function which is use to hide suggestion list and
	 * It will also remove all records from suggestion list store.
	 */
	hideSuggestionList: function ()
	{
		if (this.isExpanded()) {
			this.collapse();
			this.el.dom.value = '';
			this.sizeInputfield();
			this.store.removeAll(true);
		}
	},

	/**
	 * Calculate the desired width of the dropdown {@link #list}.
	 * This should only be called when {@link #list} has been filled with the
	 * data which is going to be shown, as we calculate the desired width
	 * based on the current contents of the {@link #list}.
	 *
	 * This means that if a subclass overrides {@link #tpl} and adds all sort
	 * of extra text, this function should still be relatively accurate in the
	 * required width.
	 *
	 * @private
	 */
	getDesiredListWidth : function()
	{
		var metric = this.getListTextMetric();
		var desiredWidth = 0;

		if (this.innerList.dom.children.length > 0) {
			for (var i = 0, len = this.innerList.dom.children.length; i < len; i++) {
				var child = Ext.fly(this.innerList.dom.children[i]);
				var width = child.getPadding('lr') + metric.getWidth(child.dom.innerHTML);

				if (width > desiredWidth) {
					desiredWidth = width;
				}
			}
		} else {
			desiredWidth = metric.getWidth(this.innerList.dom.innerHTML);
		}

		return desiredWidth;
	},

	/**
	 * Called just before the {@link #store} is going to call 'list' to the server.
	 * This will show a {@link #loadingText} in the {@link #list.
	 *
	 * We make sure that we resize our {@link #list} here using {@link #getDesiredListWidth}
	 * to guarentee that our {@link #loadingText} and loading image receive sufficient
	 * space.
	 *
	 * @private
	 */
	onBeforeLoad : function()
	{
		Zarafa.common.ui.BoxField.superclass.onBeforeLoad.apply(this, arguments);

		var width = this.getDesiredListWidth();
		this.restrictWidth(width);
	},

	/**
	 * Called when the {@link #store} has loaded and we can fill the dropdown list
	 * with the suggestionlist. Based on the records in the store we will also
	 * determine the {@link #getDesiredListWidth} desired width of the list.
	 *
	 * Note that this has been called after the dropdown box has been filled with
	 * the contents. Hence it is safe to call {@link #getDesiredListWidth} here.
	 *
	 * @param {Ext.data.Store} store The store which fired the event
	 * @param {Ext.data.Record[]} records The records which were loaded from the server
	 * @param {Object} options The options object which were provided during load
	 * @private
	 */
	onLoad : function(store, records, options)
	{
		if (this.hasFocus && (this.store.getCount() > 0 || this.listEmptyText)) {
			var desiredWidth = this.getDesiredListWidth();

			// getDesiredListWidth obtains the desired width for
			// the 'innerList'. The 'list' however is slightly larger.
			desiredWidth += this.list.getFrameWidth('lr');

			// When there are sufficient results, a scrollbar is shown.
			// Add the required space.
			desiredWidth += Ext.getScrollBarWidth();

			// Resize the dropdownbox.
			this.restrictWidth(desiredWidth);
		}

		Zarafa.common.ui.BoxField.superclass.onLoad.apply(this, arguments);
	},

	/**
	 * Change the width of the {@link #list} and {@link #innerList}. We never
	 * fill out the dropdown list to the complete width of the field, and the
	 * list itself is aligned to the {@link #el} element (which can be positioned
	 * on various locations in the field depending on the number of {@link #items boxes}
	 * which have been rendered.
	 *
	 * The width must fall within the the {@link #minListWidth} and the {@link #container}
	 * width range. Depending on the width, and the position of the input element, we
	 * also have to force the list a few pixels to the left of the {@link #el} if by
	 * that we can prevent the list to exceed the limits of the field itself.
	 *
	 * @param {Number} width The desired width of the list
	 * @private
	 */
	restrictWidth : function(width)
	{
		var target = this.getEl();
		var container = this.getResizeEl();

		var offset = target.getOffsetsTo(container);
		var fieldWidth = container.getWidth();

		var desiredOffsetLeft = 0;
		var desiredOffsetBottom = target.getFrameWidth('b');
		var desiredWidth = width;

		// Establish the actual width we can apply for this list.
		if (this.minListWidth > desiredWidth) {
			desiredWidth = this.minListWidth;
		} else if (fieldWidth < desiredWidth) {
			// Don't restrict width of suggestion-list in case of zarafa.userlistbox
			// because container is smaller then the width of content of suggestion list.
			// And we don't want the ellipsis.
			if (this.boxType !== "zarafa.userlistbox"){
				desiredWidth = fieldWidth;
			}
		}

		// We now have the width we need. Since we are going to align
		// the list to the input field, we must check the available width,
		// from the start of the input field to the end of the box field.
		var availableWidth = container.getWidth() - offset[0];
		if (availableWidth < desiredWidth) {
			// Don't adjust left-offset of suggestion-list in case of zarafa.userlistbox.
			// it will result into negative value because container is smaller then
			// the desired-width.
			if (this.boxType !== "zarafa.userlistbox") {
				desiredOffsetLeft = availableWidth - desiredWidth;
			}
		}

		// But what if so much size was needed, that the offset would cause
		// the dropdown box to appear to the left of the boxfield...
		// Lets limit that case as well, and make sure we decrease the
		// width.
		if (desiredOffsetLeft > offset[0]) {
			desiredWidth -= desiredOffsetLeft - offset[0];
			desiredOffsetLeft = -offset[0];
		}

		this.list.setWidth(desiredWidth);
		this.innerList.setWidth(desiredWidth - this.list.getFrameWidth('lr'));
		this.listAlign = [ 'tl-bl', [ desiredOffsetLeft, desiredOffsetBottom ] ];
	},

	/**
	 * Function called during the {@link #render rendering} of this component. This will
	 * wrap {@link #el} into a 'li' element which is saved as {@link #inputEl}. This element
	 * will then be wrapped into a 'ul' element which is saved as {@link #wrapBoxesEl}, and
	 * will later contain all {@link #items} as well.
	 * @param {Ext.Container} ct The container in which the component is being rendered.
	 * @param {NUmber} position The position within the container where the component will be rendered.
	 * @private
	 */
	onRender : function(ct, position)
	{
		Zarafa.common.ui.BoxField.superclass.onRender.call(this, ct, position);

		// Apply some extra CSS classes to the wrap element.
		if (!Ext.isEmpty(this.wrapCls)) {
			this.wrap.addClass(this.wrapCls);
		}

		// If autoHeight is set to false we need to set our own height. Otherwise the CSS
		// class x-form-text will set it to a default height.
		if(this.autoHeight === false){
			if(Ext.isDefined(this.height)) {
				this.wrap.setHeight(this.height);
			}
		}else{
			 this.wrap.applyStyles('height: auto;');
		}

		// Create a focus element which is used for focussing a box.
		this.boxFocusEl = this.wrap.createChild({
			tag : 'a',
			href : '#',
			// Disable tab-index, and position it somewhere where it cannot be seen
			// by the user. This will make the element completely invisible for the
			// user while we can benefit from the focus capabilities.
			tabindex: -1,
			style: 'position: absolute; left:-10000px; top:-10000px;'
		});

		// Wraps the items (boxes) in an UL-tag
		this.wrapBoxesEl = this.el.wrap({
			tag: 'ul'
		});

		this.inputEl = this.el.wrap({
			tag: 'li',
			cls: 'x-zarafa-boxfield-input-item'
		});

		if (this.border === false) {
			this.el.addClass('x-zarafa-boxfield-input-noborder');
		}

		// If a boxStore was previously configured, we
		// can now set it (this will cause the boxes to
		// be rendered).
		if (Ext.isDefined(this.boxStore)) {
			this.setBoxStore(this.boxStore, true);
		}
	},

	/**
	 * Callback function from {@link #setEditable} when the {@link #editable} state
	 * has been changed. This will go over all {@link #items} and change the
	 * {@link Zarafa.common.ui.Box#editable} state on there.
	 * @private
	 */
	updateEditState : function()
	{
		Zarafa.common.ui.BoxField.superclass.updateEditState.apply(this, arguments);

		this.inputEl.setVisible(this.editable);
		this.items.each(function(box) {
			box.setEditable(this.editable);
		});
	},

	/**
	 * Return the {@link Ext.Element} which acts as as the content element. Normally
	 * this is {@link #el}, but as this combobox is more a container, we return {@link #wrap}.
	 *
	 * @return {Ext.Element} The content element
	 * @private
	 */
	getContentTarget : function()
	{
		return this.wrap;
	},

	/**
	 * Called after the component is resized. This will automatically update
	 * the sizing of the {@link #sizeInputfield input} and {@link #sizeContainer container}.
	 *
	 * @param {Number} adjWidth The box-adjusted width that was set
	 * @param {Number} adjHeight The box-adjusted height that was set
	 * @param {Number} rawWidth The width that was originally specified
	 * @param {Number} rawHeight The height that was originally specified
	 * @private
	 */
	onResize: function(w, h, rw, rh)
	{
		Zarafa.common.ui.BoxField.superclass.onResize.call(this, w, h, rw, rh);

		this.sizeInputfield();
		this.sizeContainer();
	},

	/**
	 * Apply auto-sizing to the component. When {@link #autoHeight} is true,
	 * we apply automatic height calculations to make sure the component
	 * is always correctly sized. When {@link #boxMaxHeight} is also provided,
	 * we check if the limit has been exceeded and display the
	 * {@link #setAutoScroll scrollbar} if needed.
	 *
	 * @private
	 */
	sizeContainer : function()
	{
		if (!this.rendered || this.autoHeight === false) {
			return false;
		}

		var target = this.getResizeEl();
		if ( !Ext.isDefined(target) || !Ext.isDefined(target.dom) ){
			// The element has been removed already. This is possible
			// if a box was removed with animation at the same time that
			// this element was removed. (See Zarafa.common.ui.Box.doDestroy())
			return;
		}
		
		var outerHeight = target.getHeight();
		var innerHeight = target.dom.scrollHeight;
		var doLayout = false;

		if ( this.previousOuterHeight !== outerHeight ) {
			doLayout = true;
		}
		
		if (outerHeight > this.boxMaxHeight) {
			// The height of the box exceeds the maximim height,
			// enable the scrollbar and scroll to the bottom.
			target.setHeight(this.boxMaxHeight);
			if (this.initialConfig.autoScroll !== false) {
				this.setAutoScroll(true);
				target.scrollTo('top', outerHeight);
			}
			doLayout = true;
		} else if ( outerHeight === this.boxMaxHeight && innerHeight !== this.previousInnerHeight && innerHeight <= outerHeight -2 ) { // subtract 2 for the border
			// The scroll height is smaller then the height of the
			// box, this means we do not need the scrollbar anymore.
			target.setHeight('auto');
			if (this.initialConfig.autoScroll !== false) {
				this.setAutoScroll(false);
			}
			doLayout = true;
		}

		this.previousOuterHeight = outerHeight;
		this.previousInnerHeight = innerHeight;

		// Fire a resizeheight event so parent components can listen to it and
		// do a layout if they want to
		if (doLayout === true ) {
			this.fireEvent('resizeheight');
		}
	},

	/**
	 * Called when the {@link #ownerCt owner} has been layed out, this
	 * will obtain the new desired {@link #getDesiredBoxWidth boxWidth}
	 * and applies them to all available {@link #items boxes}.
	 * @private
	 */
	onParentLayout : function()
	{
		var width = this.getDesiredBoxWidth();
		if (Ext.isDefined(width)) {
			this.items.each(function(box) { box.setWidth(width); });
		}
	},

	/**
	 * Returns the desired width for the {@link #items boxes} which should be applied
	 * whenever the container resizes, or a new box is created. When {@link #listMode}
	 * is disabled, this function returns undefined, to ensure dynamic sizing of the box.
	 * @return {Number} The desired width for all boxes
	 * @private
	 */
	getDesiredBoxWidth : function()
	{
		if (this.listMode === true) {
			var target = this.getResizeEl();
			return target.getWidth() - target.getFrameWidth('lr') - this.el.getFrameWidth('lr');
		} else {
			return undefined;
		}
	},

	/**
	 * Apply auto-sizing to the {@link #el input element}.
	 * Whenever the contents of the input field has changed, or when
	 * the width of the entire component has changed, we must recalculate
	 * the desired width of the input element. Normally it should be only
	 * a few pixels wider then the typed text requires, with a maximum
	 * of the current width of the entire component (to prevent a
	 * horizontal scrollbar to appear while typing).
	 *
	 * @private
	 */
	sizeInputfield: function()
	{
		if (!this.rendered) {
			return false;
		}

		var target = this.getResizeEl();
		var width;

		if (this.listMode === true) {
			width = target.getWidth() - target.getFrameWidth('lr') - this.el.getFrameWidth('lr');
		} else {
			var metric = this.getInputTextMetric();

			// Calculate the desired width of the component based on the
			// required width for the input text.
			var value = Ext.util.Format.htmlEncode(this.el.dom.value);
			width = metric.getWidth(value);

			// Add spacing to the input field. This will ensure the
			// the input box will always have the correct minimum size.
			width += this.minInputFieldWidth;

			// Ensure the width does not exceed the component width.
			width = Math.min(width, target.getWidth());
		}

		// Store the current height, this way we can detect if the input
		// field has been wrapped to the next line after the resize.
		var oldHeight = target.getHeight();

		// Set the inputfield to the calculated width
		this.el.setSize(width, this.inputFieldHeight - this.el.getBorderWidth('tb'));

		// Check if linewrapping has occurred, and update the container accordingly.
		var newHeight = target.getHeight();
		if (this.listMode === true || oldHeight !== newHeight) {
			this.sizeContainer();
		}

		// When scrolling is enabled, we must always scroll to the
		// bottom of the container to ensure the input field is
		// fully visible.
		target.scrollTo('top', newHeight);
	},

	/**
	 * Called to handle the input when the user presses the handleInputKey or another trigger makes
	 * this component need to handle the input. Has to be overwritten to implement the desired
	 * behavior and the creation of the correct type of record.
	 * @param {String} value The value from the input field
	 * @protected
	 */
	handleInput : Ext.emptyFn,

	/**
	 * Called to handle a selection from the dropdown list. This function needs to
	 * convert the selected record into a record for the {@link #boxStore}.
	 * Has to be overwritten to implement the desired behavior of creation of the correct type
	 * of record.
	 * @param {Ext.data.Record} record The record which was selected from {@link #store}
	 * @protected
	 */
	handleSelection : Ext.emptyFn,

	/**
	 * Check {@link #el} for input and call {@link #handleInput} to convert
	 * the input into a new {@link Zarafa.common.ui.Box Box}.
	 * @private
	 */
	convertInputToBox : function()
	{
		var value = this.el.getValue();

		if (!Ext.isEmpty(value)) {
			this.el.dom.value = '';
			this.sizeInputfield();
			this.store.removeAll(true);
			this.handleInput(value);
		}
	},

	/**
	 * Called to filter out records before they are added to this field.
	 * This will loop over all records and call {@link #filterRecord} to
	 * check if the record should be visible or not.
	 * @param {Ext.data.Store} store The store
	 * @param {Ext.data.Record[]} records The records to filter
	 * @return {Ext.data.Record[]} The records which are visible
	 * @protected
	 */
	filterRecords: function(store, records)
	{
		var ret = [];

		for (var i = 0, len = records.length; i < len; i++) {
			var record = records[i];
			if (this.filterRecord(record)) {
				ret.push(record);
			}
		}

		return ret;
	},

	/**
	 * Called by {@link #filterRecords} to check if the given record
	 * must be visible in the field or not.
	 * @param {Ext.data.Record} record The record to filter
	 * @return {Boolean} True if the record should be visible, false otherwise
	 * @protected
	 */
	filterRecord : function(record)
	{
		return true;
	},

	/**
	 * Find the {@link Zarafa.common.ui.Box} which belongs to the given record.
	 * @param {Ext.data.Record} record The record for which the box is searched
	 * @return {Zarafa.common.ui.Box} The box which belongs to the given record
	 */
	getBoxForRecord : function(record)
	{
		return this.items.find(function(box) { return box.record === record;  });
	},

	/**
	 * Call before the field is being blurred. When we still have an
	 * {@link #currentFocus boxfocus} it must be removed now.
	 *
	 * @private
	 */
	beforeBlur : function()
	{
		Zarafa.common.ui.BoxField.superclass.beforeBlur.apply(this, arguments);
		this.convertInputToBox();
		this.boxBlur();
	},

	/**
	 * Put the focus on a particular box. This will call {@link Zarafa.common.ui.Box#blur}
	 * on the {@link #currentFocus currently focussed} element. And then call
	 * {@link Zarafa.common.ui.Box#focus} on the new box which will be set in {@link #currentFocus}.
	 *
	 * @param {Zarafa.common.ui.Box} box The box to put the focus on
	 * @private
	 */
	boxFocus : function(box)
	{
		if (this.currentFocus) {
			this.currentFocus.blur();
		}

		this.currentFocus = box;

		if (this.currentFocus) {
			this.currentFocus.focus();
		}
	},

	/**
	 * Remove the focus from the {@link #currentFocus currently focussed} box.
	 * This will call {@link Zarafa.common.ui.Box#blur} on the box, and then
	 * reset {@link #currentFocus}.
	 * @private
	 */
	boxBlur : function()
	{
		if (this.currentFocus) {
			this.currentFocus.blur();
		}

		this.currentFocus = false;
	},

	/**
	 * Try to focus this component.
	 * @param {Boolean} selectText (optional) If applicable, true to also select the text in this component
	 * @param {Boolean/Number} delay (optional) Delay the focus this number of milliseconds (true for 10 milliseconds)
	 * @return {Ext.Component} this
	 */
	focus : function(selectText, delay)
	{
		if (delay) {
			this.focusTask = new Ext.util.DelayedTask(this.focus, this, [selectText, false]);
			this.focusTask.delay(Ext.isNumber(delay) ? delay : 10);
			return;
		}
		if (this.rendered && !this.isDestroyed) {
			this.inputFocus(undefined, selectText);
		}
		return this;
	},

	/**
	 * Put the focus on the {@link #el Input element}, when a box is already
	 * {@link #currentFocus focussed} it will be {@link #boxBlur blurred} after
	 * which the focus is put on the {@link #el Input element}.
	 *
	 * When provided, the new caret position for the input field can also be provided.
	 * @param {Number} caretPos (optional) The desired caret position
	 * @private
	 */
	inputFocus : function(caretPos, selectText)
	{
		this.boxBlur();
		this.el.focus();
		if (!Ext.isEmpty(caretPos)) {
			Zarafa.core.Util.setCaretPosition(this.el, caretPos);
		}
		if (selectText === true) {
			this.el.dom.select();
		}
	},

	/**
	 * Remove the focus from the {@link #el} element.
	 * @private
	 */
	inputBlur : function()
	{
		this.el.blur();
	},

	/**
	 * Event handler which is fired when the user clicked anywhere
	 * on the {@link #container}, but not on a specific {@link #items box}.
	 * In this case, we redirect our focus to the input element.
	 * @private
	 */
	onContainerClick : function(e, element)
	{
		this.collapse();
		if (this.editable) {
			if (element === this.el.dom) {
				this.inputFocus();
			} else {
				// If element is visible then and only we can set focus on the element.
				if(this.el.isVisible()) {
					// Stop event propagation.
					e.stopEvent();
					this.inputFocus(this.el.dom.value.length);
				}
			}
		} else if (!this.currentFocus) {
			this.boxFocus(this.items.last());
		}
	},

	/**
	 * Create the {@link Ext.KeyMap} for an {@link Ext.Element} which
	 * serves as the focus element for the {@link #items boxes}.
	 * @param {Ext.Element} focusEl The element which acts as the focusElement for the boxes.
	 * @return {Ext.KeyMap} The keymap for the focus element.
	 * @private
	 */
	createBoxKeyMap : function(focusEl)
	{
		var bindings = [{
			key: [
				Ext.EventObject.ENTER
			],
			handler: this.onBoxKeyEnter,
			scope: this
		},{
			key: [
				Ext.EventObject.UP,
				Ext.EventObject.PAGE_UP
			],
			handler: this.onBoxKeyUp,
			scope: this
		},{
			key: [
				Ext.EventObject.DOWN,
				Ext.EventObject.PAGE_DOWN
			],
			handler: this.onBoxKeyDown,
			scope: this
		},{
			key: [
				Ext.EventObject.LEFT
			],
			handler: this.onBoxKeyLeft,
			scope: this
		},{
			key: [
				Ext.EventObject.RIGHT
			],
			handler: this.onBoxKeyRight,
			scope: this
		},{
			key: [
				Ext.EventObject.HOME
			],
			handler: this.onBoxKeyHome,
			scope: this
		},{
			key: [
				Ext.EventObject.END
			],
			handler: this.onBoxKeyEnd,
			scope: this
		},{
			key: [
				Ext.EventObject.BACKSPACE
			],
			handler: this.onBoxKeyBackspace,
			scope: this
		},{
			key: [
				Ext.EventObject.DELETE
			],
			handler: this.onBoxKeyDelete,
			scope: this
		}];

		// disable modifier keys in the bindings
		for(var i = 0, len = bindings.length; i < len; i++) {
			var binding = bindings[i];

			Ext.apply(binding, {
				shift: false,
				alt: false,
				ctrl: false
			});
		}

		return new Ext.KeyMap(focusEl, bindings);
	},

	/**
	 * Key handler for the {@link Ext.EventObject.ENTER ENTER} event
	 * for the {@link #boxFocusEl Box focus element}.
	 *
	 * This will perform the same action as {@link #doBoxDblClick}.
	 *
	 * @param {Number} key The key which was pressed
	 * @param {Ext.EventObject} e The event object which fired the event
	 * @private
	 */
	onBoxKeyEnter : function(key, e)
	{
		e.stopEvent();

		this.doBoxDblClick(this.currentFocus);
	},

	/**
	 * Key handler for the {@link Ext.EventObject.UP} event
	 * for the {@link #boxFocusEl Box focus element}.
	 *
	 * This will select the box left to the currently selected box.
	 * If this is the first box of the {@link #items} array, the focus
	 * on the items is lost, and the {@link #el input element} is focussed.
	 *
	 * @param {Number} key The key which was pressed
	 * @param {Ext.EventObject} e The event object which fired the event
	 * @private
	 */
	onBoxKeyUp : function(key, e)
	{
		this.onBoxKeyLeft(key, e);
	},

	/**
	 * Key handler for the {@link Ext.EventObject.DOWN} event
	 * for the {@link #boxFocusEl Box focus element}.
	 *
	 * This will select the box right to the currently selected box.
	 * If this is the last box of the {@link #items} array, the focus
	 * on the items is lost, and the {@link #el input element} is focussed.
	 *
	 * @param {Number} key The key which was pressed
	 * @param {Ext.EventObject} e The event object which fired the event
	 * @private
	 */
	onBoxKeyDown : function(key, e)
	{
		this.onBoxKeyRight(key, e);
	},

	/**
	 * Key handler for the {@link Ext.EventObject.LEFT} event
	 * for the {@link #boxFocusEl Box focus element}.
	 *
	 * This will select the box left to the currently selected box.
	 * If this is the first box of the {@link #items} array, the focus
	 * remains on the current box.
	 *
	 * @param {Number} key The key which was pressed
	 * @param {Ext.EventObject} e The event object which fired the event
	 * @private
	 */
	onBoxKeyLeft : function(key, e)
	{
		e.stopEvent();

		var index = this.items.indexOf(this.currentFocus);
		if (index !== 0) {
			this.boxFocus(this.items.itemAt(index - 1));
		}
	},

	/**
	 * Key handler for the {@link Ext.EventObject.RIGHT} event
	 * for the {@link #boxFocusEl Box focus element}.
	 *
	 * This will select the box right to the currently selected box.
	 * If this is the last box of the {@link #items} array, the focus
	 * on the items is lost, and the {@link #el input element} is focussed.
	 *
	 * @param {Number} key The key which was pressed
	 * @param {Ext.EventObject} e The event object which fired the event
	 * @private
	 */
	onBoxKeyRight : function(key, e)
	{
		e.stopEvent();

		var index = this.items.indexOf(this.currentFocus);
		if (index !== this.items.getCount() - 1) {
			this.boxFocus(this.items.itemAt(index + 1));
		} else if (this.editable) {
			this.inputFocus(0);
		}
	},

	/**
	 * Key handler for the {@link Ext.EventObject.HOME} event
	 * for the {@link #boxFocusEl Box focus element}.
	 *
	 * This will select the first item in the {@link #items} array.
	 *
	 * @param {Number} key The key which was pressed
	 * @param {Ext.EventObject} e The event object which fired the event
	 * @private
	 */
	onBoxKeyHome : function(key, e)
	{
		e.stopEvent();

		var item = this.items.first();
		if (!item.hasFocus()) {
			this.boxFocus(item);
		}
	},

	/**
	 * Key handler for the {@link Ext.EventObject.END} event
	 * for the {@link #boxFocusEl Box focus element}.
	 *
	 * This will select the last item in the {@link #items} array.
	 *
	 * @param {Number} key The key which was pressed
	 * @param {Ext.EventObject} e The event object which fired the event
	 * @private
	 */
	onBoxKeyEnd : function(key, e)
	{
		e.stopEvent();

		var item = this.items.last();
		if (!item.hasFocus()) {
			this.boxFocus(item);
		} else if (this.editable) {
			this.inputFocus(this.el.dom.value.length);
		}
	},

	/**
	 * Key handler for the {@link Ext.EventObject.BACKSPACE} event
	 * for the {@link #boxFocusEl Box focus element}.
	 *
	 * This will delete the currently selected item from the field,
	 * and will select the item to the left of the deleted item.
	 *
	 * @param {Number} key The key which was pressed
	 * @param {Ext.EventObject} e The event object which fired the event
	 * @private
	 */
	onBoxKeyBackspace : function(key, e)
	{
		e.stopEvent();

		if (this.editable !== false) {
			var index = this.items.indexOf(this.currentFocus);

			this.doBoxRemove(this.currentFocus);

			if (index > 0) {
				this.boxFocus(this.items.itemAt(index - 1));
			} else if (this.items.getCount() > 0) {
				this.boxFocus(this.items.itemAt(0));
			} else {
				this.inputFocus();
			}
		}
	},

	/**
	 * Key handler for the {@link Ext.EventObject.DELETE} event
	 * for the {@link #boxFocusEl Box focus element}.
	 *
	 * This.will delete the currently selected item from the field,
	 * and will select the item to the right of the deleted item.
	 *
	 * @param {Number} key The key which was pressed
	 * @param {Ext.EventObject} e The event object which fired the event
	 * @private
	 */
	onBoxKeyDelete : function(key, e)
	{
		e.stopEvent();

		if (this.editable !== false) {
			var index = this.items.indexOf(this.currentFocus);

			this.doBoxRemove(this.currentFocus);

			if (index < this.items.getCount()) {
				this.boxFocus(this.items.itemAt(index));
			} else {
				this.inputFocus(0);
			}
		}
	},

	/**
	 * Create the {@link Ext.KeyMap} for the {@link #el}.
	 * This KeyMap is only used for the {@link handleInputKey}, which needs its character code detected.
	 * That is why the 'keypress' event is used instead of the default 'keydown',
	 * which does not report character codes.
	 *
	 * @param {Ext.Element} focusEl The element which acts as the focusElement for the input element.
	 * @return {Ext.KeyMap} The keymap for the focus element.
	 * @private
	 */
	createInputKeyMap : function(focusEl)
	{
		return new Ext.KeyMap(focusEl, [{
			key: [
				this.handleInputKey
			],
			shift: false,
			alt: false,
			ctrl: false,
			handler: this.onInputKey,
			scope: this
		}], 'keypress');
	},

	/**
	 * Create the {@link Ext.KeyMap} for the {@link #el} to handle
	 * various key board controls for suggestion {@link #list}.
	 *
	 * @param {Ext.Element} element The {@link Zarafa.common.ui.BoxField#el combo box} element.
	 * @return {Ext.KeyMap} The keymap for the {@link Zarafa.common.ui.BoxField#el combo box} element.
	 * @private
	 */
	createListKeyMap : function(element)
	{
		// Listen to DELETE key event which remove record from suggestion list.
		return new Ext.KeyMap(element, {
			key: [
				Ext.EventObject.DELETE
			],
			handler: this.onListKeyDelete,
			scope: this,
			shift: false,
			alt: false,
			ctrl: false
		});
	},

	/**
	 * Create the {@link Ext.KeyMap} for the {@link #el}.
	 * This KeyMap is used for special keys, such as enter, page up/down, arrows, etc.
	 *
	 * @param {Ext.Element} focusEl The element which acts as the focusElement for the input element.
	 * @return {Ext.KeyMap} The keymap for the focus element.
	 * @private
	 */
	createSpecialInputKeyMap : function(focusEl)
	{
		var bindings = [{
			key: [
				Ext.EventObject.ENTER
			],
			handler: this.onInputKeyEnter,
			scope: this
		},{
			key: [
				Ext.EventObject.TAB
			],
			handler: this.onInputKeyTab,
			scope: this
		},{
			key: [
				Ext.EventObject.UP,
				Ext.EventObject.PAGE_UP
			],
			handler: this.onInputKeyUp,
			scope: this
		},{
			key: [
				Ext.EventObject.LEFT
			],
			handler: this.onInputKeyLeft,
			scope: this
		},{
			key: [
				Ext.EventObject.HOME
			],
			handler: this.onInputKeyHome,
			scope: this
		},{
			key: [
				Ext.EventObject.BACKSPACE
			],
			handler: this.onInputKeyBackspace,
			scope: this
		}];

		// disable modifier keys in the bindings
		for(var i = 0, len = bindings.length; i < len; i++) {
			var binding = bindings[i];

			Ext.apply(binding, {
				shift: false,
				alt: false,
				ctrl: false
			});
		}

		// Add combination of TAB with shift as well to trigger blur and handle input text
		bindings.push({
			key: [
				Ext.EventObject.TAB
			],
			shift: true,
			alt: false,
			ctrl: false,
			handler: this.onInputKeyTab,
			scope: this
		});

		return new Ext.KeyMap(focusEl, bindings);
	},

	/**
	 * Generic {@link Ext.Element#keydown} event handler for the {@link #el input element}.
	 * This handler is run for all keys which were not handled by the {@link #inputKeyMap}.
	 * This will simply {@link #sizeInputfield resize} the {@link #el input element}.
	 *
	 * @param {Number} key The key which was pressed
	 * @param {Ext.EventObject} e The event object which fired the event
	 * @private
	 */
	onKeyDownHandler: function(e)
	{
		// Don't resize the inputfield on special keys (arrow-keys, backspace, etc)
		// for some weird reason these keys would trigger the input field to become
		// larger, while no input is being added...
		if (!e.isSpecialKey()) {
			this.collapse();
			this.sizeInputfield();
		}
	},

	/**
	 * Key handler for the {@link #handleInputKey} event
	 * for the {@link #el input element}.
	 *
	 * This will clear  the {@link #el} element, and send the
	 * old value to {@link #handleInput} to create a new {@link #items box}.
	 *
	 * @param {Number} key The key which was pressed
	 * @param {Ext.EventObject} e The event object which fired the event
	 * @private
	 */
	onInputKey : function(key, e)
	{
		e.stopEvent();
		this.convertInputToBox();
	},

	/**
	 * Key handler for the {@link Ext.EventObject.ENTER} event
	 * for the {@link #el input element}.
	 *
	 * This will clear  the {@link #el} element, and send the
	 * old value to {@link #handleInput} to create a new {@link #items box}.
	 *
	 * @param {Number} key The key which was pressed
	 * @param {Ext.EventObject} e The event object which fired the event
	 * @private
	 */
	onInputKeyEnter : function(key, e)
	{
		// Make sure we are not expanded, because in that
		// case the ENTER command is reserved for selecting
		// an item from the dropdown list.
		if (!(this.isExpanded() && this.store.getCount() > 0)) {
			e.stopEvent();
			this.convertInputToBox();
		}
	},

	/**
	 * Key handler for the {@link Ext.EventObject.TAB} event
	 * for the {@link #el input element}.
	 *
	 * @param {Number} key The key which was pressed
	 * @param {Ext.EventObject} e The event object which fired the event
	 * @private
	 */
	onInputKeyTab : function(key, e)
	{
		//If the user entered something, we should prevent default tab behavior
		if (!Ext.isEmpty(this.getValue())) {
			e.stopEvent();

			if (!(this.isExpanded() && this.store.getCount() > 0)){
			    this.convertInputToBox();
			}
		}else{
			//Trigger a blur to remove the focus class from the element
			this.triggerBlur();
		}
	},

	/**
	 * Key handler for the {@link Ext.EventObject.UP} event
	 * for the {@link #el input element}.
	 *
	 * When the cursor is at the most-left position of the {@link #el input element}
	 * then the box to the left of the input element is selected.
	 *
	 * @param {Number} key The key which was pressed
	 * @param {Ext.EventObject} e The event object which fired the event
	 * @private
	 */
	onInputKeyUp : function(key, e)
	{
		this.onInputKeyLeft(key, e);
	},

	/**
	 * Key handler for the {@link Ext.EventObject.LEFT} event
	 * for the {@link #el input element}.
	 *
	 * When the cursor is at the most-left position of the {@link #el input element}
	 * then the box to the left of the input element is selected.
	 *
	 * @param {Number} key The key which was pressed
	 * @param {Ext.EventObject} e The event object which fired the event
	 * @private
	 */
	onInputKeyLeft : function(key, e)
	{
		var caret = Zarafa.core.Util.getSelectionRange(this.el);
		if (caret.start === 0 && caret.end === 0 && this.items.getCount() > 0) {
			e.stopEvent();
			this.boxFocus(this.items.last());
		}
	},

	/**
	 * Key handler for the {@link Ext.EventObject.HOME} event
	 * for the {@link #el input element}.
	 *
	 * When the cursor is at the most-left position of the {@link #el input element}
	 * then the first box of {@link #items} is selected.
	 *
	 * @param {Number} key The key which was pressed
	 * @param {Ext.EventObject} e The event object which fired the event
	 * @private
	 */
	onInputKeyHome : function(key, e)
	{
		var caret = Zarafa.core.Util.getSelectionRange(this.el);
		if (caret.start === 0 && caret.end === 0 && this.items.getCount() > 0) {
			e.stopEvent();
			this.boxFocus(this.items.first());
		}
	},

	/**
	 * Key handler for the {@link Ext.EventObject.BACKSPACE event
	 * for the {@link #el input element}.
	 *
	 * When the cursor is at the most-left position of the {@link #el input element}
	 * then the box to the left of the input element is selected (so that pressing
	 * 'backspace' again will delete it.
	 *
	 * @param {Number} key The key which was pressed
	 * @param {Ext.EventObject} e The event object which fired the event
	 * @private
	 */
	onInputKeyBackspace : function(key, e)
	{
		var caret = Zarafa.core.Util.getSelectionRange(this.el);
		if (caret.start === 0 && caret.end === 0 && this.items.getCount() > 0) {
			e.stopEvent();
			this.boxFocus(this.items.last());
		}
	},

	/**
	 * Key handler for the {@link Ext.EventObject.DELETE} event
	 * for the {@link #el element} defined by {@link Ext.KeyMap}.
	 *
	 * This will remove current record identified by {@link #selectedIndex} from
	 * {@link Zarafa.common.recipientfield.data.SuggestionListStore SuggestionListStore}.
	 *
	 * @param {Number} key The key which was pressed
	 * @param {Ext.EventObject} e The event object which fired the event
	 * @private
	 */
	onListKeyDelete : function(key, e)
	{
		var store = this.getStore();

		if (store.getCount() !== 0) {
			// Prevent default browser behaviour of deleting characters from input text
			// as we are going to use this event to delete records from list.
			e.stopEvent();
			store.removeAt(this.selectedIndex);

			// If deleted item is the last one in the list than previous item of the deleted item will be selected.
			if (store.getCount() ==  this.selectedIndex) {
				this.selectPrev();
			} else {
				this.select(this.selectedIndex);
			}
			this.restrictHeight();
		}
	},

	/**
	 * Event handler for the {@link Ext.DataView#extraitemclick} event.
	 * This is fired when {@link #extraItemSelector} node from dropdown-list is clicked.
	 * Just remove selected node by calling {@link #onListKeyDelete} function.
	 * @param {Ext.DataView} The underlying {@link Ext.DataView} instance responsible to create dropdown-list.
	 * @param {Number} index The index of the target node
	 * @param {HTMLElement} extraItem The target node
	 * @param {Ext.EventObject} e The raw event object
	 * @private
	 */
	onExtraItemClick : function(dataView, index, extraItem, e)
	{
		this.onListKeyDelete(false, e);
	},

	/**
	 * Event handler for the 'paste' event on the {@link #el input element}.
	 * This is fired by the special {@link Zarafa.core.Event#addPasteEventHandler}
	 * event handler. This will resize the input field, to fit the field to the
	 * new contents.
	 * @private
	 */
	onPaste : function()
	{
		this.sizeInputfield();
	},

	/**
	 * Event handler for the {@link Ext.data.Store#datachanged} event from the {@link #boxStore}.
	 * This will {@link #clearBoxes clear all boxes} and then {@link #loadBoxes rebuild them}.
	 * @param {Ext.data.Store} store The store which fired the event
	 * @private
	 */
	onBoxStoreDataChanged : function(store)
	{
		this.clearBoxes();
		this.loadBoxes(store);
	},

	/**
	 * Event handler for the {@link Ext.data.Store#clear} event from the {@link #boxStore}.
	 * This will {@link #clearBoxes clear all boxes}.
	 * @private
	 */
	onBoxStoreClear : function()
	{
		this.clearBoxes();
	},

	/**
	 * Event handler for the {@link Ext.data.Store#add} event from the {@link #boxStore}.
	 * This will check if the provided records should be {@link #filterRecords shown} inside
	 * this field, and those that are not filtered will be {@link #addBox added}.
	 * @param {Ext.data.Store} store The store which fired the event
	 * @param {Ext.data.Record[]} records The records which were added
	 * @param {Number} index The index position at which the records where added
	 * @private
	 */
	onBoxStoreAdd: function(store, records, index)
	{
		if (!Array.isArray(records)) {
			records = [ records ];
		}

		records = this.filterRecords(store, records);

		for (var i = 0; i < records.length; i++) {
			this.addBox(records[i]);
		}
	},

	/**
	 * Event handler for the {@link Ext.data.Store#remove} event from the {@link #boxStore}.
	 * This will {@link #removeBox remove} the box which is attached to the given record.
	 * @param {Ext.data.Store} store The store which fired the event
	 * @param {Ext.data.Record} record The record which was removed
	 * @param {Number} index The position from where the record was removed
	 * @private
	 */
	onBoxStoreRemove: function(store, record, index)
	{
		this.removeBox(record);
	},

	/**
	 * Event handler for the {@link Ext.data.Store#update} event from the {@link #boxStore}.
	 * This will {@link Zarafa.common.ui.Box#update update} the box with the new
	 * {@link Ext.data.Record#data record data}.
	 * When the field is updated, the modified record may have changed whether it passes the field's filter or not.
	 * Therefore, the function adds or removes this record's box.
	 * @param {Ext.data.Store} store The store which fired the event
	 * @param {Ext.data.Record} record THhe record which was updated
	 * @private
	 */
	onBoxStoreUpdate: function(store, record)
	{
		if (this.filterRecord(record)) {
			var box = this.getBoxForRecord(record);
			if (box) {
				// record passes filter and has a box - just update
				box.update(record);
			} else {
				// record passes the filter and does not have a box in this field yet - add it
				this.addBox(record);
			}
		} else {
			// if this record does not pass the filter, remove its box
			this.removeBox(record);
		}
	},

	/**
	 * Callback function from {@link Zarafa.common.ui.Box} which indicates
	 * that the box has been clicked. This will {@link #boxFocus focus the
	 * box}, and fire the {@link #boxclick} event.
	 * @param {Zarafa.common.ui.Box} box The box which called this function
	 */
	doBoxClick: function(box)
	{
		this.boxFocus(box);

		this.fireEvent('boxclick', this, box, box.record);
	},

	/**
	 * Callback function from {@link Zarafa.common.ui.Box} which indicates
	 * that the box has been doubleclicked. This will fire the
	 * {@link #boxdblclick} event.
	 * @param {Zarafa.common.ui.Box} box The box which called this function
	 */
	doBoxDblClick : function(box)
	{
		this.fireEvent('boxdblclick', this, box, box.record);
	},

	/**
	 * Callback function from {@link Zarafa.common.ui.Box} which indicates
	 * that the contextmenu has been requested for the given box. This will
	 * {@link #boxFocus focus the box}, and fire the {@link #boxcontextmenu} event.
	 * @param {Zarafa.common.ui.Box} box The box which called this function
	 */
	doBoxContextMenu : function(box)
	{
		this.boxFocus(box);

		this.fireEvent('boxcontextmenu', this, box, box.record);
	},

	/**
	 * Callback function from {@link Zarafa.common.ui.Box} which indicates that
	 * the box has received the focus. This will focus the {@link #boxFocusEl}
	 * and {@link Ext.Element#scrollIntoView scroll the box into view}. Finally
	 * the {@link #boxfocus} event.
	 * @param {Zarafa.common.ui.Box} box The box which called this function
	 */
	doBoxFocus : function(box)
	{
		// It could happen a box is being focussed without
		// the field being focussed.
		if (this.hasFocus !== true) {
			this.onFocus();
		}

		this.boxFocusEl.focus();
		box.getPositionEl().scrollIntoView(this.getContentTarget());

		this.fireEvent('boxfocus', this, box, box.record);
	},

	/**
	 * Callback function from {@link Zarafa.common.ui.Box} which indicates
	 * that the box has been blurred. This will blur the {@link #boxFocuEl}
	 * and will fire the {@link #boxblur} event.
	 * @param {Zarafa.common.ui.Box} box The box which called this function
	 */
	doBoxBlur : function(box)
	{
		this.boxFocusEl.blur();

		this.fireEvent('boxblur', this, box, box.record);
	},

	/**
	 * Callback function from {@link Zarafa.common.ui.Box} which indicates that
	 * the box is being removed by the user. This will fire the {@link #boxremove}
	 * event.
	 * @param {Zarafa.common.ui.Box} box The box which called this function
	 */
	doBoxRemove: function(box)
	{
		this.fireEvent('boxremove', this, box, box.record);
	},

	/**
	 * Event handler for the {@link #boxremove} event. This will remove
	 * the record belonging to the box from the {@link #boxStore}. Then
	 * {@link #sizeContainer} is called. This is needed because the
	 * removal of the box might have triggered a resize of the {@link #wrap}
	 * and thus we might no longer need the scrollbars.
	 * @param {Zarafa.common.ui.BoxField} field The field which has fired the event
	 * @param {Zarafa.common.ui.Box} box The box which has been removed
	 * @param {Ext.data.Record} record The record which belongs to the given box
	 * @private
	 */
	onBoxRemove: function(field, box, record)
	{
		this.boxStore.remove(record);
		if (this.boxStore.getCount() < this.boxLimit && this.initialConfig.readOnly !== true) {
			this.setReadOnly(false);
			this.inputFocus();
		}
	},

	/**
	 * Event handler for the {@link #boxadd} event. This will
	 * {@link #sizeContainer resize the container}. This is needed because
	 * the new box, might have triggered a resize of the {@link #wrap}
	 * and thus we might need scrollbars.
	 * @param {Zarafa.common.ui.BoxField} field The field which has fired the event
	 * @param {Zarafa.common.ui.Box} box The box which has been added
	 * @param {Ext.data.Record} record The record which belongs to the given box
	 * @private
	 */
	onBoxAdd : function(field, box, record)
	{
		if (this.boxStore.getCount() >= this.boxLimit) {
			this.setReadOnly(true);
		}
	},

	/**
	 * Adds a box to the field. It will instantiate the {@link Zarafa.common.ui.Box Box} component that will
	 * render the box according to the data in the supplied record. It will render the box inside
	 * the wrapBoxesEl. After rendering the box it will add the box to the {@link #items items} and
	 * fire the {@link #boxadd} event.
	 * @param {Ext.data.Record} record The record to add as a box into the field
	 * @private
	 */
	addBox: function(record)
	{
		/*
		 * Create the configuration object for the Box. The this.boxConfig is used as default and we
		 * apply the record and renderTo properties onto that object.
		 */
		var configObj = {};
		Ext.apply(configObj, {
			xtype : this.boxType,
			parent : this,
			record : record,
			editable : this.editable,
			width : this.getDesiredBoxWidth()
		}, this.boxConfig);

		var box = Ext.create(configObj);
		box.render(this.wrapBoxesEl, this.items.length);

		this.items.add(box);

		this.sizeContainer();

		this.fireEvent('boxadd', this, box, record);
	},

	/**
	 * Removes a {@link Zarafa.common.ui.Box Box} from the field.
	 * @param {Ext.data.Record} record The record which belongs to the box which must be removed.
	 * @private
	 */
	removeBox : function(record)
	{
		var box = this.getBoxForRecord(record);
		if (!box) {
			return;
		}

		var index = this.items.indexOf(box);
		box.doDestroy(this.enableAnim);
		this.items.remove(box);

		if (this.items.getCount() < this.boxLimit && this.initialConfig.readOnly !== true) {
			this.setReadOnly(false);
		}

		if (!this.currentFocus || this.currentFocus === box) {
			if (this.items.getCount() > index) {
				this.boxFocus(this.items.itemAt(index));
			} else {
				this.inputFocus();
			}
		}
	},

	/**
	 * Load all new {@link Zarafa.common.ui.Box boxes} based on the records from
	 * the {@link Ext.data.Store store}. This will first {@link #filterRecords filter}
	 * the records from the store before {@link #addBox adding} them.
	 * @param {Ext.data.Store} store
	 * @private
	 */
	loadBoxes : function(store)
	{
		var records = this.filterRecords(store, store.getRange());

		for (var i = 0; i < records.length; i++) {
			this.addBox(records[i]);
		}
	},

	/**
	 * This will clear all {@link #items boxes}. Each box will be
	 * {@link Zarafa.common.ui.Box#destroy destroyed}, and then removed from {@link #items}
	 * @private
	 */
	clearBoxes: function()
	{
		this.items.each(function(item) {
			item.destroy();
		});

		this.items.clear();
	},

	/**
	 * Called when the component is being destroyed
	 * @private
	 */
	onDestroy : function()
	{
		Zarafa.common.ui.BoxField.superclass.onDestroy.apply(this, arguments);

		if (this.editable !== false) {
			Zarafa.core.Events.removePasteEventHandler(this, this.el, this.onPaste, this);
		}
	}
});

Ext.reg('zarafa.boxfield', Zarafa.common.ui.BoxField);