<?php

/**
 * Wrapper for including files
 *
 * @since 2.0.3
 */
function pp_plugin_include( $file ) {

	$path = pp_plugin_get_path( $file );

	if ( file_exists( $path ) ) {
		include_once( $path );
	}
}

/**
 * Returns the path to a file relative to our plugin
 *
 * @since 2.0.3
 */
function pp_plugin_get_path( $path ) {

	return POWERPACK_ELEMENTS_PATH . $path;

}

if ( ! function_exists( 'pp_get_page_templates' ) ) {
	/**
	 * Get page templates
	 *
	 * @param  string $type type of page template.
	 * @return array list of page templates
	 */
	function pp_get_page_templates( $type = '' ) {
		$args = [
			'post_type'      => 'elementor_library',
			'posts_per_page' => -1,
		];

		if ( $type ) {
			$args['tax_query'] = [
				[
					'taxonomy' => 'elementor_library_type',
					'field'    => 'slug',
					'terms'    => $type,
				],
			];
		}

		$page_templates = get_posts( $args );

		$options = [];

		if ( ! empty( $page_templates ) && ! is_wp_error( $page_templates ) ) {
			foreach ( $page_templates as $post ) {
				$options[ $post->ID ] = $post->post_title;
			}
		}
		return $options;
	}
}

if ( ! function_exists( 'is_pp_magic_wand' ) ) {
	/**
	 * Is Magic Wand active
	 *
	 * @return bool
	 */
	function is_pp_magic_wand() {
		if ( file_exists( POWERPACK_ELEMENTS_PATH . 'classes/class-pp-magic-wand.php' ) ) {
			return true;
		}

		return false;
	}
}

if ( ! function_exists( 'is_plugin_active' ) ) {
	include_once ABSPATH . 'wp-admin/includes/plugin.php';
}

if ( ! function_exists( 'is_pp_woocommerce_active' ) ) {
	/**
	 * Is WooCommerce active
	 *
	 * @return bool
	 */
	function is_pp_woocommerce_active() {
		if ( class_exists( 'WooCommerce' ) || is_plugin_active( 'woocommerce/woocommerce.php' ) ) {
			return true;
		}

		return false;
	}
}

if ( ! function_exists( 'is_pp_woocommerce' ) ) {
	/**
	 * Is WooCommerce active
	 *
	 * @return bool
	 */
	function is_pp_woocommerce() {
		if ( is_pp_woocommerce_active() && file_exists( POWERPACK_ELEMENTS_PATH . 'modules/woocommerce/module.php' ) ) {
			return true;
		}

		return false;
	}
}

if ( ! function_exists( 'is_pp_woo_builder' ) ) {
	/**
	 * Is WooCommerce active
	 *
	 * @return bool
	 */
	function is_pp_woo_builder() {
		if ( is_pp_woocommerce_active() && file_exists( POWERPACK_ELEMENTS_PATH . 'classes/class-pp-woo-builder.php' ) ) {
			return true;
		}

		return false;
	}
}

/**
 * Get PowerPack Modules
 *
 * @return $modules
 */
function pp_get_modules() {
	$modules = array();

	foreach ( \PowerpackElements\Classes\PP_Config::get_widget_info() as $widgets ) {
		foreach ( $widgets as $widget ) {
			$modules[ $widget['name'] ] = $widget['title'];
		}
	}

	ksort( $modules );

	return $modules;
}

function pp_get_thumbnail_taxonomies() {
	$taxonomies    = [];
	$taxonomy_list = [];

	$post_types = \PowerpackElements\Classes\PP_Posts_Helper::get_post_types();

	foreach ( $post_types as $slug => $type ) {
		$taxonomies = \PowerpackElements\Classes\PP_Posts_Helper::get_post_taxonomies( $slug );
		foreach ( (array) $taxonomies as $taxonomy ) {
			$taxonomy_list[ $taxonomy->name ] = $taxonomy->label;
		}
	}

	return $taxonomy_list;
}

function pp_get_extensions() {
	$extensions = [
		'pp-display-conditions'            => esc_html__( 'Display Conditions', 'powerpack' ),
		'pp-background-effects'            => esc_html__( 'Background Effects', 'powerpack' ),
		'pp-animated-gradient-background'  => esc_html__( 'Animated Gradient Background', 'powerpack' ),
		'pp-wrapper-link'                  => esc_html__( 'Wrapper Link', 'powerpack' ),
		'pp-custom-cursor'                 => esc_html__( 'Custom Cursor', 'powerpack' ),
		'pp-tooltips'                      => esc_html__( 'Tooltips', 'powerpack' ),
		'pp-presets-style'                 => esc_html__( 'Presets', 'powerpack' ),
	];

	$extensions = apply_filters( 'pp_elements_extensions', $extensions );

	return $extensions;
}

