<?php
namespace WPDRMS\ASP\Hooks;

if ( !defined('ABSPATH') ) {
	die('-1');
}

class FiltersManager {
	const NAMESPACE = 'WPDRMS\\ASP\\Hooks\\Filters\\';
	/**
	 * Array of internal known filters
	 *
	 * @var array
	 */
	private static $filters = array(
		array(
			'filter'   => 'posts_request',
			'handler'  => array( 'SearchOverride', 'maybeCancelWPQuery' ),
			'priority' => 999999999,
			'args'     => 2,
		),
		array(
			'filter'   => 'posts_results',
			'handler'  => array( 'SearchOverride', 'override' ),
			'priority' => 999999999,
			'args'     => 2,
		),
		array(
			'filter'   => 'page_link',
			'handler'  => array( 'SearchOverride', 'fixUrls' ),
			'priority' => 999999999,
			'args'     => 2,
		),
		array(
			'filter'   => 'post_link',
			'handler'  => array( 'SearchOverride', 'fixUrls' ),
			'priority' => 999999999,
			'args'     => 2,
		),
		array(
			'filter'   => 'post_type_link',
			'handler'  => array( 'SearchOverride', 'fixUrls' ),
			'priority' => 999999999,
			'args'     => 2,
		),
		array(
			'filter'   => 'elementor/query/query_args',
			'handler'  => array( 'Elementor', 'posts' ),
			'priority' => 999,
			'args'     => 2,
		),
		array(
			'filter'   => 'elementor/theme/posts_archive/query_posts/query_vars',
			'handler'  => array( 'Elementor', 'posts_archive' ),
			'priority' => 999,
			'args'     => 1,
		),
		array(
			'filter'   => 'woocommerce_shortcode_products_query',
			'handler'  => array( 'Elementor', 'products' ),
			'priority' => 999,
			'args'     => 3,
		),
		array(
			'filter'   => 'jet-engine/listing/grid/posts-query-args',
			'handler'  => array( 'Elementor', 'jetListingGridQuery' ),
			'priority' => 0,
			'args'     => 3,
		),
		array(
			'filter'   => 'jet-engine/listing/grid/source',
			'handler'  => array( 'Elementor', 'jetListingGridQueryBuilderToPost' ),
			'priority' => 99999,
			'args'     => 3,
		),
		array(
			'filter'   => 'register_block_type_args',
			'handler'  => array( 'QueryLoopBlock', 'addAttributes' ),
			'priority' => 10,
			'args'     => 2,
		),
		array(
			'filter'   => 'query_loop_block_query_vars',
			'handler'  => array( 'QueryLoopBlock', 'queryVars' ),
			'priority' => 99,
			'args'     => 3,
		),
		array(
			'filter'   => 'register_block_type_args',
			'handler'  => array( 'GenerateBlocksQueryBlock', 'addAttributes' ),
			'priority' => 10,
			'args'     => 2,
		),
		array(
			'filter'   => 'generateblocks_query_wp_query_args',
			'handler'  => array( 'GenerateBlocksQueryBlock', 'queryVars' ),
			'priority' => 10,
			'args'     => 2,
		),

		array(
			'filter'   => 'blocksy:general:blocks:query:args',
			'handler'  => array( 'BlocksyAdvancedPostsBlock', 'queryVars' ),
			'priority' => 10,
			'args'     => 2,
		),

		array(
			'filter'   => 'bricks/posts/query_vars',
			'handler'  => array( 'BricksQueryLoop', 'bricksPostsQueryVars' ),
			'priority' => 10,
			'args'     => 4,
		),
		array(
			'filter'   => 'wp_enqueue_scripts',
			'handler'  => array( 'Asset', 'onPluginFrontendHead' ),
			'priority' => 10,
			'args'     => 0,
		),
		array(
			'filter'   => 'wp_print_footer_scripts',
			'handler'  => array( 'Asset', 'onPluginFooter' ),
			'priority' => 6,
			'args'     => 0,
		),
		array(
			'filter'   => 'admin_print_footer_scripts',
			'handler'  => array( 'Asset', 'onPluginFooter' ),
			'priority' => 6,
			'args'     => 0,
		),
		array(
			'filter'   => 'admin_print_footer_scripts',
			'handler'  => array( 'Asset', 'onPluginBackendFooter' ),
			'priority' => 7,
			'args'     => 0,
		),
		array(
			'filter'   => 'asp_ob_end',
			'handler'  => array( 'Asset', 'injectToOutputBuffer' ),
			'priority' => -101,
			'args'     => 1,
		),
		array(
			'filter'   => 'shutdown',
			'handler'  => array( 'Asset', 'onShutdown' ),
			'priority' => -100,
			'args'     => 0,
		),
		array(
			'filter'   => 'asp/assets/load',
			'handler'  => array( 'Asset', 'applySelectiveAssetLoader' ),
			'priority' => 10,
			'args'     => 1,
		),
		/* GENESIS REPLACEMENT FOR MULTISITE */
		array(
			'filter'   => 'genesis_post_title_output',
			'handler'  => array( 'SearchOverride', 'fixUrlsGenesis' ),
			'priority' => 999999999,
			'args'     => 3,
		),
		/* ALLOW SHORTCODE AS MENU TITLE */
		array(
			'filter'   => 'wp_nav_menu_objects',
			'handler'  => array( 'EtcFixes', 'allowShortcodeInMenus' ),
			'priority' => 10,
			'args'     => 1,
		),
		array(
			'filter'   => 'asp_theme_search_form',
			'handler'  => 'FormOverride',
			'priority' => 999999999,
			'args'     => 1,
		),
		array(
			'filter'   => 'get_search_form',
			'handler'  => 'FormOverride',
			'priority' => 999999999,
			'args'     => 1,
		),
		array(
			'filter'   => 'get_product_search_form',
			'handler'  => 'WooFormOverride',
			'priority' => 999999999,
			'args'     => 1,
		),
		array(
			'filter'   => 'asp_query_args',
			'handler'  => array( 'SearchExclude', 'handleExclusions' ),
			'priority' => 20,
			'args'     => 1,
		),
		array(
			'filter'   => 'asp_results',
			'handler'  => array( 'EtcFixes', 'plug_DownloadMonitorLink' ),
			'priority' => 999999999,
			'args'     => 1,
		),
		array(
			'filter'   => 'asp_fontend_get_taxonomy_terms',
			'handler'  => array( 'EtcFixes', 'fixPostFormatStandard' ),
			'priority' => 999,
			'args'     => 4,
		),
		array(
			'filter'   => 'asp_query_args',
			'handler'  => array( 'EtcFixes', 'fixPostFormatStandardArgs' ),
			'priority' => 999,
			'args'     => 1,
		),
		array(
			'filter'   => 'asp_query_args',
			'handler'  => array( 'IclTranslations', 'aspQueryArgsTranslations' ),
			'priority' => 999,
			'args'     => 2,
		),
		array(
			'filter'   => 'asp/assets/load/js',
			'handler'  => array( 'EtcFixes', 'fixOxygenEditorJS' ),
			'priority' => 999,
			'args'     => 1,
		),
		array(
			'filter'   => 'wp_get_attachment_image_src',
			'handler'  => array( 'EtcFixes', 'multisiteImageFix' ),
			'priority' => 999,
			'args'     => 4,
		),
		array(
			'filter'   => 'upload_mimes',
			'handler'  => array( 'EtcFixes', 'allow_json_mime_type' ),
			'priority' => 999,
			'args'     => 1,
		),
		array(
			'filter'   => 'http_request_host_is_external',
			'handler'  => array( 'EtcFixes', 'http_request_host_is_external_filter' ),
			'priority' => 9999,
			'args'     => 3,
		),
		array(
			'filter'   => 'http_request_args',
			'handler'  => array( 'EtcFixes', 'http_request_args' ),
			'priority' => 9999,
			'args'     => 2,
		),
		array(
			'filter'   => 'asp/shortcode/include_styles',
			'handler'  => array( 'EtcFixes', 'breakdanceFixShortcodeInEditor' ),
			'priority' => 10,
			'args'     => 1,
		),
		array(
			'filter'   => 'asp_post_content_before_tokenize_clear',
			'handler'  => array( 'EtcFixes', 'diviInitModules' ),
			'priority' => 9999,
			'args'     => 1,
		),
		array(
			'filter'   => 'attachment_fields_to_edit',
			'handler'  => 'MediaScreen',
			'priority' => 9999,
			'args'     => 2,
		),
		array(
			'filter'   => 'divi_loop_data_before_execution',
			'handler'  => array( 'Divi', 'loop' ),
			'priority' => 9999,
			'args'     => 3,
		),
		array(
			'filter'   => 'et_builder_blog_query',
			'handler'  => array( 'Divi', 'blog' ),
			'priority' => 9999,
			'args'     => 2,
		),
		array(
			'filter'   => 'et_builder_load_actions',
			'handler'  => array( 'EtcFixes', 'diviInitModulesOnAjax' ),
			'priority' => 9999,
			'args'     => 1,
		),
		array(
			'filter'   => 'divi_blog_extras_query_args',
			'handler'  => array( 'Divi', 'blogExtras' ),
			'priority' => 9999,
			'args'     => 2,
		),
		array(
			'filter'   => 'ctdqb_post_query_args',
			'handler'  => array( 'Divi', 'queryBuilder' ),
			'priority' => 9999,
			'args'     => 2,
		),
		array(
			'filter'   => 'asp_post_custom_field_before_tokenize',
			'handler'  => array( 'ACF', 'indexRepeaterAndFlexFields' ),
			'priority' => 10,
			'args'     => 3,
		),
		array(
			'filter'   => 'et_builder_ready', // Divi 4
			'handler'  => array( 'EtcFixes', 'diviBuilderReady' ),
			'priority' => 9999,
			'args'     => 0,
		),
		array(
			'filter'   => 'divi_module_library_modules_dependency_tree', // Divi 5
			'handler'  => array( 'EtcFixes', 'diviBuilderReady' ),
			'priority' => 9999,
			'args'     => 0,
		),
		/**
		 * Optimizes the HTML output by removing line breaks.
		 * This prevents some wpautop applied paragraphs and line breaks from appearing
		 * when the shortcode is used in a shortcode block.
		 */
		array(
			'filter'   => 'asp_shortcode_output',
			'handler'  => array( 'EtcFixes', 'optimizeHTML' ),
			'priority' => 9999,
			'args'     => 1,
		),

		array(
			'filter'   => 'rocket_exclude_js',
			'handler'  => array( 'JsCompatibility', 'rocket_exclude_js' ),
			'priority' => 9999,
			'args'     => 1,
		),

		array(
			'filter'   => 'rocket_excluded_inline_js_content',
			'handler'  => array( 'JsCompatibility', 'rocket_excluded_inline_js_content' ),
			'priority' => 9999,
			'args'     => 1,
		),

		array(
			'filter'   => 'asp_fontend_get_taxonomy_terms',
			'handler'  => array( 'ArchivePages', 'restrictTaxonomyTermFiltersOnArchivePages' ),
			'priority' => 10,
			'args'     => 5,
		),
	);

