/*!
 * OpenUI5
 * (c) Copyright 2009-2026 SAP SE or an SAP affiliate company.
 * Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
 */
/*eslint-disable max-len */
// Provides object sap.ui.model.odata.AnnotationHelper
sap.ui.define([
	"./_AnnotationHelperBasics",
	"./_AnnotationHelperExpression",
	"sap/base/Log",
	"sap/ui/base/BindingParser"
], function (Basics, Expression, Log, BindingParser) {
		'use strict';

		/**
		 * Returns a function representing the composition <code>fnAfter</code> after
		 * <code>fnBefore</code>.
		 *
		 * @param {function} fnAfter
		 *   the second function, taking a single argument
		 * @param {function} fnBefore
		 *   the first function, taking multiple arguments
		 * @returns {function}
		 *   the composition <code>fnAfter</code> after <code>fnBefore</code>
		 */
		function chain(fnAfter, fnBefore) {
			return function () {
				return fnAfter.call(this, fnBefore.apply(this, arguments));
			};
		}

		/**
		 * @classdesc
		 * A collection of methods which help to consume
		 * <a href="http://docs.oasis-open.org/odata/odata/v4.0/odata-v4.0-part3-csdl.html">
		 * OData V4 annotations</a> in XML template views. Every context argument must belong to a
		 * <code>sap.ui.model.odata.ODataMetaModel</code> instance.
		 *
		 * Formatter functions like {@link #.format format} and {@link #.simplePath simplePath} can
		 * be used in complex bindings to turn OData V4 annotations into texts or data bindings,
		 * e.g. <code>&lt;sfi:SmartField value="{path : 'meta>Value', formatter :
		 * 'sap.ui.model.odata.AnnotationHelper.simplePath'}"/></code>.
		 *
		 * Helper functions like {@link #.resolvePath resolvePath} can be used by template
		 * instructions in XML template views, e.g. <code>&lt;template:with path="meta>Value"
		 * helper="sap.ui.model.odata.AnnotationHelper.resolvePath" var="target"></code>.
		 *
		 * Since 1.31.0, you DO NOT need to {@link sap.ui.require} this module before use.
		 *
		 * @public
		 * @since 1.27.0
		 * @namespace
		 * @alias sap.ui.model.odata.AnnotationHelper
		 */
		var AnnotationHelper = {
			/**
			 * Creates a property setting (which is either a constant value or a binding info
			 * object) from the given parts and from the optional root formatter function.
			 * Each part can have one of the following types:
			 * <ul>
			 *   <li><code>boolean</code>, <code>number</code>, <code>undefined</code>: The part is
			 *   a constant value.
			 *
			 *   <li><code>string</code>: The part is a data binding expression with complex
			 *   binding syntax (for example, as created by {@link #.format format}) and is parsed
			 *   accordingly to create either a constant value or a binding info object. Proper
			 *   backslash escaping must be used for constant values with curly braces.
			 *
			 *   <li><code>object</code>: The part is a binding info object if it has a "path" or
			 *   "parts" property, otherwise it is a constant value.
			 * </ul>
			 * If a binding info object is not the only part and has a "parts" property itself,
			 * then it must have no other properties except "formatter"; this is the case for
			 * expression bindings and data binding expressions created by {@link #.format format}.
			 *
			 * If all parts are constant values, the resulting property setting is also a constant
			 * value computed by applying the root formatter function to the constant parts once.
			 * If at least one part is a binding info object, the resulting property setting is
			 * also a binding info object and the root formatter function will be applied again and
			 * again to the current values of all parts, no matter whether constant or variable.
			 *
			 * Note: The root formatter function should not rely on its <code>this</code> value
			 * because it depends on how the function is called.
			 *
			 * Note: A single data binding expression can be given directly to
			 * {@link sap.ui.base.ManagedObject#applySettings applySettings}, no need to call this
			 * function first.
			 *
			 * Example:
			 * <pre>
			 * function myRootFormatter(oValue1, oValue2, sFullName, sGreeting, iAnswer) {
			 *     return ...;
			 * }
			 *
			 * oSupplierContext = oMetaModel.getMetaContext("/ProductSet('HT-1021')/ToSupplier");
			 * oValueContext = oMetaModel.createBindingContext("com.sap.vocabularies.UI.v1.DataPoint/Value", oSupplierContext);
			 *
			 * vPropertySetting =  sap.ui.model.odata.AnnotationHelper.createPropertySetting([
			 *     sap.ui.model.odata.AnnotationHelper.format(oValueContext),
			 *     "{path : 'meta>Value', formatter : 'sap.ui.model.odata.AnnotationHelper.simplePath'}",
			 *     "{:= 'Mr. ' + ${/FirstName} + ' ' + ${/LastName}}",
			 *     "hello, world!",
			 *     42
			 * ], myRootFormatter);
			 *
			 * oControl.applySettings({"someProperty" : vPropertySetting});
			 * </pre>
			 *
			 * @param {any[]} aParts
			 *   array of parts
			 * @param {function} [fnRootFormatter]
			 *   root formatter function; default: <code>Array.prototype.join(., " ")</code>
			 *   in case of multiple parts, just like
			 *   {@link sap.ui.model.CompositeBinding#getExternalValue getExternalValue}
			 * @returns {any|object}
			 *   constant value or binding info object for a property as expected by
			 *   {@link sap.ui.base.ManagedObject#applySettings applySettings}
			 * @throws {Error}
			 *   if some part has an unsupported type or refers to a function name which is not
			 *   found
			 * @public
			 * @since 1.31.0
			 */
			createPropertySetting : function (aParts, fnRootFormatter) {
				var bMergeNeeded = false,
					vPropertySetting;

				aParts = aParts.slice(); // shallow copy to avoid changes visible to caller
				aParts.forEach(function (vPart, i) {
					switch (typeof vPart) {
						case "boolean":
						case "number":
						case "undefined":
							bMergeNeeded = true;
							break;

						case "string":
							vPropertySetting = BindingParser.complexParser(vPart, null, true, true);
							if (vPropertySetting !== undefined) {
								if (vPropertySetting.functionsNotFound) {
									throw new Error("Function name(s) "
										+ vPropertySetting.functionsNotFound.join(", ")
										+  " not found");
								}
								aParts[i] = vPart = vPropertySetting;
							}
							// falls through
						case "object":
							// merge is needed if some parts are constants or again have parts
							// Note: a binding info object has either "path" or "parts"
							if (!vPart || typeof vPart !== "object" || !("path" in vPart)) {
								bMergeNeeded = true;
							}
							break;

						default:
							throw new Error("Unsupported part: " + vPart);
					}
				});

				vPropertySetting = {
					formatter : fnRootFormatter,
					parts : aParts
				};
				if (bMergeNeeded) {
					BindingParser.mergeParts(vPropertySetting);
				}
				fnRootFormatter = vPropertySetting.formatter; // may have changed due to merge

				if (vPropertySetting.parts.length === 0) {
					// special case: all parts are constant values, call formatter once
					vPropertySetting = fnRootFormatter && fnRootFormatter();
					if (typeof vPropertySetting === "string") {
						vPropertySetting = BindingParser.complexParser.escape(vPropertySetting);
					}
				} else if (vPropertySetting.parts.length === 1) {
					// special case: a single property setting only
					// Note: sap.ui.base.ManagedObject#_bindProperty cannot handle the single-part
					//       case with two formatters, unless the root formatter is marked with
					//       "textFragments". Unpacking the single part does not work in case it has
					//       a type! We do not unpack here, but chain the formatters ourselves.
					// Note: we prefer a root formatter because it has access to "this" and has an
					//       influence on the binding mode (OneTime/OneWay)
					if (fnRootFormatter && !fnRootFormatter.textFragments
							&& vPropertySetting.parts[0].formatter) {
						vPropertySetting.formatter
							= chain(fnRootFormatter, vPropertySetting.parts[0].formatter);
						// avoid changes visible to caller
						vPropertySetting.parts[0] = Object.assign({}, vPropertySetting.parts[0]);
						delete vPropertySetting.parts[0].formatter;
					}
				}

				return vPropertySetting;
			},

			/**
			 * A formatter function to be used in a complex binding inside an XML template view
			 * in order to interpret OData V4 annotations. It knows about
			 * <ul>
			 *   <li> the "14.4 Constant Expressions" for "edm:Bool", "edm:Date",
			 *   "edm:DateTimeOffset", "edm:Decimal", "edm:Float", "edm:Guid", "edm:Int",
			 *   "edm:TimeOfDay".
			 *   <li> the constant "14.4.11 Expression edm:String": This is turned into a fixed
			 *   text (e.g. <code>"Width"</code>) or into a data binding expression (e.g. <code>
			 *   "{/##/dataServices/schema/0/entityType/1/com.sap.vocabularies.UI.v1.FieldGroup#Dimensions/Data/0/Label/String}"
			 *   </code>). Data binding expressions are used in case XML template processing has
			 *   been started with the setting <code>bindTexts : true</code>. The purpose is to
			 *   reference translatable texts from OData V4 annotations, especially for XML
			 *   template processing at design time. Since 1.31.0, string constants that contain a
			 *   simple binding <code>"{@i18n>...}"</code> to the hard-coded model name "@i18n"
			 *   with arbitrary path are not turned into a fixed text, but kept as a data binding
			 *   expression; this allows local annotation files to refer to a resource bundle for
			 *   internationalization.
			 *   <li> the dynamic "14.5.1 Comparison and Logical Operators": These are turned into
			 *   expression bindings to perform the operations at run-time. It's strongly
			 *   recommended to require the <code>sap.ui.model.odata.v4.ODataUtils</code> module in
			 *   advance to avoid synchronous loading of this module.
			 *   <li> the dynamic "14.5.3 Expression edm:Apply":
			 *   <ul>
			 *     <li> "14.5.3.1.1 Function odata.concat": This is turned into a data binding
			 *     expression relative to an entity.
			 *     <li> "14.5.3.1.2 Function odata.fillUriTemplate": This is turned into an
			 *     expression binding to fill the template at run-time. It's strongly
			 *     recommended to require the <code>sap.ui.thirdparty.URITemplate</code> module in
			 *     advance to avoid synchronous loading of this module.
			 *     <li> "14.5.3.1.3 Function odata.uriEncode": This is turned into an expression
			 *     binding to encode the parameter at run-time. It's strongly recommended to require
			 *     the <code>sap.ui.model.odata.ODataUtils</code> module in advance to avoid
			 *     synchronous loading of this module.
			 *     <li> Apply functions may be nested arbitrarily.
			 *   </ul>
			 *   <li> the dynamic "14.5.6 Expression edm:If": This is turned into an expression
			 *   binding to be evaluated at run-time. The expression is a conditional expression
			 *   like <code>"{=condition ? expression1 : expression2}"</code>.
			 *   <li> the dynamic "14.5.10 Expression edm:Null": This is turned into a
			 *   <code>null</code> value. In <code>odata.concat</code> it is ignored.
			 *   <li> the dynamic "14.5.12 Expression edm:Path" and "14.5.13 Expression
			 *   edm:PropertyPath": This is turned into a data binding relative to an entity,
			 *   including type information and constraints as available from metadata,
			 *   e.g. <code>"{path : 'Name', type : 'sap.ui.model.odata.type.String',
			 *   constraints : {'maxLength':'255'}}"</code>.
			 *   Depending on the used type, some additional constraints of this type are set:
			 *   <ul>
			 *     <li>Edm.DateTime: The "displayFormat" constraint is set to the value of the
			 *     "sap:display-format" annotation of the referenced property.
			 *     <li>Edm.Decimal: The "precision" and "scale" constraints are set to the values
			 *     of the corresponding attributes of the referenced property. The "minimum",
			 *     "maximum", "minimumExclusive" and "maximumExlusive" constraints are set to the
			 *     values of the corresponding "Org.OData.Validation.V1" annotation of the
			 *     referenced property; note that in this case only constant expressions are
			 *     supported to determine the annotation value.
			 *     <li>Edm.String: The "maxLength" constraint is set to the value of the
			 *     corresponding attribute of the referenced property and the "isDigitSequence"
			 *     constraint is set to the value of the
			 *     "com.sap.vocabularies.Common.v1.IsDigitSequence" annotation of the referenced
			 *     property; note that in this case only constant expressions are supported to
			 *     determine the annotation value.
			 *   </ul>
			 * </ul>
			 * Unsupported or incorrect values are turned into a string nevertheless, but indicated
			 * as such. Proper escaping is used to make sure that data binding syntax is not
			 * corrupted. An error describing the problem is logged to the console in such a case.
			 *
			 * Example:
			 * <pre>
			 * &lt;Text text="{path: 'meta>Value', formatter: 'sap.ui.model.odata.AnnotationHelper.format'}" />
			 * </pre>
			 *
			 * @param {sap.ui.core.util.XMLPreprocessor.IContext|sap.ui.model.Context} oInterface
			 *   the callback interface related to the current formatter call
			 * @param {any} [vRawValue]
			 *   the raw value from the meta model, which is embedded within an entity set or
			 *   entity type:
			 *   <ul>
			 *   <li>if this function is used as formatter the value
			 *   is provided by the framework</li>
			 *   <li>if this function is called directly, provide the parameter only if it is
			 *   already calculated</li>
			 *   <li>if the parameter is omitted, it is calculated automatically through
			 *   <code>oInterface.getObject("")</code></li>
			 *   </ul>
			 * @returns {string}
			 *   the resulting string value to write into the processed XML
			 * @public
			 */
			format : function (oInterface, vRawValue) {
				if (arguments.length === 1) {
					vRawValue = oInterface.getObject("");
				}
				return Expression.getExpression(oInterface, vRawValue, true);
			},

			/**
			 * A formatter function to be used in a complex binding inside an XML template view
			 * in order to interpret OData V4 annotations. It knows about the following dynamic
			 * expressions:
			 * <ul>
			 * <li>"14.5.2 Expression edm:AnnotationPath"</li>
			 * <li>"14.5.11 Expression edm:NavigationPropertyPath"</li>
			 * <li>"14.5.12 Expression edm:Path"</li>
			 * <li>"14.5.13 Expression edm:PropertyPath"</li>
			 * </ul>
			 * It returns a binding expression for a navigation path in an OData model, starting at
			 * an entity.
			 * Currently supports navigation properties. Term casts and annotations of
			 * navigation properties terminate the navigation path.
			 *
			 * Examples:
			 * <pre>
			 * &lt;template:if test="{path: 'facet>Target', formatter: 'sap.ui.model.odata.AnnotationHelper.getNavigationPath'}">
			 *     &lt;form:SimpleForm binding="{path: 'facet>Target', formatter: 'sap.ui.model.odata.AnnotationHelper.getNavigationPath'}" />
			 * &lt;/template:if>
			 * </pre>
			 *
			 * @param {sap.ui.core.util.XMLPreprocessor.IContext|sap.ui.model.Context} oInterface
			 *   the callback interface related to the current formatter call
			 * @param {any} [vRawValue]
			 *   the raw value from the meta model, e.g. <code>{AnnotationPath :
			 *   "ToSupplier/@com.sap.vocabularies.Communication.v1.Address"}</code> or <code>
			 *   {AnnotationPath : "@com.sap.vocabularies.UI.v1.FieldGroup#Dimensions"}</code>;
			 *   embedded within an entity set or entity type;
			 *   <ul>
			 *   <li>if this function is used as formatter the value
			 *   is provided by the framework</li>
			 *   <li>if this function is called directly, provide the parameter only if it is
			 *   already calculated</li>
			 *   <li>if the parameter is omitted, it is calculated automatically through
			 *   <code>oInterface.getObject("")</code></li>
			 *   </ul>
			 * @returns {string}
			 *   the resulting string value to write into the processed XML, e.g. "{ToSupplier}"
			 *   or "{}" (in case no navigation is needed); returns "" in case the navigation path
			 *   cannot be determined (this is treated as falsy in <code>template:if</code>
			 *   statements!)
			 * @public
			 */
			getNavigationPath : function (oInterface, vRawValue) {
				if (arguments.length === 1) {
					vRawValue = oInterface.getObject("");
				}
				var oResult = Basics.followPath(oInterface, vRawValue);

				return oResult
					? "{" + oResult.navigationProperties.join("/") + "}"
					: "";
			},

			/**
			 * Helper function for a <code>template:with</code> instruction that depending on how
			 * it is called goes to the entity set with the given name or to the one determined
			 * by the last navigation property. Supports the following dynamic expressions:
			 * <ul>
			 * <li>"14.5.2 Expression edm:AnnotationPath"</li>
			 * <li>"14.5.11 Expression edm:NavigationPropertyPath"</li>
			 * <li>"14.5.12 Expression edm:Path"</li>
			 * <li>"14.5.13 Expression edm:PropertyPath"</li>
			 * </ul>
			 *
			 * Example:
			 * <pre>
			 *   &lt;template:with path="facet>Target" helper="sap.ui.model.odata.AnnotationHelper.gotoEntitySet" var="entitySet"/>
			 *   &lt;template:with path="associationSetEnd>entitySet" helper="sap.ui.model.odata.AnnotationHelper.gotoEntitySet" var="entitySet"/>
			 * </pre>
			 *
			 * @param {sap.ui.model.Context} oContext
			 *   a context which must point to a simple string or to an annotation (or annotation
			 *   property) of type <code>Edm.AnnotationPath</code>,
			 *   <code>Edm.NavigationPropertyPath</code>, <code>Edm.Path</code>, or
			 *   <code>Edm.PropertyPath</code> embedded within an entity set or entity type;
			 *   the context's model must be an {@link sap.ui.model.odata.ODataMetaModel}
			 * @returns {string|undefined}
			 *   the path to the entity set, or <code>undefined</code> if no such set is found. In
			 *   this case, a warning is logged to the console.
			 * @public
			 */
			gotoEntitySet : function (oContext) {
				var sEntitySet,
					sEntitySetPath,
					vRawValue = oContext.getObject(),
					oResult;

				if (typeof vRawValue === "string") {
					sEntitySet = vRawValue;
				} else {
					oResult = Basics.followPath(oContext, vRawValue);
					sEntitySet = oResult
						&& oResult.associationSetEnd
						&& oResult.associationSetEnd.entitySet;
				}

				if (sEntitySet) {
					sEntitySetPath = oContext.getModel().getODataEntitySet(sEntitySet, true);
				}

				if (!sEntitySetPath) {
					Log.warning(oContext.getPath() + ": found '" + sEntitySet
						+ "' which is not a name of an entity set", undefined,
						"sap.ui.model.odata.AnnotationHelper");
				}

				return sEntitySetPath;
			},

			/**
			 * Helper function for a <code>template:with</code> instruction that goes to the
			 * entity type with the qualified name which <code>oContext</code> points at.
			 *
			 * Example: Assume that "entitySet" refers to an entity set within an OData meta model;
			 * the helper function is then called on the "entityType" property of that entity set
			 * (which holds the qualified name of the entity type) and in turn the path of that
			 * entity type is assigned to the variable "entityType".
			 * <pre>
			 *   &lt;template:with path="entitySet>entityType" helper="sap.ui.model.odata.AnnotationHelper.gotoEntityType" var="entityType">
			 * </pre>
			 *
			 * @param {sap.ui.model.Context} oContext
			 *   a context which must point to the qualified name of an entity type;
			 *   the context's model must be an {@link sap.ui.model.odata.ODataMetaModel}
			 * @returns {string|undefined}
			 *   the path to the entity type with the given qualified name,
			 *   or <code>undefined</code> if no such type is found. In this case, a warning is
			 *   logged to the console.
			 * @public
			 */
			gotoEntityType : function (oContext) {
				var sEntityType = oContext.getProperty(""),
					oResult = oContext.getModel().getODataEntityType(sEntityType, true);

				if (!oResult) {
					Log.warning(oContext.getPath() + ": found '" + sEntityType
						+ "' which is not a name of an entity type", undefined,
						"sap.ui.model.odata.AnnotationHelper");
				}

				return oResult;
			},

			/**
			 * Helper function for a <code>template:with</code> instruction that goes to the
			 * function import with the name which <code>oContext</code> points at.
			 *
			 * Example: Assume that "dataField" refers to a DataFieldForAction within an
			 * OData meta model;
			 * the helper function is then called on the "Action" property of that data field
			 * (which holds an object with the qualified name of the function import in the
			 * <code>String</code> property) and in turn the path of that function import
			 * is assigned to the variable "function".
			 * <pre>
			 *   &lt;template:with path="dataField>Action"
			 *   helper="sap.ui.model.odata.AnnotationHelper.gotoFunctionImport" var="function">
			 * </pre>
			 * @param {sap.ui.model.Context} oContext
			 *   a context which must point to an object with a <code>String</code> property, which
			 *   holds the qualified name of the function import;
			 *   the context's model must be an {@link sap.ui.model.odata.ODataMetaModel}
			 * @returns {string|undefined}
			 *   the path to the function import with the given qualified name,
			 *   or <code>undefined</code> if no function import is found. In this case, a warning
			 *   is logged to the console.
			 * @since 1.29.1
			 * @public
			 */
			gotoFunctionImport : function (oContext) {
				var sFunctionImport = oContext.getProperty("String"),
					oResult = oContext.getModel().getODataFunctionImport(sFunctionImport, true);

				if (!oResult) {
					Log.warning(oContext.getPath() + ": found '" + sFunctionImport
						+ "' which is not a name of a function import", undefined,
						"sap.ui.model.odata.AnnotationHelper");
				}

				return oResult;
			},

			/**
			 * A formatter function to be used in a complex binding inside an XML template view
			 * in order to interpret OData V4 annotations. It knows about the following dynamic
			 * expressions:
			 * <ul>
			 * <li>"14.5.2 Expression edm:AnnotationPath"</li>
			 * <li>"14.5.11 Expression edm:NavigationPropertyPath"</li>
			 * <li>"14.5.12 Expression edm:Path"</li>
			 * <li>"14.5.13 Expression edm:PropertyPath"</li>
			 * </ul>
			 * It returns the information whether the navigation path ends with an association end
			 * with multiplicity "*". It throws an error if the navigation path has an association
			 * end with multiplicity "*" which is not the last one.
			 * Currently supports navigation properties. Term casts and annotations of
			 * navigation properties terminate the navigation path.
			 *
			 * Examples:
			 * <pre>
			 * &lt;template:if test="{path: 'facet>Target', formatter: 'sap.ui.model.odata.AnnotationHelper.isMultiple'}">
			 * </pre>
			 *
			 * @param {sap.ui.core.util.XMLPreprocessor.IContext|sap.ui.model.Context} oInterface
			 *   the callback interface related to the current formatter call
			 * @param {any} [vRawValue]
			 *   the raw value from the meta model, e.g. <code>{AnnotationPath :
			 *   "ToSupplier/@com.sap.vocabularies.Communication.v1.Address"}</code> or <code>
			 *   {AnnotationPath : "@com.sap.vocabularies.UI.v1.FieldGroup#Dimensions"}</code>;
			 *   embedded within an entity set or entity type;
			 *   <ul>
			 *   <li>if this function is used as formatter the value
			 *   is provided by the framework</li>
			 *   <li>if this function is called directly, provide the parameter only if it is
			 *   already calculated</li>
			 *   <li>if the parameter is omitted, it is calculated automatically through
			 *   <code>oInterface.getObject("")</code></li>
			 *   </ul>
			 * @returns {string}
			 *    <code>"true"</code> if the navigation path ends with an association end with
			 *    multiplicity "*", <code>""</code> in case the navigation path cannot be
			 *    determined, <code>"false"</code> otherwise (the latter are both treated as falsy
			 *    in <code>template:if</code> statements!)
			 * @throws {Error}
			 *   if the navigation path has an association end with multiplicity "*" which is not
			 *   the last one
			 * @public
			 */
			isMultiple : function (oInterface, vRawValue) {
				if (arguments.length === 1) {
					vRawValue = oInterface.getObject("");
				}
				var oResult = Basics.followPath(oInterface, vRawValue);

				if (oResult) {
					if (oResult.navigationAfterMultiple) {
						throw new Error(
							'Association end with multiplicity "*" is not the last one: '
							+ vRawValue.AnnotationPath);
					}
					return String(oResult.isMultiple);
				}
				return "";
			},

			/**
			 * Helper function for a <code>template:with</code> instruction that resolves a dynamic
			 * "14.5.2 Expression edm:AnnotationPath",
			 * "14.5.11 Expression edm:NavigationPropertyPath", "14.5.12 Expression edm:Path" or
			 * "14.5.13 Expression edm:PropertyPath".
			 * Currently supports navigation properties and term casts.
			 *
			 * Example:
			 * <pre>
			 *   &lt;template:with path="meta>Value" helper="sap.ui.model.odata.AnnotationHelper.resolvePath" var="target">
			 * </pre>
			 *
			 * @param {sap.ui.model.Context} oContext
			 *   a context which must point to an annotation or annotation property of type
			 *   <code>Edm.AnnotationPath</code>, <code>Edm.NavigationPropertyPath</code>,
			 *   <code>Edm.Path</code> or <code>Edm.PropertyPath</code>, embedded within an entity
			 *   set or entity type;
			 *   the context's model must be an {@link sap.ui.model.odata.ODataMetaModel}
			 * @returns {string|undefined}
			 *   the path to the target, or <code>undefined</code> in case the path cannot be
			 *   resolved. In this case, a warning is logged to the console.
			 * @public
			 */
			resolvePath : function (oContext) {
				var oResult = Basics.followPath(oContext, oContext.getObject());

				if (!oResult) {
					Log.warning(oContext.getPath() + ": Path could not be resolved ",
						undefined, "sap.ui.model.odata.AnnotationHelper");
				}

				return oResult
					? oResult.resolvedPath
					: undefined;
			},

			/**
			 * Formatter function that is used in a complex binding inside an XML template view.
			 * The function is used to interpret OData V4 annotations, supporting the same
			 * annotations as {@link #.format format} but with a simplified output aimed at
			 * design-time templating with smart controls.
			 *
			 * In contrast to <code>format</code>, "14.5.12 Expression edm:Path" or
			 * "14.5.13 Expression edm:PropertyPath" is turned into a simple binding path without
			 * type or constraint information. In certain cases, a complex binding is required to
			 * allow for proper escaping of the path.
			 *
			 * Example:
			 * <pre>
			 *   &lt;sfi:SmartField value="{path: 'meta>Value', formatter: 'sap.ui.model.odata.AnnotationHelper.simplePath'}"/>
			 * </pre>
			 *
			 * @param {sap.ui.core.util.XMLPreprocessor.IContext|sap.ui.model.Context} oInterface
			 *   the callback interface related to the current formatter call
			 * @param {any} [vRawValue]
			 *   the raw value from the meta model, which is embedded within an entity set or
			 *   entity type:
			 *   <ul>
			 *   <li>if this function is used as formatter the value
			 *   is provided by the framework</li>
			 *   <li>if this function is called directly, provide the parameter only if it is
			 *   already calculated</li>
			 *   <li>if the parameter is omitted, it is calculated automatically through
			 *   <code>oInterface.getObject("")</code></li>
			 *   </ul>
			 * @returns {string}
			 *   the resulting string value to write into the processed XML
			 * @public
			 */
			simplePath : function (oInterface, vRawValue) {
				if (arguments.length === 1) {
					vRawValue = oInterface.getObject("");
				}
				return Expression.getExpression(oInterface, vRawValue, false);
			}
		};

		// BEWARE: keep this in sync with sap/ui/core/library.js!
		AnnotationHelper.format.requiresIContext = true;
		AnnotationHelper.getNavigationPath.requiresIContext = true;
		AnnotationHelper.isMultiple.requiresIContext = true;
		AnnotationHelper.simplePath.requiresIContext = true;

		return AnnotationHelper;
	}, /* bExport= */ true);