function pp_get_enabled_modules() {
	$enabled_modules = get_option( 'pp_elementor_modules' );

	if ( ! is_array( $enabled_modules ) && 'disabled' != $enabled_modules ) {
		$enabled_modules = pp_get_modules();
	}

	return apply_filters( 'pp_elementor_enabled_modules', $enabled_modules );
}

/**
 * Get the enabled modules as a lookup table.
 *
 * The 'pp_elementor_modules' option is stored as a plain list of widget names,
 * but 'pp_get_enabled_modules()' may also return a 'name => title' map when the
 * option has never been saved, or the string 'disabled'. Both shapes are
 * flattened here into a 'name => true' map.
 *
 * Module_Base::is_widget_active() runs once per widget on every registration
 * pass, so this is one of the hottest paths in the plugin. The option is read
 * and filtered once per request, and membership becomes a single isset() rather
 * than an in_array() scan over the full list.
 *
 * @since 3.0.0
 * @param bool $reset Internal. Flush the cached lookup, see pp_flush_enabled_modules_cache().
 * @return array Map of enabled widget name => true.
 */
function pp_get_enabled_modules_lookup( $reset = false ) {
	static $lookup = null;

	if ( $reset ) {
		$lookup = null;

		return [];
	}

	if ( null !== $lookup ) {
		return $lookup;
	}

	$enabled_modules = pp_get_enabled_modules();
	$lookup          = [];

	if ( is_array( $enabled_modules ) ) {
		foreach ( $enabled_modules as $key => $value ) {
			$module_name = is_int( $key ) ? $value : $key;

			if ( is_string( $module_name ) ) {
				$lookup[ $module_name ] = true;
			}
		}
	}

	return $lookup;
}

/**
 * Flush the cached enabled modules lookup.
 *
 * Hooked to the option writes so a settings save is picked up within the same
 * request that performed it.
 *
 * @since 3.0.0
 * @return void
 */
function pp_flush_enabled_modules_cache() {
	pp_get_enabled_modules_lookup( true );
}
add_action( 'add_option_pp_elementor_modules', 'pp_flush_enabled_modules_cache' );
add_action( 'update_option_pp_elementor_modules', 'pp_flush_enabled_modules_cache' );
add_action( 'delete_option_pp_elementor_modules', 'pp_flush_enabled_modules_cache' );

/**
 * Get the list of enabled module names, limited to widgets that still ship.
 *
 * Stale names left over from removed widgets are dropped so counts always line
 * up with the current widget library.
 *
 * @since 3.0.0
 * @return array List of widget names.
 */
function pp_get_enabled_module_names() {
	$all_modules = array_keys( pp_get_modules() );
	$enabled     = array_keys( pp_get_enabled_modules_lookup() );

	return array_values( array_intersect( $all_modules, $enabled ) );
}

/**
 * Get counts for the widget library, used to decide whether to nudge the user
 * to disable widgets they do not need.
 *
 * @since 3.0.0
 * @return array {
 *     @type int $total    Total number of widgets shipped with the plugin.
 *     @type int $enabled  Number of enabled widgets.
 *     @type int $disabled Number of disabled widgets.
 *     @type int $percent  Percentage of the library that is enabled, rounded.
 * }
 */
function pp_get_modules_stats() {
	$total   = count( pp_get_modules() );
	$enabled = count( pp_get_enabled_module_names() );

	return [
		'total'    => $total,
		'enabled'  => $enabled,
		'disabled' => max( 0, $total - $enabled ),
		'percent'  => $total > 0 ? (int) round( ( $enabled / $total ) * 100 ) : 0,
	];
}