	/**
	 * Array of already registered objects
	 *
	 * @var array
	 */
	private static $registered = array();

	/**
	 * Registers all the handlers from the $actions variable
	 */
	public static function registerAll() {
		foreach ( self::$filters as $data ) {
			self::register($data['filter'], $data['handler'], $data['priority'], $data['args']);
		}
	}

	/**
	 * Get all the queued handlers
	 *
	 * @return array
	 */
	public static function getAll(): array {
		return array_keys(self::$filters);
	}

	/**
	 * Get all the already registered handlers (singleton instance storage)
	 *
	 * @return array
	 */
	public static function getRegistered(): array {
		return self::$registered;
	}

	/**
	 * Registers a filter with the handler class name.
	 *
	 * @param $filter
	 * @param $handler string|array
	 * @param int                  $priority
	 * @param int                  $accepted_args
	 * @return bool
	 */
	public static function register( $filter, $handler, int $priority = 10, int $accepted_args = 0 ): bool {

		if ( is_array($handler) ) {
			$class  = self::NAMESPACE . $handler[0];
			$handle = $handler[1];
		} else {
			$class  = self::NAMESPACE . $handler;
			$handle = 'handle';
		}

		if ( !class_exists($class) ) {
			return false;
		}

		if ( !isset(self::$registered[ $class ]) ) {
			self::$registered[ $class ] = call_user_func(array( $class, 'getInstance' ));
		}

		if ( !has_filter($filter, array( self::$registered[ $class ], $handle )) ) {
			add_filter($filter, array( self::$registered[ $class ], $handle ), $priority, $accepted_args);
		}

		return true;
	}

	/**
	 * Deregisters an action handler.
	 *
	 * @param $filter
	 * @param $handler
	 */
	public static function deregister( $filter, $handler ) {

		if ( is_array($handler) ) {
			$class  = self::NAMESPACE . $handler[0];
			$handle = $handler[1];
		} else {
			$class  = self::NAMESPACE . $handler;
			$handle = 'handle';
		}

		if ( isset(self::$registered[ $class ]) ) {
			// Deregister via custom method, as WordPress sometimes does not recognize object->method filters
			self::remove_object_filter($filter, $class, $handle);
		}
	}

	private static function remove_object_filter( $filter_name, $class_name, $function_name ) {
		global $wp_filter;
		foreach ( $wp_filter[ $filter_name ]->callbacks as $priority => $pri_data ) {
			foreach ( $pri_data as $cb => $cb_data ) {
				if (
					is_array($cb_data['function']) &&
					isset($cb_data['function'][0], $cb_data['function'][1])
					&& get_class($cb_data['function'][0]) == $class_name &&
					$cb_data['function'][1] == $function_name
				) {
					unset($wp_filter[ $filter_name ]->callbacks[ $priority ][ $cb ]);
				}
			}
		}
	}
}
