<?php
/**
 * Condition Operator Trait
 *
 * @link       https://personalizewp.com/
 * @since      3.2.0 Merged into PWP
 * @since      2.3.0
 *
 * @package    PersonalizeWP
 * @subpackage PersonalizeWP/Traits
 */

namespace PersonalizeWP\Traits;

/**
 * Condition Operator Trait
 *
 * This trait is used by Segments and Scoring Rules to allow multiple conditions to be evaluated.
 *
 * @since 3.2.0
 */
trait Condition_Operator_Trait {

	/**
	 * Default operator, used when multiple conditions are evaluated.
	 *
	 * @since 2.3.0
	 *
	 * @var string
	 */
	protected static $default_operator = 'ANY';

	/**
	 * Test condition against items' criteria.
	 *
	 * @since 2.3.0
	 *
	 * @param array $args {
	 *     Array of args to use for matching the condition. Often overloaded with additional params.
	 *
	 *     @type Activity $activity   Activity object
	 *     @type mixed    $condition  Raw condition key from database
	 *     @type mixed    $options    Additional condition options, optional
	 * }
	 *
	 * @return boolean
	 */
	abstract protected function condition_has_matched_criteria( $args );

	/**
	 * Loop through conditions, check if Activity matches - used when deciding if an item is to be applied or not.
	 *
	 * @since 2.3.0
	 *
	 * @param array $args {
	 *     Array of args for matching an activity against a series of conditions. Passes through additional args it has been called with.
	 *
	 *     @type Activity $activity   Activity object - Unused
	 *     @type array    $conditions Array of conditions to match
	 *     @type string   $operator   Operator to use when multiple conditions are set. Default 'ANY'
	 * }
	 *
	 * @return boolean
	 */
	protected function activity_has_matched_conditions( $args ) {

		$args = wp_parse_args( $args, [ 'operator' => self::$default_operator ] );
		list( 'conditions' => $conditions, 'operator' => $operator ) = $args;
		unset( $args['conditions'] ); // Reusing the main args and passing onto the arguments below.

		foreach ( $conditions as $condition => $opts ) {
			$match_args = [
				'condition' => $condition,
				'options'   => $opts,
			];
			// Combine with whatever arguments the parent call might have added.
			$match_args = array_merge( $args, $match_args );

			$matched = $this->condition_has_matched_criteria( $match_args );
			switch ( $operator ) {
				case 'ALL':
					// Require all conditions to match, so a single failure causes no match.
					if ( ! $matched ) {
						return false;
					}
					break;

				default:
				case 'ANY':
					// Require any condition to match, so a single success triggers true.
					if ( $matched ) {
						return true;
					}
					break;
			}
		}

		switch ( $operator ) {
			case 'ALL':
				// Required all conditions to match, no failures above must indicate a success.
				return true;

			default:
			case 'ANY':
				// Required any condition to match, no matches above must indicate a failure.
				return false;
		}
	}
}
