sap.ui.define([
	"sap/ui/demo/iconexplorer/controller/BaseController",
	"sap/ui/core/IconPool",
	"sap/ui/model/json/JSONModel",
	"sap/ui/demo/iconexplorer/model/formatter",
	"sap/ui/model/Filter",
	"sap/ui/model/FilterOperator",
	"sap/ui/Device",
	"sap/m/MessageToast",
	"sap/m/Label",
	"sap/m/ToggleButton",
	"sap/m/library",
	"jquery.sap.global"
], function (BaseController, IconPool, JSONModel, formatter, Filter, FilterOperator, Device, MessageToast, Label, ToggleButton, mobileLibrary, $) {
	"use strict";

	var TYPING_DELAY = 200; // ms

	return BaseController.extend("sap.ui.demo.iconexplorer.controller.Overview", {

		formatter: formatter,

		/* =========================================================== */
		/* lifecycle methods                                           */
		/* =========================================================== */

		/**
		 * Called when the overview controller is instantiated.
		 * @public
		 */
		onInit : function () {
			var oViewModel,
				oTagModel;

			this._oPreviousQueryContext = {};
			this._oCurrentQueryContext = null;

			// model used to manipulate control states
			oViewModel = new JSONModel({
				growingThreshold : 200,
				iconFilterCount: this.getResourceBundle().getText("overviewTabAllInitial"),
				overviewNoDataText : this.getResourceBundle().getText("overviewNoDataText")
			});
			this.setModel(oViewModel, "view");

			// helper model for managing the tag selection
			oTagModel = new JSONModel();
			this.setModel(oTagModel, "tags");

			this.getRouter().getRoute("overview").attachPatternMatched(this._updateUI, this);
		},

		/**
		 * Focus search field after rendering for immediate searchability
		 */
		onAfterRendering: function () {
			setTimeout(function () {
				this.byId("searchField").focus();
			}.bind(this),0);
		},

		/* =========================================================== */
		/* event handlers                                              */
		/* =========================================================== */

		/**
		 * Event handler for navigating back.
		 * We navigate back in the browser history
		 * @public
		 */
		onNavBack : function() {
			history.go(-1);
		},

		/**
		 * Triggered by the table's 'updateFinished' event and by the other tabs change: after new table
		 * data is available, this handler method updates the icon counter.
		 * @public
		 */
		onUpdateFinished : function () {
			function getRootControl(oEvent) {
				if (oEvent.srcControl.getMetadata().getName().search("CustomListItem") >= 0) {
					// keyboard event, get child
					return oEvent.srcControl.getContent()[0];
				} else if (oEvent.srcControl.getMetadata().getName().search("VerticalLayout") >= 0) {
					// layout clicked, just return it
					return oEvent.srcControl;
				} else {
					// inner control clicked, return parent
					return oEvent.srcControl.getParent();
				}
			}

			// show total count of items
			this.getModel("view").setProperty("/iconFilterCount", this.byId("results").getBinding(this._sAggregationName).getLength());
			// register press callback for grid and visual mode
			if (this._oCurrentQueryContext.tab === "grid" || this._oCurrentQueryContext.tab === "visual") {
				if (!this._oPressLayoutCellDelegate) {
					this._oPressLayoutCellDelegate = {
						// tap: set selected and hoverable class
						ontap: function (oEvent) {
							var oBindingContext = oEvent.srcControl.getBindingContext();
							var oRoot = getRootControl(oEvent);

							// prevent setting styles on the favorite button
							if (oRoot.getMetadata().getName().search("ToggleButton") >= 0 || oEvent.srcControl.getMetadata().getName().search("ToggleButton") >= 0) {
								return;
							}

							// reset previoulsy pressed item and store current item
							if (this._oPreviouslySelectedLayoutCell) {
								this._oPreviouslySelectedLayoutCell.removeStyleClass("sapMLIBSelected");
								this._oPreviouslySelectedLayoutCell.removeStyleClass("sapMLIBHoverable");
							}
							// set the LIB styles on the current cell
							oRoot.addStyleClass("sapMLIBSelected");

							this._oPreviouslySelectedLayoutCell = oRoot;
							oRoot.addStyleClass("sapMLIBHoverable");

							// select the icon
							this._updateHash("icon", oBindingContext.getProperty("name"));
						}.bind(this),
						// touchstart: set item active and remove hoverable class, invert icon color
						ontouchstart: function (oEvent) {
							var oRoot = getRootControl(oEvent);

							oRoot.addStyleClass("sapMLIBActive");
							oRoot.removeStyleClass("sapMLIBHoverable");
							if (!this._sNormalIconColor) {
								this._sNormalIconColor = oRoot.$().find(".sapUiIcon").control(0).getColor();
							}
							oRoot.$().find(".sapUiVltCell > .sapUiIcon").control().forEach(function (oIcon) {
								oIcon.setColor(sap.ui.core.theming.Parameters.get("sapUiTextInverted"));
							});
						}.bind(this),
						// touchend: remove active class, reset icon color
						ontouchend: function (oEvent) {
							var oRoot = getRootControl(oEvent);

							oRoot.removeStyleClass("sapMLIBActive");
							oRoot.$().find(".sapUiVltCell > .sapUiIcon").control().forEach(function (oIcon) {
								oIcon.setColor(this._sNormalIconColor);
							}.bind(this));
						}.bind(this)
					};
					// enter + space key: same as tab
					this._oPressLayoutCellDelegate.onsapenter = this._oPressLayoutCellDelegate.ontap;
				}

				// there is no addEventDelegateOnce so we remove and add it for all items
				var aItems = this.byId("results").getAggregation(this._sAggregationName);
				if (aItems) {
					aItems.forEach(function (oItem) {
						oItem.removeEventDelegate(this._oPressLayoutCellDelegate);
						oItem.addEventDelegate(this._oPressLayoutCellDelegate);
					}.bind(this));
				}
			}
		},

		/**
		 * Event handler when a table item gets pressed
		 * @param {sap.ui.base.Event} oEvent the table selectionChange event
		 * @public
		 */
		onSelectionChange : function (oEvent) {
			var sModelName = (this._oCurrentQueryContext.tab === "favorites" ? "fav" : undefined),
				oItem = oEvent.getParameter("listItem");

			this._updateHash("icon", oItem.getBindingContext(sModelName).getProperty("name"));
		},

		/**
		 * Event handler for changing the icon browse mode.
		 * We update the hash in case a new tab is selected.
		 * @param {sap.ui.base.Event} oEvent the tabSelect event of the IconTabBar
		 */
		onTabSelect : function (oEvent){
			if (oEvent.getParameter("selectedKey") === "all") {
				this._updateHash("reset", "all");
			} else {
				this._updateHash("tab", oEvent.getParameter("selectedKey"));
			}
		},

		/**
		 * Searches the icons and filters the bindings accordingly
		 * @param {sap.ui.base.Event} oEvent the liveChange event of the SearchField
		 * @public
		 */
		onSearch: function (oEvent) {
			this._updateHash("search", oEvent.getParameter("newValue"));
		},

		/**
		 * Event handler for the category selection
		 * @param {sap.ui.base.Event} oEvent the selectionChange event
		 */
		onSelectCategory : function (oEvent) {
			this._updateHash("cat", (oEvent.getParameter("selectedItem") ? oEvent.getParameter("selectedItem").getKey() : undefined));
		},

		/**
		 * Searches the icons for a single tag only and filters the bindings accordingly
		 * @param {sap.ui.base.Event} oEvent the liveChange event of the SearchField
		 * @public
		 */
		onTagSelect: function (oEvent) {
			this._updateHash("tag", oEvent.getParameter("pressed") === false ? "" : oEvent.getSource().getText());
		},

		/**
		 * Toggles the favorite state of an icon when the user presses on the favorite button
		 * @param {sap.ui.base.Event} oEvent the press event of the ToggleButton
		 * @public
		 */
		onToggleFavorite: function (oEvent) {
			var sModelName = (this._oCurrentQueryContext.tab === "favorites" ? "fav" : undefined),
				oBindingContext = oEvent.getSource().getBindingContext(sModelName),
				sName = oBindingContext.getProperty("name"),
				oResourceBundle = this.getResourceBundle(),
				bFavorite = this.getModel("fav").toggleFavorite(oBindingContext);

			if (bFavorite) {
				MessageToast.show(oResourceBundle.getText("overviewFavoriteAdd", [sName]));
			} else {
				MessageToast.show(oResourceBundle.getText("overviewFavoriteRemove", [sName]));
			}
		},

		/**
		 * Switches between code and icon copy mode
		 * @param {sap.ui.base.Event} oEvent the select event of the RadioButtonGroup
		 */
		onCopySelect: function (oEvent) {
			var iIndex = oEvent.getParameter("selectedIndex");

			if (iIndex === 0) {
				this.byId("previewCopy").getContent()[0].setVisible(true);
				this.byId("previewCopy").getContent()[1].setVisible(false);
			} else {
				this.byId("previewCopy").getContent()[1].setVisible(true);
				this.byId("previewCopy").getContent()[0].setVisible(false);
			}
		},

		/**
		 * Copies the value of the code input field to the clipboard and displays a message
		 * @public
		 */
		onCopyCodeToClipboard: function () {
			var sString = this.byId("previewCopyCode").getValue(),
				oResourceBundle = this.getResourceBundle(),
				sSuccessText, sExceptionText;

			sSuccessText = oResourceBundle.getText("previewCopyToClipboardSuccess", [sString]);
			sExceptionText = oResourceBundle.getText("previewCopyToClipboardFail", [sString]);
			this._copyStringToClipboard(sString, sSuccessText, sExceptionText);
		},

		/**
		 * Copies the unicode part from the input field to the clipboard and displays a message
		 * @public
		 */
		onCopyUnicodeToClipboard: function () {
			var oResourceBundle = this.getResourceBundle(),
				sSuccessText, sExceptionText,
				sIconName = this.byId("preview").getBindingContext().getObject().name,
				sString = this.getModel().getUnicodeHTML(sIconName);
			sString = sString.substring(2, sString.length - 1);
			sSuccessText = oResourceBundle.getText("previewCopyUnicodeToClipboardSuccess", [sString]);
			sExceptionText = oResourceBundle.getText("previewCopyUnicodeToClipboardFail", [sString]);
			this._copyStringToClipboard(sString, sSuccessText, sExceptionText);
		},

		/**
		 * Copies the icon to the clipboard and displays a message
		 * @public
		 */
		onCopyIconToClipboard: function () {
			var sString = this.byId("previewCopyCode").getValue(),
				oResourceBundle = this.getResourceBundle(),
				sSuccessText, sExceptionText,
				sIcon = this.getModel().getUnicode(sString);

			sSuccessText = oResourceBundle.getText("previewCopyToClipboardSuccess", [sString]);
			sExceptionText = oResourceBundle.getText("previewCopyToClipboardFail", [sString]);
			this._copyStringToClipboard(sIcon, sSuccessText, sExceptionText);
		},

		/**
		 * Shows a random icon in the preview pane
		 * @public
		 */
		onSurpriseMe: function () {
			var aIcons = this.getModel().getProperty("/groups/0/icons"),
				oRandomItem = aIcons[Math.floor(Math.random() * aIcons.length)];

			this._updateHash("icon", oRandomItem.name);
		},

		/**
		 * Downloads the icon font relatively from the UI5 delivery
		 * @public
		 */
		onDownload: function () {
			mobileLibrary.URLHelper.redirect(jQuery.sap.getModulePath("sap.ui.core", "/themes/base/fonts/SAP-icons.ttf"));
		},

		/* =========================================================== */
		/* internal method                                             */
		/* =========================================================== */

		/**
		 * Copies the string to the clipboard and displays a message
		 * @param {string} copyText the text string that has to be copied to the clipboard
		 */
		_copyStringToClipboard: function (copyText, successText, exceptionText) {
			var $temp = $("<input>");

			try {
				$("body").append($temp);
				$temp.val(copyText).select();
				document.execCommand("copy");
				$temp.remove();

				MessageToast.show(successText);
			} catch (oException) {
				MessageToast.show(exceptionText);
			}
		},

		/**
		 * Shows the selected item on the object page
		 * On phones a additional history entry is created
		 * @param {string} sIcon the icon name to be previewed
		 * @private
		 */
		_previewIcon : function (sIcon) {
			this.getModel().iconsLoaded().then(function () {
				// bind the preview to the item path
				this.byId("preview").bindElement({
					path: this.getModel().getIconPath(sIcon)
				});

				var sIconSymbol = this.getModel().getUnicodeHTML(sIcon);
				this.byId("previewCopyIcon").setHtmlText("<span>" + sIconSymbol + "</span>" + sIcon);

				// update the group information with a timeout as this task takes some time to calculate
				setTimeout(function () {
					var aGroups = this.getModel().getIconGroups(sIcon);
					this.byId("categoryInfo").setText(aGroups.join(", "));
				}.bind(this),0);

				// update unicode info
				this.byId("unicodeInfo").setText(this.getModel().getUnicodeHTML(sIcon));
			}.bind(this));
		},

		/**
		 * Updates the UI according to the hash
		 * @param {sap.ui.base.Event} oEvent the routing event
		 * @private
		 */
		_updateUI: function (oEvent) {
			var oQuery = oEvent.getParameter("arguments")["?query"],
				bInitial = false;

			// set a default query object in case no has is defined
			if (!oQuery) {
				oQuery = {
					tab: "grid"
				};
			}

			// keep the previous item if all tab (remove filters) has been pressed
			if (oQuery.tab === "all") {
				oQuery.tab = this._oPreviousQueryContext.tab;
			}

			// check tab value against a whitelist
			var aValidKeys = ["details", "grid", "visual", "favorites"];
			if (aValidKeys.indexOf(oQuery.tab) < 0) {
				oQuery.tab = "grid";
			}

			// store current context
			if (!this._oCurrentQueryContext) {
				bInitial = true;
			}
			this._oCurrentQueryContext = oQuery;

			// helper variables for updating the UI pieces
			var bTabChanged = this._oPreviousQueryContext.tab !== oQuery.tab;
			var bCategoryChanged = this._oPreviousQueryContext.cat !== oQuery.cat;
			var bSearchChanged = this._oPreviousQueryContext.search !== oQuery.search;
			var bTagChanged = this._oPreviousQueryContext.tag !== oQuery.tag;
			var bIconChanged = this._oPreviousQueryContext.icon !== oQuery.icon;

			this._sAggregationName = "items";

			this.getOwnerComponent().iconsLoaded().then(function () {
				// tab
				if (!this.byId("iconTabBar")) {
					return;
				}
				this.byId("iconTabBar").setSelectedKey(oQuery.tab);
				if (bTabChanged) {
					var oContent = this.byId("resultContainer").getContent();

					// destroy last content item (1 is the search bar and 2 is the tags bar)
					if (oContent.length === 3) {
						oContent.pop().destroy();
					}
					// uppercase first letter
					var sFragmentName = formatter.uppercaseFirstLetter(oQuery.tab);

					// add new content to the end of result container
					var oResultsFragment = sap.ui.xmlfragment(
						this.getView().getId(),
						"sap.ui.demo.iconexplorer.view.browse." + sFragmentName, this);
					this.byId("resultContainer").addContent(oResultsFragment);

					var bCategoriesVisible = !(Device.system.phone || oQuery.tab == "favorites");
					this.byId("categorySelection").setVisible(bCategoriesVisible);
				}

				// icon
				if (oQuery.icon && bIconChanged) {
					this._previewIcon(oQuery.icon);
					this.byId("preview").setVisible(true);
					if (this.byId("preview").getLayoutData().getSize() === "0px") {
						this.byId("preview").getLayoutData().setSize("350px");
					}
				} else if (!oQuery.icon) {
					if (bInitial) {
						this._previewIcon("sap-ui5");
					}
					this.byId("preview").setVisible(false);
					this.byId("preview").getLayoutData().setSize("0px");
				}

				// category
				this.byId("categorySelection").setSelectedKey(oQuery.cat);
				if ((oQuery.cat || bCategoryChanged) && oQuery.tab !== "favorites") {
					if (bInitial || bTabChanged) {
						this._selectCategory(oQuery);
					} else {
						clearTimeout(this._iCategorySelectionTimeout);
						this._iCategorySelectionTimeout = setTimeout(function () {
							this._selectCategory(oQuery);
						}.bind(this), TYPING_DELAY);
					}
				}

				// search & tags
				this.byId("searchField").setValue(oQuery.search);
				if (bInitial || bSearchChanged || bTagChanged || bTabChanged) {
					// search
					if (bInitial || bTabChanged) {
						if (oQuery.search || bTabChanged) {
							this._searchIcons(oQuery.search, oQuery.tag);
						}
					} else {
						clearTimeout(this._iSearchTimeout);
						this._iSearchTimeout = setTimeout(function () {
							this._searchIcons(oQuery.search, oQuery.tag);
						}.bind(this), TYPING_DELAY);
					}

					// tags
					if (bInitial || bTabChanged) {
						if (oQuery.tab === "favorites") {
							this._aCategoryTags = undefined;
						}
						this._updateTags(oQuery);
					} else {
						clearTimeout(this._iTagTimeout);
						this._iTagTimeout = setTimeout(function () {
							this._updateTags(oQuery);
						}.bind(this), TYPING_DELAY);
					}
				}

			}.bind(this));
		},

		/**
		 * Updates the hash with the current UI state
		 * @param {string} [sKey] the key of the query to be updated
		 * @param {string} [sValue] the value of the query to be updated
		 * @private
		 */
		_updateHash: function (sKey, sValue) {
			var oQuery = {};

			// deep copy of the context
			if (this._oCurrentQueryContext.tab) {
				oQuery.tab = this._oCurrentQueryContext.tab;
			}
			if (this._oCurrentQueryContext.icon) {
				oQuery.icon = this._oCurrentQueryContext.icon;
			}
			if (this._oCurrentQueryContext.search) {
				oQuery.search = this._oCurrentQueryContext.search;
			}
			if (this._oCurrentQueryContext.cat) {
				oQuery.cat = this._oCurrentQueryContext.cat;
			}
			if (this._oCurrentQueryContext.tag) {
				oQuery.tag = this._oCurrentQueryContext.tag;
			}

			// explicit reset for tags and search when the all item was pressed
			if (sKey === "reset") {
				delete oQuery.tag;
				delete oQuery.search;
				delete oQuery.cat;
			} else {
				// override the key value pair passed in as parameters
				if (sKey && sValue) {
					oQuery[sKey] = sValue;
				}

				// reset tags under the following conditions
				// - navigating from or to favorite tab
				// - category was changed
				// - emtpy tag value
				if (this._oCurrentQueryContext.tab !== oQuery.tab  && (this._oCurrentQueryContext.tab === "favorites" || oQuery.tab === "favorites") ||
					this._oCurrentQueryContext.cat !== oQuery.cat ||
					sKey === "tag" && !sValue) {
					delete oQuery.tag;
				}

				// reset search if no value has been passed
				if (sKey === "search" && !sValue) {
					delete oQuery.search;
				}

				// reset icon if no value has been passed
				if (sKey === "icon" && !sValue) {
					delete oQuery.icon;
				}
			}

			// call route with query parameter
			this.getRouter().navTo("overview", {
				query: oQuery
			});

			// store previous context
			this._oPreviousQueryContext = this._oCurrentQueryContext;
			// store the new context
			this._oCurrentQueryContext = oQuery;
		},

		/**
		 * Does the real search after a short delay to improve the perceived performance of the app
		 * The following search modes can apply depending on the parameter values
		 * - search, no tag: reset the filters
		 * - search, no tag: search for the string in the name OR the tags of the icons
		 * - no search, tag: search for the tag in the tags of the icons
		 * - search, tag: search for the tag in the tags of the icons AND search for the string in the name OR the tags of the icons
		 * @param {string} sSearchValue the search string
		 * @param {string} sTagValue the tag string
		 * @private
		 */
		_searchIcons : function (sSearchValue, sTagValue) {
			if (sSearchValue || sTagValue) {
				// only initialize the filters if needed to save some time
				var aFilters = [],
					oFilterTags = (sTagValue ? new Filter("tagString", FilterOperator.Contains, sTagValue) : undefined),
					oFilterSearchName = (sSearchValue ? new Filter("name", FilterOperator.Contains, sSearchValue) : undefined),
					fnUmicodeCustomFilter = (sSearchValue ? this._unicodeFilterFactory(sSearchValue) : undefined),
					oFilterSearchUnicode = (sSearchValue ? new Filter("name", fnUmicodeCustomFilter) : undefined),
					oFilterSearchTags = (sSearchValue ? new Filter("tagString", FilterOperator.Contains, sSearchValue) : undefined),
					oFilterSearchNameTags = (sSearchValue ? new Filter({
						filters: [oFilterSearchTags, oFilterSearchName, oFilterSearchUnicode],
						and: false
					}) : undefined);

				// search for name
				if (sSearchValue) {
					aFilters.push(oFilterSearchNameTags);
				}
				// search for tags
				if (sTagValue) {
					aFilters.push(oFilterTags);
				}
				if (aFilters.length <= 1) {
					// search or tag: just take the filter
					this._vFilterSearch = aFilters;
				} else {
					// search and tag: tags contain the tag value and search for name or tags
					this._vFilterSearch = [new Filter({
						filters: aFilters,
						and: true
					})];
				}
			} else {
				// reset search
				this._vFilterSearch = [];
			}

			// filter icon list
			var oResultBinding = this.byId("results").getBinding(this._sAggregationName);
			if (oResultBinding !== undefined) {
				oResultBinding.filter(this._vFilterSearch);
				this.getModel("view").setProperty("/overviewNoDataText", this.getResourceBundle().getText("overviewNoDataWithSearchText"));
			}
		},

		/**
		 * Factory that produces the custom filter for the given unicode query
		 * @param {string} query the query text that has been entered in the search field and contains the unicode character
		 * @return {function} the custom filter function that takes the name of the icon and returns true if the icon's unicode contains the query string
		 * @private
		 */
		_unicodeFilterFactory: function(query) {
			return function (name) {
				var sUnicode = this.getModel().getUnicodeHTML(name.toLowerCase());
				return sUnicode.indexOf(query) !== -1;
			}.bind(this);
		},

		/**
		 * Event handler for the category selection
		 * @param {object} oQuery the query object from the routing event
		 * @private
		 */
		_selectCategory: function (oQuery) {
			var sGroupPath = this.getModel().getGroupPath(oQuery.cat);

			// rebind the result set to the current group
			this.byId("results").bindAggregation(this._sAggregationName, {
				path: sGroupPath + "/icons",
				length: this.getModel("view").getProperty("/growingThreshold"),
				template: this.byId("results").getBindingInfo(this._sAggregationName).template,
				events: {
					change: this.onUpdateFinished.bind(this)
				}
			});
			// apply filters
			this.byId("results").getBinding(this._sAggregationName).filter(this._vFilterSearch);
			// update tags
			this._aCategoryTags = this.getModel().getProperty(sGroupPath + "/tags");
			// update tag bar directly with all tags of this category when no search or tag is selected
			if (!oQuery.tag && !oQuery.search) {
				this._updateTagSelectionBar(this._aCategoryTags);
			}
		},

		/**
		 * updates the tags to the currently available binding contexts
		 * @param {Object} oQuery the current query state
		 * @private
		 */
		_updateTags: function (oQuery) {
			// caution: it is really important to use getCurrentContexts and not getContexts here as the later modifies the binding
			var aContexts = this.byId("results").getBinding(this._sAggregationName).getCurrentContexts(),
				aAllTags = [],
				aCurrentTags = [],
				bTagVisible = false,
				i;

			// collect all current tags from the result list
			for (i = 0; i < aContexts.length; i++) {
				aAllTags = aAllTags.concat(aContexts[i].getProperty("tags").map(function(oItem) { return oItem.name; }));
			}

			// no category selected yet: use all tags
			if (!this._aCategoryTags) {
				this._aCategoryTags = this.getModel().getProperty("/groups/0/tags");
			}

			// filter tags to the currently visible
			for (i = 0; i < this._aCategoryTags.length; i++) {
				if (aAllTags.indexOf(this._aCategoryTags[i].name) >= 0) {
					this._aCategoryTags[i].pressed = (this._aCategoryTags[i].name === oQuery.tag);
					if (this._aCategoryTags[i].pressed) {
						bTagVisible = true;
					}
					aCurrentTags.push(this._aCategoryTags[i]);
				}
			}

			// add current tag if it is not visible yet (tag bar only contains the top [x] tags)
			if (oQuery.tag && !bTagVisible) {
				aCurrentTags.push({
					pressed : true,
					name : oQuery.tag
				});
			}

			// update model data and bind the tags
			this._updateTagSelectionBar(aCurrentTags);
		},

		/**
		 * Binds tags to the tag selection bar and appends a label
		 * @param {object[]} aTags the tags to be bound
		 * @private
		 */
		_updateTagSelectionBar: function (aTags) {
			this.getModel("tags").setData([{"name" : ""}].concat(aTags));
			this.byId("tagSelection").bindAggregation("content", {
				path: "tags>/",
				length: 51,
				factory: this._tagSelectionFactory.bind(this)
			});
		},

		/**
		 * Factory function for filling the tag bar.
		 * First item is a label, then the tags are listed
		 * @param {string} sId the id for the control to be created
		 * @param {sap.ui.model.Context} oContext the binding context for the control to be created
		 * @return {sap.m.Label|sap.m.ToggleButton} the control for the toolbar
		 * @private
		 */
		_tagSelectionFactory: function (sId, oContext) {
			if (oContext.getProperty("name") === "") {
				return new Label(sId, {
					text: "{i18n>overviewTagSelectionLabel}"
				});
			} else {
				return new ToggleButton(sId, {
					text: "{tags>name}",
					pressed: "{tags>pressed}",
					press: [this.onTagSelect, this]
				});
			}
		}

	});
});
