/*!
 * OpenUI5
 * (c) Copyright 2009-2026 SAP SE or an SAP affiliate company.
 * Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
 */

sap.ui.define([
	"sap/base/Log",
	"sap/base/strings/capitalize",
	"sap/base/util/each",
	"sap/base/util/isPlainObject"
], function (Log, capitalize, each, isPlainObject) {
	"use strict";
	var oLogger = Log.getLogger("sap.ui.test.matchers.Properties");

	/**
	 * @class
	 * Checks if a control's properties have the provided values - all properties have to match their values.
	 *
	 * As of version 1.72, it is available as a declarative matcher with the following syntax:
	 * <code><pre>{
	 *     properties: {
	 *         propertyName: "propertyValue"
	 *     }
	 * }
	 * </pre></code>
	 * As of version 1.74, you can use regular expressions in declarative syntax:
	 * <code><pre>{
	 *     properties: {
	 *         propertyName: {
	 *             regex: {
	 *                 source: "propertyValue$",
	 *                 flags: "ig"
	 *             }
	 *         }
	 *     }
	 * }
	 * </pre></code>
	 * @param {object} oProperties the object with the properties to be checked. Example:
	 * <pre>
	 * // Would filter for an enabled control with the text "Accept".
	 * new Properties({
	 *     // The property text has the exact value "Accept"
	 *     text: "Accept",
	 *     // The property enabled also has to be true
	 *     enabled: true
	 * })
	 * </pre>
	 * If the value is a RegExp, it tests the RegExp with the value. RegExp only works with string properties.
	 * @public
	 * @name sap.ui.test.matchers.Properties
	 * @author SAP SE
	 * @since 1.27
	 */

	return function (oProperties) {
		return function (oControl) {
			var bIsMatching = true;

			each(oProperties, function (sPropertyName, oPropertyValue) {
				var fnProperty = oControl["get" + capitalize(sPropertyName, 0)];

				if (!fnProperty) {
					bIsMatching = false;
					oLogger.error("Control '" + oControl + "' does not have a property '" + sPropertyName + "'");
					return false;
				}

				var vCurrentPropertyValue = fnProperty.call(oControl);
				// propertyValue is set in parent frame (on matcher instantiation), so match it against the parent's RegExp constructor
				if (oPropertyValue instanceof RegExp) {
					bIsMatching = oPropertyValue.test(vCurrentPropertyValue);
				} else if (isPlainObject(oPropertyValue) && oPropertyValue.regex && oPropertyValue.regex.source) {
					// declarative syntax
					var oRegExp = new RegExp(oPropertyValue.regex.source, oPropertyValue.regex.flags);
					bIsMatching = oRegExp.test(vCurrentPropertyValue);
				} else {
					bIsMatching = vCurrentPropertyValue === oPropertyValue;
				}

				if (!bIsMatching) {
					oLogger.debug("Control '" + oControl + "' property '" + sPropertyName +
						"' has value '" + vCurrentPropertyValue + "' but should have value '" + oPropertyValue + "'");
					return false;
				}
			});

			return bIsMatching;
		};
	};

}, /* bExport= */ true);