<?php
/**
 * FANCIFY Filters extend WordPress Filters by registering sub filters if they are told to do so.
 *
 * @package SplendorStudio\Framework\API\Filters
 */
final class Fancify_Lite_Filters extends Fancify_Lite_Model {
		
	/**
	 * Constructor
	 *
	 * @since    1.0.0
	 */
	protected function __construct() {}

	/**
	 * Register callbacks for actions and filters
	 *
	 * @since    1.0.0
	 */
	protected function register_hook_callbacks() {}

	/**
	 * Hooks a callback (function or method) to a specific filter event.
	 *
	 * @since 1.0.0
	 *
	 * @param string         $hook              The name of the filter event to which the callback is hooked.
	 * @param callable|mixed $callback_or_value For a callback, specify the name of the function|method.
	 * @param int            $args              Optional. The number of arguments the callback accepts. Default is 1.
	 *
	 * @return bool|Fancify_Lite_Anonymous_Filters
	 */
	public static function add_filter( $hook, $callback_or_value, $priority = 10, $args = 1 ) {
		return add_filter( $hook, $callback_or_value, $priority, $args );
	}

	/**
	 * Call the functions added to a filter hook.
	 *
	 * @since 1.0.0
	 *
	 * @param string $id    A unique string used as a reference.
	 * @param mixed  $value The value on which the filters hooked to <tt>$id</tt> are applied to it.
	 *
	 * @return mixed The filtered value after all hooked functions are applied to it.
	 */
	public static function apply_filters( $id, $value ) {
		$args = func_get_args();

		// Return simple filter if no sub-hook(s) is(are) set.
		if ( ! preg_match_all( '#\[(.*?)\]#', $args[0], $sub_hooks ) ) {
			return call_user_func_array( 'apply_filters', $args );
		}

		$prefix          = current( explode( '[', $args[0] ) );
		$variable_prefix = $prefix;
		$suffix          = preg_replace( '/^.*\]\s*/', '', $args[0] );

		// Base filter.
		$args[0] = $prefix . $suffix;
		$value   = call_user_func_array( 'apply_filters', $args );

		foreach ( (array) $sub_hooks[0] as $index => $sub_hook ) {

			// If there are more than 3 sub-hooks, stop processing.
			if ( $index > 2 ) {
				break;
			}

			$variable_prefix .= $sub_hook;
			$levels           = array( $prefix . $sub_hook . $suffix );

			// Cascade sub-hooks.
			if ( $index > 0 ) {
				$levels[] = $variable_prefix . $suffix;
			}

			// Apply sub-hooks.
			foreach ( $levels as $level ) {
				$args[0] = $level;
				$args[1] = $value;
				$value   = call_user_func_array( 'apply_filters', $args );

				// Apply filter without square brackets for backwards compatibility.
				$args[0] = preg_replace( '#(\[|\])#', '', $args[0] );
				$args[1] = $value;
				$value   = call_user_func_array( 'apply_filters', $args );
			}
		}

		return $value;
	}

	/**
	 * Check if any filter has been registered for a hook.
	 *
	 * @since 1.0.0
	 *
	 * @param string        $id       A unique string used as a reference. Sub-hook(s) must be set in square brackets.
	 * @param callable|bool $callback Optional. The callback to check for. Default false.
	 *
	 * @return bool|int If $callback is omitted, returns boolean for whether the hook has any callbacks registered.
	 */
	public static function has_filters( $id, $callback = false ) {
		// Check simple filter if no sub-hook is set.
		if ( ! preg_match_all( '#\[(.*?)\]#', $id, $sub_hooks ) ) {
			return has_filter( $id, $callback );
		}

		$prefix          = current( explode( '[', $id ) );
		$variable_prefix = $prefix;
		$suffix          = preg_replace( '/^.*\]\s*/', '', $id );

		// Check base filter.
		$priority_number = has_filter( $prefix . $suffix, $callback );

		if ( false !== $priority_number ) {
			return $priority_number;
		}

		foreach ( (array) $sub_hooks[0] as $index => $sub_hook ) {

			// If there are more than 3 sub-hooks, return false.
			if ( $index > 2 ) {
				return false;
			}

			$variable_prefix .= $sub_hook;
			$levels           = array( $prefix . $sub_hook . $suffix );

			// Cascade sub-hooks.
			if ( $index > 0 ) {
				$levels[] = $variable_prefix . $suffix;
			}

			// Apply sub-hooks.
			foreach ( $levels as $level ) {
				$priority_number = has_filter( $level, $callback );

				if ( false !== $priority_number ) {
					return $priority_number;
				}

				// Check filter without square brackets for backwards compatibility.
				$priority_number = has_filter( preg_replace( '#(\[|\])#', '', $level ), $callback );

				if ( false !== $priority_number ) {
					return $priority_number;
				}
			}
		}

		return false;
	}

}