function pp_get_filter_modules( $staus = '' ) {
	global $wpdb;

	$modules          = [];
	$get_used_widgets = [];
	$all_widget_list  = pp_get_modules();

	$post_ids = $wpdb->get_col(
		'SELECT `post_id` FROM `' . $wpdb->postmeta . '`
				WHERE `meta_key` = \'_elementor_version\';'
	);

	if ( ! empty( $post_ids ) ) {
		foreach ( $post_ids as $post_id ) {
			if ( 'revision' === get_post_type( $post_id ) ) {
				continue;
			}

			$get_used_widgets[] = pp_check_widget_used_status( $all_widget_list, $post_id );
		}
	}

	if ( empty( $get_used_widgets ) ) {
		return $modules;
	}

	foreach ( $get_used_widgets as $get_used_widget ) {
		if ( ! empty( $get_used_widget ) ) {
			foreach ( $get_used_widget as $key => $value ) {
				if ( ! array_key_exists( $value, $modules ) ) {
					if ( isset( $all_widget_list[ $value ] ) ) {
						$modules[ $value ] = $all_widget_list[ $value ];
					}
				}
			}
		}
	}
	asort( $modules );
	update_option( 'pp_elementor_used_modules', $modules );

	$notused_modules = array_diff_key( $all_widget_list, $modules );
	asort( $notused_modules );
	update_option( 'pp_elementor_notused_modules', $notused_modules );

	if ( 'notused' === $staus ) {
		$modules = $notused_modules;
	}

	return $modules;
}

function pp_check_widget_used_status( $all_widget_list, $post_id = '' ) {
	$widget_data = [];
	if ( ! current_user_can( 'install_plugins' ) ) {
		$widget_data;
	}

	if ( ! empty( $post_id ) ) {
		$meta_data = \Elementor\Plugin::$instance->documents->get( $post_id );

		if ( is_object( $meta_data ) ) {
			$meta_data = $meta_data->get_elements_data();

			if ( empty( $meta_data ) ) {
				$widget_data;
			}

			\Elementor\Plugin::$instance->db->iterate_data( $meta_data, function( $element ) use ( $all_widget_list, &$widget_data ) {
				if ( ! empty( $element['widgetType'] ) ) {
					if ( substr( $element['widgetType'], 0, 3 ) === 'pp-' ) {
						$widget_data[] = $element['widgetType'];
					}
				}
			} );
		}
	}
	return $widget_data;
}

function pp_get_enabled_extensions() {
	$enabled_extensions = get_option( 'pp_elementor_extensions' );

	if ( ! is_array( $enabled_extensions ) && 'disabled' != $enabled_extensions ) {
		$enabled_extensions = pp_get_extensions();
	}

	return apply_filters( 'pp_elementor_enabled_extensions', $enabled_extensions );
}

function pp_get_enabled_taxonomies() {
	$enabled_taxonomies = get_option( 'pp_elementor_taxonomy_thumbnail_taxonomies' );

	if ( is_array( $enabled_taxonomies ) ) {
		return $enabled_taxonomies;
	}

	if ( 'disabled' == $enabled_taxonomies ) {
		return $enabled_taxonomies;
	}

	return pp_get_thumbnail_taxonomies();
}

// Get templates

function pp_get_saved_templates( $templates = [] ) {

	if ( empty( $templates ) ) {
		return [];
	}

	$options = [];

	foreach ( $templates as $template ) {
		$options[ $template['template_id'] ] = $template['title'];
	}

	return $options;
}

// Query functions.

/**
 * Fetches available post types
 *
 * @since 2.0.0
 */
function pp_get_public_post_types_options( $singular = false, $any = false, $args = [] ) {
	$defaults = [
		'show_in_nav_menus' => true,
	];

	$post_types     = [];
	$post_type_args = wp_parse_args( $args, $defaults );

	if ( $any ) {
		$post_types['any'] = esc_html__( 'Any', 'powerpack' );
	}

	if ( ! function_exists( 'get_post_types' ) ) {
		return $post_types;
	}

	$_post_types = get_post_types( $post_type_args, 'objects' );

	foreach ( $_post_types as $post_type => $object ) {
		$post_types[ $post_type ] = $singular ? $object->labels->singular_name : $object->label;
	}

	return $post_types;
}

/**
 * Get Taxonomies Options
 *
 * Fetches available taxonomies
 *
 * @since 2.0.0
 */
function pp_get_taxonomies_options( $post_type = false ) {

	$options = [];

	if ( ! $post_type ) {
		// Get all available taxonomies
		$taxonomies = get_taxonomies(
			[
				'show_in_nav_menus' => true,
			],
			'objects'
		);
	} else {
		$taxonomies = get_object_taxonomies( $post_type, 'objects' );
	}

	foreach ( $taxonomies as $taxonomy ) {
		if ( ! $taxonomy->publicly_queryable ) {
			continue;
		}

		$options[ $taxonomy->name ] = $taxonomy->label;
	}

	if ( empty( $options ) ) {
		$options[0] = esc_html__( 'No taxonomies found', 'powerpack' );
		return $options;
	}

	return $options;
}

/**
 * Get Taxonomies Labels
 *
 * Fetches labels for given taxonomy
 *
 * @since 2.1.0
 */
