/*!
 * ${copyright}
 */

// Provides control sap.m.Breadcrumbs.
sap.ui.define([
	"sap/ui/core/Control",
	"sap/ui/util/openWindow",
	"sap/m/Text",
	"sap/m/Link",
	"sap/m/Select",
	"sap/ui/core/Item",
	"sap/ui/core/delegate/ItemNavigation",
	"sap/ui/core/ResizeHandler",
	"sap/ui/core/IconPool",
	"sap/ui/Device",
	"sap/m/library",
	"./BreadcrumbsRenderer",
	'sap/ui/base/ManagedObject',
	'sap/ui/core/InvisibleText'
], function(
	Control,
	openWindow,
	Text,
	Link,
	Select,
	Item,
	ItemNavigation,
	ResizeHandler,
	IconPool,
	Device,
	library,
	BreadcrumbsRenderer,
	ManagedObject,
	InvisibleText
) {
	"use strict";

	// shortcut for sap.m.SelectType
	var SelectType = library.SelectType,

		// shortcut for sap.m.BreadCrumbsSeparatorStyle
		SeparatorStyle = library.BreadcrumbsSeparatorStyle,

		// shortcut for texts resource bundle
		oResource = sap.ui.getCore().getLibraryResourceBundle("sap.m");

	/**
	 * Constructor for a new <code>Breadcrumbs</code>.
	 *
	 * @param {string} [sId] ID for the new control, generated automatically if no ID is given
	 * @param {object} [mSettings] Initial settings for the new control
	 *
	 * @class
	 * Enables users to navigate between items by providing a list of links to previous steps in the user's
	 * navigation path. The last three steps can be accessed as links directly, while the remaining links prior to them
	 * are available in a drop-down menu.
	 *
	 * @see {@link fiori:https://experience.sap.com/fiori-design-web/breadcrumb/ Breadcrumbs}
	 *
	 * @extends sap.ui.core.Control
	 * @implements sap.m.IBreadcrumbs, sap.m.IOverflowToolbarContent, sap.ui.core.IShrinkable
	 *
	 * @author SAP SE
	 * @version ${version}
	 *
	 * @constructor
	 * @public
	 * @since 1.34
	 * @alias sap.m.Breadcrumbs
	 *
	 */
	var Breadcrumbs = Control.extend("sap.m.Breadcrumbs", {
		metadata: {
			library: "sap.m",
			interfaces: [
				"sap.m.IBreadcrumbs",
				"sap.m.IOverflowToolbarContent",
				"sap.ui.core.IShrinkable"
			],
			designtime: "sap/m/designtime/Breadcrumbs.designtime",
			properties: {

				/**
				 * Determines the text of current/last element in the Breadcrumbs path.
				 * @since 1.34
				 */
				currentLocationText: {type: "string", group: "Behavior", defaultValue: null},
				/**
				 * Determines the visual style of the separator between the <code>Breadcrumbs</code> elements.
				 * @since 1.69
				 */
				separatorStyle: {
					type: "sap.m.BreadcrumbsSeparatorStyle",
					group: "Appearance",
					defaultValue: SeparatorStyle.Slash
				}
			},
			aggregations: {

				/**
				 * A list of all the active link elements in the Breadcrumbs control.
				 * <b>Note:</b> Enabling the property <code>wrapping</code> of the link will not work
				 * since it's incompatible with the concept of the control.
				 * The other properties will work, but their effect may be undesirable.
				 * @since 1.34
				 */
				links: {type: "sap.m.Link", multiple: true, singularName: "link"},

				/**
				 * Private aggregations
				 */
				_currentLocation: {type: "sap.m.Text", multiple: false, visibility: "hidden"},
				_select: {type: "sap.m.Select", multiple: false, visibility: "hidden"}
			},
			defaultAggregation: "links",
			associations: {

				/**
				 * Association to controls / IDs which label this control (see WAI-ARIA attribute <code>aria-labelledby</code>).
				 * @since 1.92
				 */
				ariaLabelledBy: {
					type: "sap.ui.core.Control", multiple: true, singularName: "ariaLabelledBy"
				}
			}
		},

		renderer: BreadcrumbsRenderer
	});

	/*
	 * STATIC MEMBERS
	 */

	Breadcrumbs.STYLE_MAPPER = {
		Slash: "/",
		BackSlash: "\\",
		DoubleSlash: "//",
		DoubleBackSlash: "\\\\",
		GreaterThan: ">",
		DoubleGreaterThan: ">>"
	};

	Breadcrumbs._getResourceBundleText = function (sText, vOptions) {
		return oResource.getText(sText, vOptions);
	};

	/*************************************** Framework lifecycle events ******************************************/

	Breadcrumbs.prototype.init = function () {
		this._sSeparatorSymbol = Breadcrumbs.STYLE_MAPPER[this.getSeparatorStyle()];
		this._aCachedInvisibleTexts = [];
		this._getInvisibleText();
	};

	Breadcrumbs.prototype.onBeforeRendering = function () {
		this.bRenderingPhase = true;

		if (this._sResizeListenerId) {
			ResizeHandler.deregister(this._sResizeListenerId);
			this._sResizeListenerId = null;
		}

		if (this._bControlsInfoCached) {
			this._updateSelect(true);
		}

		this._destroyInvisibleTexts();
		this._aCachedInvisibleTexts = this._buildInvisibleTexts();
	};

	Breadcrumbs.prototype.onAfterRendering = function () {
		if (!this._sResizeListenerId) {
			this._sResizeListenerId = ResizeHandler.register(this, this._handleScreenResize.bind(this));
		}

		if (!this._bControlsInfoCached) {
			this._updateSelect(true);
			return;
		}

		this._configureKeyboardHandling();

		this.bRenderingPhase = false;
	};

	Breadcrumbs.prototype.onThemeChanged = function () {
		this._resetControl();
	};

	Breadcrumbs.prototype.exit = function () {
		this._resetControl();
		this._destroyItemNavigation();
		this._destroyInvisibleTexts();

		if (this._oInvisibleText) {
			this._oInvisibleText.destroy();
			this._oInvisibleText = null;
		}
	};

	/*************************************** Static members ******************************************/

	Breadcrumbs.PAGEUP_AND_PAGEDOWN_JUMP_SIZE = 5;

	/*************************************** Internal aggregation handling  ******************************************/

	Breadcrumbs.prototype._getAugmentedId = function (sSuffix) {
		return this.getId() + "-" + sSuffix;
	};


	Breadcrumbs.prototype._getInvisibleText = function() {
		var oAriaLabelText = Breadcrumbs._getResourceBundleText("BREADCRUMB_LABEL");

		if (!this._oInvisibleText) {
			this._oInvisibleText = new InvisibleText({ id: this.getId() + "-InvisibleText"});
			this._oInvisibleText.setText(oAriaLabelText).toStatic();
		}

		return this._oInvisibleText;
	};

	Breadcrumbs.prototype._getSelect = function () {
		if (!this.getAggregation("_select")) {
			this.setAggregation("_select", this._decorateSelect(new Select({
				id: this._getAugmentedId("select"),
				change: this._selectChangeHandler.bind(this),
				forceSelection: false,
				autoAdjustWidth: true,
				icon: IconPool.getIconURI("slim-arrow-down"),
				type: SelectType.IconOnly,
				tooltip: Breadcrumbs._getResourceBundleText("BREADCRUMB_SELECT_TOOLTIP")
			})), true);
		}
		return this.getAggregation("_select");
	};

	Breadcrumbs.prototype._getCurrentLocation = function () {
		if (!this.getAggregation("_currentLocation")) {
			var oCurrentLocation = new Text({
				id: this._getAugmentedId("currentText"),
				text: this.getCurrentLocationText(),
				wrapping: false
			}).addStyleClass("sapMBreadcrumbsCurrentLocation");

			oCurrentLocation.addEventDelegate({
				onAfterRendering: function () {
					this._setCurrentLocationAccInfo(oCurrentLocation);
				}.bind(this)
			});

			this.setAggregation("_currentLocation", oCurrentLocation).addStyleClass("sapMBreadcrumbsCurrentLocation");
		}
		return this.getAggregation("_currentLocation");
	};

	Breadcrumbs.prototype._setCurrentLocationAccInfo = function (oCurrentLocation) {
		var aVisibleItems = this._getControlsForBreadcrumbTrail(),
			positionText = Breadcrumbs._getResourceBundleText("BREADCRUMB_ITEM_POS", [aVisibleItems.length, aVisibleItems.length]);

		oCurrentLocation.$().attr("aria-current", "page");
		oCurrentLocation.$().attr("tabindex", 0);
		oCurrentLocation.$().attr("role", "link");
		oCurrentLocation.$().attr("aria-label", this.getCurrentLocationText() + " " + positionText);
	};

	function fnConvertArguments(sAggregationName, aArguments) {
		var aConvertedArguments = Array.prototype.slice.apply(aArguments);
		aConvertedArguments.unshift(sAggregationName);
		return aConvertedArguments;
	}

	Breadcrumbs.prototype.insertLink = function (oLink, iIndex) {
		var vResult = this.insertAggregation.apply(this, fnConvertArguments("links", arguments));
		this._registerControlListener(oLink);
		this._resetControl();
		return vResult;
	};

	Breadcrumbs.prototype.addLink = function (oLink) {
		var vResult = this.addAggregation.apply(this, fnConvertArguments("links", arguments));
		this._registerControlListener(oLink);
		this._resetControl();
		return vResult;
	};

	Breadcrumbs.prototype.removeLink = function (vObject) {
		var vResult = this.removeAggregation.apply(this, fnConvertArguments("links", arguments));
		this._deregisterControlListener(vResult);
		this._resetControl();
		return vResult;
	};

	Breadcrumbs.prototype.removeAllLinks = function () {
		var aLinks = this.getAggregation("links", []);
		var vResult = this.removeAllAggregation.apply(this, fnConvertArguments("links", arguments));
		aLinks.forEach(this._deregisterControlListener, this);
		this._resetControl();
		return vResult;
	};

	Breadcrumbs.prototype.destroyLinks = function () {
		var aLinks = this.getAggregation("links", []);
		var vResult = this.destroyAggregation.apply(this, fnConvertArguments("links", arguments));
		aLinks.forEach(this._deregisterControlListener, this);
		this._resetControl();
		return vResult;
	};

	Breadcrumbs.prototype._destroyInvisibleTexts = function () {
		var oControl;
		this._aCachedInvisibleTexts.forEach(function (oData) {
			oControl = sap.ui.getCore().byId(oData.controlId);

			// remove reference to the invisible text on the sap.m.Link control
			// check for control existence as it might have been destroyed already
			if (oControl && oControl.removeAriaLabelledBy) {
				oControl.removeAriaLabelledBy(oData.invisibleText.getId());
			}

			oData.invisibleText.destroy();
		});
		this._aCachedInvisibleTexts = [];
	};

	/*************************************** Select Handling ******************************************/

	Breadcrumbs.prototype._decorateSelect = function (oSelect) {
		oSelect.getPicker()
			.attachAfterOpen(this._removeItemNavigation, this)
			.attachBeforeClose(this._restoreItemNavigation, this);

		oSelect._onBeforeOpenDialog = this._onSelectBeforeOpenDialog.bind(this);
		oSelect._onBeforeOpenPopover = this._onSelectBeforeOpenPopover.bind(this);
		oSelect.onsapescape = this._onSelectEscPress.bind(this);

		return oSelect;
	};

	Breadcrumbs.prototype._removeItemNavigation = function () {
		this.removeDelegate(this._getItemNavigation());
	};

	Breadcrumbs.prototype._onSelectBeforeOpenDialog = function () {
		var oSelect = this._getSelect();

		if (this.getCurrentLocationText() && Device.system.phone) {
			oSelect.setSelectedIndex(0);
		} else {
			oSelect.setSelectedItem(null);
		}

		Select.prototype._onBeforeOpenDialog.call(oSelect);
		this._removeItemNavigation();
	};

	Breadcrumbs.prototype._onSelectBeforeOpenPopover = function () {
		this._getSelect().setSelectedItem(null);
		this._removeItemNavigation();
	};

	Breadcrumbs.prototype._restoreItemNavigation = function () {
		this.addDelegate(this._getItemNavigation());
	};

	Breadcrumbs.prototype._onSelectEscPress = function () {
		this._getSelect().close();
	};

	/**
	 * Retrieves selected item item using an sap.m.Link or sap.m.Text
	 *
	 * @param {control} oItem
	 * @returns {sap.ui.core.Item}
	 * @private
	 */
	Breadcrumbs.prototype._createSelectItem = function (oItem) {
		return new Item({
			key: oItem.getId(),
			text: ManagedObject.escapeSettingsValue(oItem.getText())
		});
	};

	/**
	 * Handles the "select" event
	 *
	 * @param {jQuery.Event} oEvent
	 * @private
	 */
	Breadcrumbs.prototype._selectChangeHandler = function (oEvent) {
		var oLink,
			sLinkHref,
			sLinkTarget,
			oSelectedItem = oEvent.getParameter("selectedItem");

		/* there's no selected item, nothing to do in this case (the selected item is often set to null) */
		if (!oSelectedItem) {
			return;
		}

		/* The select change event is fired every time a selection is made, in Icon mode (in which we're using it)
		 the user doesn't see this selection change and we shouldn't act on it */
		if (!this._getSelect().isOpen()) {
			return;
		}

		oLink = sap.ui.getCore().byId(oSelectedItem.getKey());

		/* if it's not a link, then it must be only the current location text, we shouldn't do anything */
		if (!(oLink instanceof Link)) {
			return;
		}

		sLinkHref = oLink.getHref();
		sLinkTarget = oLink.getTarget();

		oLink.firePress();

		if (sLinkHref) {
			if (sLinkTarget) {
				// TODO: take oLink.getRel() value into account ('links' is a public aggregation)
				openWindow(sLinkHref, sLinkTarget);
			} else {
				window.location.href = sLinkHref;
			}
		}
	};

	Breadcrumbs.prototype._getItemsForMobile = function () {
		var oItems = this.getLinks().filter(function (oLink) { return oLink.getVisible(); });

		if (this.getCurrentLocationText()) {
			oItems.push(this._getCurrentLocation());
		}

		return oItems;
	};

	/**
	 * Updates the select with the current "distribution" of controls.
	 *
	 * @private
	 * @param {boolean} bInvalidateDistribution
	 */
	Breadcrumbs.prototype._updateSelect = function (bInvalidateDistribution) {
		var oSelect = this._getSelect(),
			aControlsForSelect,
			oControlsDistribution = this._getControlDistribution();

		if (!this._bControlDistributionCached || bInvalidateDistribution) {
			oSelect.destroyItems();
			aControlsForSelect = Device.system.phone ? this._getItemsForMobile() : oControlsDistribution.aControlsForSelect;
			aControlsForSelect.map(this._createSelectItem).reverse().forEach(oSelect.insertItem, oSelect);
			this._bControlDistributionCached = true;
			this.invalidate(this);
		}

		oSelect.setVisible(!!oControlsDistribution.aControlsForSelect.length);

		if (!this._sResizeListenerId && !this.bRenderingPhase) {
			this._sResizeListenerId = ResizeHandler.register(this, this._handleScreenResize.bind(this));
		}
	};

	Breadcrumbs.prototype._getControlsForBreadcrumbTrail = function () {
		var aVisibleControls;

		if (this._bControlDistributionCached && this._oDistributedControls) {
			return this._oDistributedControls.aControlsForBreadcrumbTrail;
		}

		aVisibleControls = this.getLinks().filter(function (oLink) { return oLink.getVisible(); });

		if (this.getCurrentLocationText()) {
			return aVisibleControls.concat([this._getCurrentLocation()]);
		}
		return aVisibleControls;
	};

	Breadcrumbs.prototype._getControlInfo = function (oControl) {
		return {
			id: oControl.getId(),
			control: oControl,
			width: getElementWidth(oControl.$().parent()),
			bCanOverflow: oControl instanceof Link
		};
	};

	/**
	 * Creates InvisibleText instances for the Link controls in the Breadcrumbs.
	 * Used to add the position and the size of the controls to their ariaLabelledBy association.
	 * An array of objects is returned for the instances to be destroyed on next invalidation with the following properties:
	 * - controlId: the id of the Link to later remove the InvisibleText instance id from the ariaLabelledBy association
	 * - invisibleText: the InvisibleText control itself to be destroyed
	 */
	Breadcrumbs.prototype._buildInvisibleTexts = function() {
		var aVisibleItems = this._getControlsForBreadcrumbTrail(), // all visible links outside the drop-down, including current location
			iItemCount = aVisibleItems.length,
			oInvisibleText,
			oInvisibleTexts = [];

		aVisibleItems.forEach(function(oItem, iIndex) {
			if (!oItem.isA("sap.m.Link")) {
				// only links are relevant for the ariaLabelledBy association
				return;
			}

			oInvisibleText = new InvisibleText({
				text: Breadcrumbs._getResourceBundleText("BREADCRUMB_ITEM_POS", [iIndex + 1, iItemCount])
			}).toStatic();

			if (oItem.getAriaLabelledBy().indexOf(oItem.getId()) === -1) {
				oItem.addAriaLabelledBy(oItem.getId());
			}

			oItem.addAriaLabelledBy(oInvisibleText.getId());
			oInvisibleTexts.push({
				controlId: oItem.getId(),
				invisibleText: oInvisibleText
			});
		});

		return oInvisibleTexts;
	};

	Breadcrumbs.prototype._getControlDistribution = function (iMaxContentSize) {
		iMaxContentSize = iMaxContentSize || this._iContainerSize;
		this._iContainerSize = iMaxContentSize;
		this._oDistributedControls = this._determineControlDistribution(iMaxContentSize);
		return this._oDistributedControls;
	};

	Breadcrumbs.prototype._getSelectWidth = function() {
		return this._getSelect().getVisible() && this._iSelectWidth || 0;
	};

	Breadcrumbs.prototype._determineControlDistribution = function (iMaxContentSize) {
		var index,
			oControlInfo,
			aControlInfo = this._getControlsInfo().aControlInfo,
			iSelectWidth = this._getSelectWidth(),
			aControlsForSelect = [],
			aControlsForBreadcrumbTrail = [],
			iUsedSpace = iSelectWidth; // account for the selectWidth initially;

		// The rightmost controls should go into overflow first, hence iterating the controls in reverse
		for (index = aControlInfo.length - 1; index >= 0; index--) {
			oControlInfo = aControlInfo[index];
			iUsedSpace += oControlInfo.width;

			// put the last item of the array in the breadcrumb trail
			if (aControlInfo.length - 1 === index) {
				aControlsForBreadcrumbTrail.push(oControlInfo.control);
				continue;
			}

			// we've reached the last item and we've not used a select then we will not need to take it into account
			if (index === 0) {
				iUsedSpace -= iSelectWidth;
			}

			if (iUsedSpace > iMaxContentSize && oControlInfo.bCanOverflow) {
				aControlsForSelect.unshift(oControlInfo.control);
			} else {
				aControlsForBreadcrumbTrail.unshift(oControlInfo.control);
			}
		}

		return {
			aControlsForBreadcrumbTrail: aControlsForBreadcrumbTrail,
			aControlsForSelect: aControlsForSelect
		};
	};

	/**
	 * Stores the sizes and other info of controls so they don't need to be recalculated again until they change.
	 * @private
	 * @returns {Object} The <code>Breadcrumbs</code> control information
	 */
	Breadcrumbs.prototype._getControlsInfo = function () {
		if (!this._bControlsInfoCached) {
			this._iSelectWidth = getElementWidth(this._getSelect().$().parent()) || 0;
			this._aControlInfo = this._getControlsForBreadcrumbTrail().map(this._getControlInfo);
			// ceil the container width to prevent unnecessary overflow of a link due to rounding issues
			// (when the available space appears insufficient with less than a pixel
			this._iContainerSize = Math.ceil(getElementWidth(this.$()));
			this._bControlsInfoCached = true;
		}

		return {
			aControlInfo: this._aControlInfo,
			iSelectWidth: this._iSelectWidth,
			iContentSize: this._iContainerSize
		};
	};

	/**
	 * Handles the resize event of the Breadcrumbs control container
	 *
	 * @param {jQuery.Event} oEvent
	 * @returns {this} this
	 * @private
	 */
	Breadcrumbs.prototype._handleScreenResize = function (oEvent) {
		var iCachedControlsForBreadcrumbTrailCount,
			oControlsDistribution,
			iCalculatedControlsForBreadcrumbTrailCount;

		if (oEvent.size.width === oEvent.oldSize.width || oEvent.size.width === 0) {
			return this;
		}

		iCachedControlsForBreadcrumbTrailCount = this._oDistributedControls.aControlsForBreadcrumbTrail.length;
		// ceil the container width to prevent unnecessary overflow of a link due to rounding issues
		// (when the available space appears insufficient with less than a pixel
		oControlsDistribution = this._getControlDistribution(Math.ceil(getElementWidth(this.$())));
		iCalculatedControlsForBreadcrumbTrailCount = oControlsDistribution.aControlsForBreadcrumbTrail.length;

		if (iCachedControlsForBreadcrumbTrailCount !== iCalculatedControlsForBreadcrumbTrailCount) {
			this._updateSelect(true);
		}

		return this;
	};

	/**
	 * Retrieves the items which should be included in navigation.
	 *
	 * @private
	 * @returns {array} aItemsToNavigate
	 */
	Breadcrumbs.prototype._getItemsToNavigate = function () {
		var aItemsToNavigate = this._getControlsForBreadcrumbTrail().slice(),
			oSelect = this._getSelect();

		if (oSelect.getVisible()) {
			aItemsToNavigate.unshift(oSelect);
		}

		return aItemsToNavigate;
	};

	Breadcrumbs.prototype._getItemNavigation = function () {
		if (!this._itemNavigation) {
			this._itemNavigation = new ItemNavigation();
		}

		return this._itemNavigation;
	};

	Breadcrumbs.prototype._destroyItemNavigation = function () {
		if (this._itemNavigation) {
			this.removeEventDelegate(this._itemNavigation);
			this._itemNavigation.destroy();
			this._itemNavigation = null;
		}
	};

	/**
	 * Configures the Keyboard handling for the control
	 *
	 * @private
	 * @returns {object} this
	 */
	Breadcrumbs.prototype._configureKeyboardHandling = function () {
		var oItemNavigation = this._getItemNavigation(),
			iSelectedDomIndex = -1,
			aItemsToNavigate = this._getItemsToNavigate(),
			aNavigationDomRefs = [];

		if (aItemsToNavigate.length === 0) {
			return;
		}

		aItemsToNavigate.forEach(function (oItem, iIndex) {
			if (iIndex === 0) {
				oItem.$().attr("tabindex", "0");
			}
			oItem.$().attr("tabindex", "-1");
			aNavigationDomRefs.push(oItem.getFocusDomRef());
		});

		this.addDelegate(oItemNavigation);
		oItemNavigation.setDisabledModifiers({
			sapnext: ["alt", "meta"],
			sapprevious: ["alt", "meta"],
			saphome : ["alt"],
			sapend : ["alt"]
		});
		oItemNavigation.setCycling(false);
		oItemNavigation.setPageSize(Breadcrumbs.PAGEUP_AND_PAGEDOWN_JUMP_SIZE);
		oItemNavigation.setRootDomRef(this.getDomRef());
		oItemNavigation.setItemDomRefs(aNavigationDomRefs);
		oItemNavigation.setSelectedIndex(iSelectedDomIndex);
		return this;
	};

	/**
	 * Every time a control is inserted in the breadcrumb, it must be monitored for size/visibility changes
	 * @param oControl
	 * @private
	 */
	Breadcrumbs.prototype._registerControlListener = function (oControl) {
		if (oControl) {
			oControl.attachEvent("_change", this._resetControl, this);
		}
	};

	/**
	 * Each time a control is removed from the breadcrumb, detach listeners
	 * @param oControl
	 * @private
	 */
	Breadcrumbs.prototype._deregisterControlListener = function (oControl) {
		if (oControl) {
			oControl.detachEvent("_change", this._resetControl, this);
		}
	};

	Breadcrumbs.prototype.setCurrentLocationText = function (sText) {
		var oCurrentLocation = this._getCurrentLocation(),
			vResult = this.setProperty("currentLocationText", sText, true);

		if (oCurrentLocation.getText() !== sText) {
			oCurrentLocation.setText(sText);
			this._resetControl();
		}

		return vResult;
	};

	/**
	 * Custom setter for the <code>Breadcrumbs</code> separator style.
	 *
	 * @returns {sap.m.Breadcrumbs} this
	 * @param {sap.m.BreadcrumbsSeparatorStyle} sSeparatorStyle
	 * @public
	 * @since 1.71
	 */
	Breadcrumbs.prototype.setSeparatorStyle = function (sSeparatorStyle) {
		this.setProperty("separatorStyle", sSeparatorStyle);
		var sSeparatorSymbol = Breadcrumbs.STYLE_MAPPER[this.getSeparatorStyle()];
		if (sSeparatorSymbol){
			this._sSeparatorSymbol = sSeparatorSymbol;
		}
		return this;
	};

	/**
	 * Resets all of the internally cached values used by the control and invalidates it
	 *
	 * @returns {object} this
	 * @private
	 */
	Breadcrumbs.prototype._resetControl = function () {
		this._aControlInfo = null;
		this._iContainerSize = null;
		this._bControlsInfoCached = null;
		this._bControlDistributionCached = null;
		this._oDistributedControls = null;

		if (this._sResizeListenerId) {
			ResizeHandler.deregister(this._sResizeListenerId);
			this._sResizeListenerId = null;
		}

		this.removeDelegate(this._getItemNavigation());
		this.invalidate(this);
		return this;
	};

	/**
	 * Required by the {@link sap.m.IOverflowToolbarContent} interface.
	 * Registers invalidation event which is fired when width of the control is changed.
	 *
	 * @returns {object} Configuration information for the <code>sap.m.IOverflowToolbarContent</code> interface.
	 *
	 * @private
	 * @ui5-restricted sap.m.OverflowToolBar
	 */
	Breadcrumbs.prototype.getOverflowToolbarConfig = function() {
		var oConfig = {
			canOverflow: true,
			getCustomImportance: function () {
				return "Medium";
			}
		};

		return oConfig;
	};

	// helper functions
	function getElementWidth($element) {
		var iMargins;
		if ($element.length) {
			iMargins = $element.outerWidth(true) - $element.outerWidth();

			return $element.get(0).getBoundingClientRect().width + iMargins;
		}
	}

	return Breadcrumbs;

});