function pp_get_taxonomy_labels( $taxonomy = '' ) {

	if ( ! $taxonomy || '' === $taxonomy ) {
		return false;
	}

	$labels          = false;
	$taxonomy_object = get_taxonomy( $taxonomy );

	if ( $taxonomy_object && is_object( $taxonomy_object ) ) {
		$labels = $taxonomy_object->labels;
	}

	return $labels;
}

/**
 * Get Terms Options
 *
 * Retrieve the terms options array for a control
 *
 * @since  1.6.0
 * @param  taxonomy     The taxonomy for the terms
 * @param  key|string   The key to use when building the options. Can be 'slug' or 'id'
 * @param  all|bool     The string to use for the first option. Can be false to disable. Default: true
 * @return array
 */
function pp_get_terms_options( $taxonomy, $key = 'slug', $all = true ) {

	if ( false !== $all ) {
		$all     = ( true === $all ) ? esc_html__( 'All', 'powerpack' ) : $all;
		$options = [ '' => $all ];
	}

	$terms = get_terms(
		[
			'taxonomy' => $taxonomy,
		]
	);

	if ( empty( $terms ) ) {
		$options[''] = sprintf( esc_html__( 'No terms found', 'powerpack' ), $taxonomy );
		return $options;
	}

	foreach ( $terms as $term ) {
		$term_key             = ( 'id' === $key ) ? $term->term_id : $term->slug;
		$options[ $term_key ] = $term->name;
	}

	return $options;
}

/**
 * Get Terms
 *
 * Retrieve a list of terms for specific taxonomies
 *
 * @since  1.6.0
 * @return array
 */
function pp_get_terms( $taxonomies = [] ) {
	$_terms = [];

	if ( empty( $taxonomies ) ) {
		return false;
	}

	if ( is_array( $taxonomies ) ) {
		foreach ( $taxonomies as $taxonomy ) {
			$terms = get_the_terms( get_the_ID(), $taxonomy );

			if ( empty( $terms ) ) {
				continue;
			}

			foreach ( $terms as $term ) {
				$_terms[] = $term; }
		}
	} else {
		$_terms = get_the_terms( get_the_ID(), $taxonomies );
	}

	if ( empty( $_terms ) || 0 === count( $_terms ) ) {
		return false;
	}

	return $_terms;

}

/**
 * Fetches available pages
 *
 * @since 2.0.0
 */
function pp_get_pages_options() {

	$options = [];

	$pages = get_pages(
		[
			'hierarchical' => false,
		]
	);

	if ( empty( $pages ) ) {
		$options[''] = esc_html__( 'No pages found', 'powerpack' );
		return $options;
	}

	foreach ( $pages as $page ) {
		$options[ $page->ID ] = $page->post_title;
	}

	return $options;
}

/**
 * Fetches available users
 *
 * @since 2.0.0
 */
function pp_get_users_options() {

	$options = [];

	$users = get_users(
		[
			'fields' => [ 'ID', 'display_name' ],
		]
	);

	if ( empty( $users ) ) {
		$options[''] = esc_html__( 'No users found', 'powerpack' );
		return $options;
	}

	foreach ( $users as $user ) {
		$options[ $user->ID ] = $user->display_name;
	}

	return $options;
}

/**
 * Get category with highest number of parents
 * from a given list
 *
 * @since 2.0.0
 */
function pp_get_most_parents_category( $categories = [] ) {

	$counted_cats = [];

	if ( ! is_array( $categories ) ) {
		return $categories;
	}

	foreach ( $categories as $category ) {
		$category_parents                   = get_category_parents( $category->term_id, false, ',' );
		$category_parents                   = explode( ',', $category_parents );
		$counted_cats[ $category->term_id ] = count( $category_parents );
	}

	arsort( $counted_cats );
	reset( $counted_cats );

	return key( $counted_cats );
}

/**
 * Recursively sort an array of taxonomy terms hierarchically. Child categories will be
 * placed under a 'children' member of their parent term.
 *
 * @since 2.2.6
 *
 * @param Array   $cats     taxonomy term objects to sort
 * @param Array   $into     result array to put them in
 * @param integer $parentId the current parent ID to put them in
 */
function pp_sort_terms_hierarchicaly( array &$cats, array &$into, $parentId = 0 ) {
	foreach ( $cats as $i => $cat ) {
		if ( $cat->parent == $parentId ) {
			$into[ $cat->term_id ] = $cat;
			unset( $cats[ $i ] );
		}
	}

	foreach ( $into as $topCat ) {
		$topCat->children = [];
		pp_sort_terms_hierarchicaly( $cats, $topCat->children, $topCat->term_id );
	}
}

/**
 * Constrain search query for posts by searching only in post titles
 *
 * @since 2.2.0
 */
function pp_posts_where_by_title_name( $where, &$wp_query ) {
	global $wpdb;
	if ( $s = $wp_query->get( 'search_title_name' ) ) {
		$where .= ' AND (' . $wpdb->posts . '.post_title LIKE \'%' . esc_sql( $wpdb->esc_like( $s ) ) . '%\' OR ' . $wpdb->posts . '.post_name LIKE \'%' . esc_sql( $wpdb->esc_like( $s ) ) . '%\')';
	}
	return $where;
}

/**
 * Checks if Header is enabled from PowerPack settings.
 *
 * @since  1.4.15
 * @return bool True if header is enabled. False if header is not enabled
 */
function pp_header_enabled() {
	$header_id = get_option( 'pp_header_footer_template_header' );
	$status    = false;

	if ( '' !== $header_id ) {
		$status = true;
	}

	return apply_filters( 'pp_header_enabled', $status );
}

/**
 * Checks if Footer is enabled from PowerPack settings.
 *
 * @since  1.4.15
 * @return bool True if header is enabled. False if header is not enabled.
 */
function pp_footer_enabled() {
	$footer_id = get_option( 'pp_header_footer_template_footer' );
	$status    = false;

	if ( '' !== $footer_id ) {
		$status = true;
	}

	return apply_filters( 'pp_footer_enabled', $status );
}

/**
 * Checks if Elementor Additional Custom Breakpoints feature is enabled from Elementor Experiments settings
 *
 * @since  2.8.0
 * @return bool True if Elementor Additional Custom Breakpoints feature is enabled. False otherwise.
 */
function pp_has_custom_breakpoints() {
	if ( pp_get_elementor()->breakpoints->has_custom_breakpoints() ) {
		return true;
	}

	return false;
}

/**
 * Get Breakpoints Config
 * 
 * Iterates over an array of all of the system's breakpoints (both active and inactive), queries each breakpoint's
 * class instance, and generates an array containing data on each breakpoint: its label, current value, direction
 * ('min'/'max') and whether it is enabled or not.
 *
 * @since  2.8.0
 * @return array
 */
function pp_get_breakpoints_config() {
	$breakpoints = pp_get_elementor()->breakpoints->get_breakpoints_config();

	return $breakpoints;
}

/**
 * Elementor
 *
 * Retrieves the elementor plugin instance
 *
 * @since  2.1.0
 * @return \Elementor\Plugin|$instace
 */
function pp_get_elementor() {
	return \Elementor\Plugin::$instance;
}

/**
 * Check if extension is enabled through admin settings
 *
 * @since 2.9.0
 *
 * @access public
 * @return bool
 */
function is_extension_enabled( $extension = '' ) {
	$enabled_extensions = pp_get_enabled_extensions();

	if ( ! is_array( $enabled_extensions ) ) {
		$enabled_extensions = [];
	}

	$extension = str_replace( '_', '-', $extension );

	$extension_name = 'pp-' . $extension;

	if ( in_array( $extension_name, $enabled_extensions ) || isset( $enabled_extensions[ $extension_name ] ) ) {
		return true;
	}

	return false;
}

/**
 * Widgets that ship switched off.
 *
 * Read from the 'default_off' flag in PP_Config::get_widget_info(), so the fact
 * lives next to the widget it describes and cannot drift out of sync with a
 * rename the way a separate list of names does.
 *
 * Note this flag is permanent, unlike the neighbouring 'is_new' flag that the
 * release manager strips once a widget is a couple of releases old.
 *
 * @since x.x.x
 *
 * @return array List of widget names.
 */
function pp_get_default_off_modules() {
	$default_off = [];

	foreach ( \PowerpackElements\Classes\PP_Config::get_widget_info() as $widgets ) {
		foreach ( $widgets as $widget ) {
			if ( ! empty( $widget['default_off'] ) && ! empty( $widget['name'] ) ) {
				$default_off[] = $widget['name'];
			}
		}
	}

	return $default_off;
}

/**
* Run While Fresh installation.
*
* @since 2.11.4
*/
function default_disabled_modules() {
	$enabled_modules = pp_get_modules();

	foreach ( pp_get_default_off_modules() as $disable_widget ) {
		unset( $enabled_modules[ $disable_widget ] );
	}

	$default_modules = [];
	foreach ( $enabled_modules as $key => $enabled_module ) {
		$default_modules[] = $key;
	}

	update_option( 'pp_elementor_modules', $default_modules );
}
