<?php
/**
 * Plugin class.
 *
 * @package amve\classes
 */

// Exit if accessed directly.
defined( 'ABSPATH' ) || exit;

/**
 * AMVE Plugin Singleton Class
 */
final class AMVE {
	/**
	 * The instance of the AMVE plugin
	 *
	 * @var      instanceof AMVE $instance
	 * @static
	 */
	private static $instance;

	/**
	 * The config of the AMVE plugin
	 *
	 * @var      array $config
	 * @static
	 */
	private static $config;

	/**
	 * __clone method
	 *
	 * @return   void
	 */
	public function __clone() {
		_doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin&#8217; huh?', 'amve_lang' ), '1.0' );
	}

	/**
	 * __wakeup method
	 *
	 * @return   void
	 */
	public function __wakeup() {
		_doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin&#8217; huh?', 'amve_lang' ), '1.0' );
	}

	/**
	 * Instance method
	 *
	 * @return   self::$instance
	 */
	public static function instance() {
		if ( ! isset( self::$instance ) && ! ( self::$instance instanceof AMVE ) ) {
			self::$instance = new AMVE();
			// Load textdomain.
			self::$instance->load_textdomain();
			// Load config file.
			require_once AMVE_DIR . 'config.php';
			require_once AMVE_DIR . 'admin/cron-x/cron-import.php';
			require_once AMVE_DIR . 'admin/vendors/simple-html-dom-x/simple-html-dom.php';
			require_once AMVE_DIR . 'admin/pages/page-options-x.php';
			if ( is_admin() || wp_next_scheduled( 'AMVE_update_one_feed' ) ) {
				self::$instance->load_admin_filters();
				self::$instance->load_admin_hooks();
				self::$instance->auto_load_php_files( 'admin' );
				self::$instance->admin_init();
			}
			if ( ! is_admin() ) {
				self::$instance->auto_load_php_files( 'public' );
				self::$instance->public_init();
			}
		}
		return self::$instance;
	}

	/**
	 * Add js and css files, tabs, pages, php files in admin mode.
	 *
	 * @return void.
	 */
	public function load_admin_filters() {
		// add js and css files, tabs, pages, php files.
		add_filter( 'WPSCORE-scripts', array( $this, 'add_admin_scripts' ) );
		add_filter( 'WPSCORE-tabs', array( $this, 'add_admin_navigation' ) );
		add_filter( 'WPSCORE-pages', array( $this, 'add_admin_navigation' ) );
	}

	/**
	 * Add admin js and css scripts. This is a WPSCORE-scripts filter callback function.
	 *
	 * @param array $scripts List of all WPS CORE CSS / JS to load.
	 *
	 * @return array $scripts List of all WPS CORE + plugin CSS / JS to load.
	 */
	public function add_admin_scripts( $scripts ) {
		if ( isset( self::$config['scripts'] ) ) {
			if ( isset( self::$config['scripts']['js'] ) ) {
				$scripts += (array) self::$config['scripts']['js'];
			}
			if ( isset( self::$config['scripts']['css'] ) ) {
				$scripts += (array) self::$config['scripts']['css'];
			}
		}
		return $scripts;
	}

	/**
	 * Add plugin admin navigation tab. This is a WPSCORE-tabs and WPSCORE-pages filters callback function.
	 *
	 * @param array $nav List of all WPS CORE navigation tabs to add.
	 *
	 * @return array $nav List of all WPS CORE + plugin navigation tabs to add.
	 */
	public function add_admin_navigation( $nav ) {
		if ( isset( self::$config['nav'] ) ) {
			$nav += (array) self::$config['nav'];
		}
		return $nav;
	}

	/**
	 * Auto-loader for PHP files
	 *
	 * @param string{'admin','public'} $dir Directory where to find PHP files to load.
	 *
	 * @return void
	 */
	public function auto_load_php_files( $dir ) {
		$dirs = (array) ( AMVE_DIR . $dir . '/' );
		foreach ( (array) $dirs as $dir ) {
			$files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $dir ) );
			if ( ! empty( $files ) ) {
				foreach ( $files as $file ) {
					// exlude dirs.
					if ( $file->isDir() ) {
						continue; }
					// exlude index.php.
					if ( $file->getPathname() === 'index.php' ) {
						continue; }
					// exlude files !== .php.
					if ( substr( $file->getPathname(), -4 ) !== '.php' ) {
						continue; }
					// exlude files from -x suffixed directories.
					if ( substr( $file->getPath(), -2 ) === '-x' ) {
						continue; }
					// exlude -x suffixed files.
					if ( substr( $file->getPathname(), -6 ) === '-x.php' ) {
						continue; }
					// else require file.
					require $file->getPathname();
				}
			}
		}
	}

	/**
	 * Registering plugin activation / deactivation / uninstall hooks.
	 *
	 * @return void
	 */
	public function load_admin_hooks() {
		register_activation_hook( AMVE_FILE, array( __CLASS__, 'activation' ) );
		register_deactivation_hook( AMVE_FILE, array( __CLASS__, 'deactivation' ) );
		register_uninstall_hook( AMVE_FILE, array( __CLASS__, 'uninstall' ) );
	}

	/**
	 * Stuff to do on plugin activation. This is a register_activation_hook callback function.
	 *
	 * @static
	 *
	 * @return void
	 */
	public static function activation() {
		WPSCORE()->update_client_signature();
		WPSCORE()->init( true );
	}

	/**
	 * Stuff to do on plugin deactivation. This is a register_deactivation_hook callback function.
	 *
	 * @static
	 *
	 * @return void
	 */
	public static function deactivation() {
		WPSCORE()->update_client_signature();
		WPSCORE()->init( true );
	}

	/**
	 * Stuff to do on plugin deactivation. This is a register_deactivation_hook callback function.
	 *
	 * @static
	 *
	 * @return void
	 */
	public static function uninstall() {
		WPSCORE()->update_client_signature();
		WPSCORE()->init( true );
	}

	/**
	 * Load textdomain method.
	 *
	 * @return bool True when textdomain is successfully loaded, false if not.
	 */
	public function load_textdomain() {
		$lang = ( current( explode( '_', get_locale() ) ) );
		if ( 'zh' === $lang ) {
			$lang = 'zh-TW';
		}
		$textdomain = 'amve_lang';
		$mofile     = AMVE_DIR . "languages/{$textdomain}_{$lang}.mo";
		return load_textdomain( $textdomain, $mofile );
	}

	/**
	 * Load public filters.
	 *
	 * @return   void
	 */
	public function load_public_filters() {
		add_filter( 'WPSCORE-public_dirs', array( $this, 'add_public_dirs' ) );
	}

	/**
	 * Add public php files to require.
	 *
	 * @param array $public_dirs Array of public directories.
	 *
	 * @return array $public_dirs Array of public directories with the current plugin ones.
	 */
	public function add_public_dirs( $public_dirs ) {
		$public_dirs[] = plugin_dir_path( __FILE__ ) . 'public/';
		return $public_dirs;
	}

	/**
	 * Stuff to do on admin init.
	 *
	 * @access private
	 *
	 * @return void
	 */
	private function admin_init() {}

	/**
	 * Stuff to do on public init.
	 *
	 * @access private
	 *
	 * @return void
	 */
	private function public_init() {
		add_action( 'wp_head', array( $this, 'amve_head' ), 9999 );
	}

	/**
	 * Stuff to do before rendering the page.
	 *
	 * @return void
	 */
	public function amve_head() {
		$amve_dom = new AMVE\Dom();
		ob_start( array( $amve_dom, 'prepare_outgoing_links' ) );
	}

	/**
	 * Get partners raw data.
	 *
	 * @return array The list of all partners configs.
	 */
	private function get_partners_row_config() {
		$partners_configs     = array();
		$partners_configs_dir = AMVE_DIR . 'admin/data/partners-x/';
		foreach ( scandir( $partners_configs_dir ) as $filename ) {
			$partner_config_file_path = $partners_configs_dir . $filename;

			if ( ! is_file( $partner_config_file_path ) ) {
				continue;
			}

			require $partner_config_file_path;
			// require the file grants access to $partner_infos variable.
			$partners_configs[ $partner_infos['id'] ]               = $partner_infos;
			$partners_configs[ $partner_infos['id'] ]['popularity'] = $this->get_partner_popularity( $partner_infos['id'] );
		}

		return $partners_configs;
	}

	/**
	 * Get partner popularity given a prtner id.
	 *
	 * @param string $partner_id The partner id.
	 * @return int The partner popularity.
	 */
	private function get_partner_popularity( $partner_id ) {
		$partners_popularity = array(
			'xhamster'            => 218781,
			'xvideos'             => 128526,
			'pornhub'             => 127517,
			'redtube'             => 124060,
			'youporn'             => 94247,
			'drtuber'             => 53266,
			'eporner'             => 35439,
			'txxx'                => 33712,
			'xnxx'                => 26344,
			'viptube'             => 26042,
			'pornerbros'          => 19092,
			'gotporn'             => 17692,
			'iceporn'             => 17403,
			'nuvid'               => 16805,
			'sextronix'           => 12241,
			'xtube'               => 11651,
			'pornxs'              => 11565,
			'famedollars'         => 10304,
			'hclips'              => 9578,
			'vporn'               => 8964,
			'vjav'                => 8029,
			'anilos'              => 7322,
			'pornrabbit'          => 6720,
			'befuck'              => 6588,
			'avrevenue'           => 6374,
			'pornsharing'         => 6274,
			'nubilescash'         => 6155,
			'youjizz'             => 6111,
			'youporngay'          => 5658,
			'fetishhits'          => 5582,
			'la_france_a_poil'    => 5488,
			'hdzog'               => 5284,
			'viprevenue'          => 4861,
			'thegay'              => 4818,
			'upornia'             => 4598,
			'vporno'              => 4349,
			'porndig'             => 3913,
			'tukif'               => 3904,
			'royalcash'           => 3625,
			'seriouscash'         => 3517,
			'mcfucker'            => 3338,
			'shemaleprofit'       => 3313,
			'inkorrect'           => 3287,
			'h2porn'              => 3199,
			'hotmovs'             => 3028,
			'hd_pornos'           => 2973,
			'getscorecash'        => 2674,
			'pimpboss'            => 2537,
			'hotshame'            => 2464,
			'wtfbucks'            => 2394,
			'droselia'            => 2184,
			'buddyprofits'        => 2141,
			'voyeurhit'           => 2055,
			'wetplace'            => 2014,
			'gay'                 => 1946,
			'seriouspartners'     => 1811,
			'partnercash'         => 1726,
			'pornoid'             => 1611,
			'hentaibiz'           => 1598,
			'indecentes_voisines' => 1553,
			'pornomovies'         => 1410,
			'fetishwealth'        => 1332,
			'pornohirsch'         => 1214,
			'pornalized'          => 1158,
			'ferrocash'           => 1151,
			'eravage'             => 1143,
			'pinkrod'             => 1111,
			'seemybucks'          => 1083,
			'videosz'             => 958,
			'thenewporn'          => 914,
			'tubepornclassic'     => 819,
			'carpediem'           => 700,
			'gaytronix'           => 659,
			'sultancash'          => 615,
			'pornoaffe'           => 581,
			'vador_ewok'          => 575,
			'spunkycash'          => 488,
			'updatetube'          => 463,
			'french_bukkake'      => 363,
			'xponsor'             => 329,
			'pornfr'              => 325,
			'payglad'             => 324,
			'soloslutcash'        => 320,
			'hd-pornos'           => 0,
			'flyflv'              => 0,
			'pornoente'           => 0,
			'pornve'              => 0,
			'extremetube'         => 0,
			'x18'                 => 0,
			'shemalez'            => 0,
		);
		if ( ! isset( $partners_popularity[ $partner_id ] ) ) {
			return 0;
		}
		return $partners_popularity[ $partner_id ];
	}
		/**
		 * Get all partners data.
		 *
		 * @since 1.0.0
		 *
		 * @access public
		 * @return array All the partners data.
		 */
	public function get_partners() {
		$i        = 0;
		$partners = $this->get_partners_row_config();

		foreach ( (array) $partners as $partner_key => $partner_config ) {
			$is_configured = true;
			// adding options infos.
			if ( isset( $partner_config['options'] ) ) {
				$partner_id            = $partner_config['id'];
				$saved_partner_options = WPSCORE()->get_product_option( 'AMVE', $partner_id . '_options' );
				foreach ( (array) $partner_config['options'] as $key => $option ) {
					if ( isset( $option['id'] ) ) {
						$partners[ $partner_key ]['options'][ $key ]['value'] = isset( $saved_partner_options[ $option['id'] ] ) ? $saved_partner_options[ $option['id'] ] : '';
						if ( isset( $partners[ $partner_key ]['options'][ $key ]['required'] ) && true === $partners[ $partner_key ]['options'][ $key ]['required'] ) {
							if ( ! isset( $saved_partner_options[ $option['id'] ] ) ) {
								$is_configured = false;
							} else {
								if ( '' === $saved_partner_options[ $option['id'] ] ) {
									$is_configured = false;
								}
							}
						}
					}
				}
			}
			$partners[ $partner_key ]['is_configured'] = $is_configured;

			// Check for svg or jpg.
			$partners[ $partner_key ]['thumbnail'] = '';
			$partner_thumbnail_path                = AMVE_DIR . 'admin/assets/img/partners/' . $partners[ $partner_key ]['id'];
			$partner_thumbnail_url                 = AMVE_URL . 'admin/assets/img/partners/' . $partners[ $partner_key ]['id'];

			if ( file_exists( $partner_thumbnail_path . '.svg' ) ) {
				$partners[ $partner_key ]['thumbnail'] = $partner_thumbnail_url . '.svg';
			} elseif ( file_exists( $partner_thumbnail_path . '.jpg' ) ) {
				$partners[ $partner_key ]['thumbnail'] = $partner_thumbnail_url . '.jpg';
			}

			// ordering partners categories.
			$ordered_cats = array();
			foreach ( $partner_config['categories'] as $cat_id => $cat_name ) {
				if ( strpos( $cat_id, 'optgroup' ) !== false ) {
					$cat_id_explode     = explode( '::', $cat_id );
					$ordered_cats[ $i ] = array(
						'id'   => 'optgroup',
						'name' => end( $cat_id_explode ),
					);
					foreach ( (array) $cat_name as $sub_cat_id => $sub_cat_name ) {
						$ordered_cats[ $i ]['sub_cats'][] = array(
							'id'   => $sub_cat_id,
							'name' => $sub_cat_name,
						);
					}
				} else {
					$ordered_cats[ $i ] = array(
						'id'   => $cat_id,
						'name' => $cat_name,
					);
				}
				++$i;
			}
			$partners[ $partner_key ]['categories'] = $ordered_cats;
		}
		return (array) $partners;
	}

		/**
		 * Get a partner infos from a given partner id.
		 *
		 * @since 1.0.0
		 *
		 * @access public
		 * @param string $partner_id the partner id we want to retrieve the data from.
		 * @return array All the wanted partner infos.
		 */
	public function get_partner( $partner_id ) {
		$partners = $this->get_partners();
		return $partners[ $partner_id ];
	}

		/**
		 * Get all WordPress categories depending on the categories taxonomies defined in the options poage.
		 *
		 * @since 1.0.0
		 *
		 * @access public
		 * @return array The categories.
		 */
	public function get_wp_cats() {
		$taxonomy = xbox_get_field_value( 'amve-options', 'custom-video-categories', 'category' );
		return (array) get_terms( $taxonomy, array( 'hide_empty' => 0 ) );
	}

		/**
		 * Get all saved feeds.
		 *
		 * @since 1.0.0
		 *
		 * @access public
		 * @return array An array of saved feeds.
		 */
	public function get_feeds() {
		$saved_feeds = WPSCORE()->get_product_option( 'AMVE', 'feeds' );

		if ( ! is_array( $saved_feeds ) ) {
			$saved_feeds = array();
		}

		foreach ( (array) $saved_feeds as $feed_id => $feed_data ) {
			$more_data                              = explode( '__', $feed_id );
			$saved_feeds[ $feed_id ]['wp_cat']      = $more_data[0];
			$saved_feeds[ $feed_id ]['partner_id']  = $more_data[1];
			$saved_feeds[ $feed_id ]['partner_cat'] = $more_data[2];
			$saved_feeds[ $feed_id ]['id']          = $feed_id;

			// Add default data if they don't exist yet.
			$saved_feeds[ $feed_id ]['wp_cat_state'] = term_exists( intval( $saved_feeds[ $feed_id ]['wp_cat'] ) ) === null ? 0 : 1;
			if ( ! isset( $saved_feeds[ $feed_id ]['status'] ) || '' === $saved_feeds[ $feed_id ]['status'] ) {
				$saved_feeds[ $feed_id ]['status'] = xbox_get_field_value( 'amve-options', 'default-status', 'publish' );
			}
			if ( ! isset( $saved_feeds[ $feed_id ]['outgoing_links'] ) || '' === $saved_feeds[ $feed_id ]['outgoing_links'] ) {
				$saved_feeds[ $feed_id ]['outgoing_links'] = false;
			}
		}
		return (array) $saved_feeds;
	}

		/**
		 * Get a saved feed data from a given feed id.
		 *
		 * @since 1.0.0
		 *
		 * @access public
		 * @param string $feed_id The feed id we want to get get the data from.
		 * @return array|bool The saved feed data if success, false if not.
		 */
	public function get_feed( $feed_id ) {
		$feeds = $this->get_feeds();
		return isset( $feeds[ $feed_id ] ) ? $feeds[ $feed_id ] : false;
	}

		/**
		 * Update a feed from a given freed id and the new data to put.
		 *
		 * @since 1.0.0
		 *
		 * @access public
		 * @param string $feed_id  The feed id we want to update the data from.
		 * @param string $new_data The new data to put.
		 * @return bool true if everything works well, false if not.
		 */
	public function update_feed( $feed_id, $new_data ) {
		if ( ! isset( $feed_id, $new_data ) ) {
			return false;
		}

		$saved_feeds = WPSCORE()->get_product_option( 'AMVE', 'feeds' );

		if ( ! is_array( $saved_feeds ) ) {
			$saved_feeds = array();
		}

		foreach ( (array) $new_data as $key => $value ) {
			$saved_feeds[ $feed_id ][ $key ] = $value;
		}

		// if total videos <= 0, delete the feed.
		if ( ! isset( $saved_feeds[ $feed_id ]['total_videos'] ) || $saved_feeds[ $feed_id ]['total_videos'] <= 0 ) {
			unset( $saved_feeds[ $feed_id ] );
		}

		return WPSCORE()->update_product_option( 'AMVE', 'feeds', $saved_feeds );
	}

		/**
		 * Delete a feed from a given freed id..
		 *
		 * @since 1.0.0
		 *
		 * @access public
		 * @param string $feed_id The feed id we want to delete the data from.
		 * @return bool true if everything works well, false if not.
		 */
	public function delete_feed( $feed_id ) {
		if ( ! isset( $feed_id ) ) {
			return false;
		}

		$saved_feeds = WPSCORE()->get_product_option( 'AMVE', 'feeds' );
		if ( isset( $saved_feeds[ $feed_id ] ) ) {
			unset( $saved_feeds[ $feed_id ] );
		}
		return WPSCORE()->update_product_option( 'AMVE', 'feeds', $saved_feeds );
	}

		/**
		 * Get all expressions to translate.
		 *
		 * @since 1.0.0
		 *
		 * @access public
		 * @return array All expressions to translate.
		 */
	public function get_object_l10n() {
		return array(
			'and'                     => __( 'AND', 'amve_lang' ),
			'check_least'             => __( 'Check at least 1 video', 'amve_lang' ),
			'enable_button'           => __( 'to enable this button', 'amve_lang' ),
			'import'                  => __( 'Import', 'amve_lang' ),
			'or_keyword_if_available' => __( 'or a keyword (if it is available)', 'amve_lang' ),
			'search_feed'             => __( 'videos and save this search as a Feed. All your Feeds are displayed at the bottom of this page.', 'amve_lang' ),
			'select_cat_from'         => __( 'Select a category from', 'amve_lang' ),
			'select_wp_cat'           => __( 'Select a WordPress category', 'amve_lang' ),
		);
	}

		/**
		 * Return the reference of a given variable.
		 *
		 * @since 1.0.0
		 *
		 * @access public
		 * @param mixed $var The variable we want the reference from.
		 * @return mixed The reference of a variable.
		 */
	public function call_by_ref( &$var ) {
		return $var;
	}

		/**
		 * Overcharged media_sideload_image WordPress native function.
		 *
		 * @since 1.0.0
		 *
		 * @access public
		 * @param string     $file    The media filename.
		 * @param string|int $post_id The post id the mediafile is attached to.
		 * @param string     $desc    The description of the media file.
		 * @return mixed The reference of a variable.
		 */
	public function media_sideload_image( $file, $post_id, $desc = '' ) {
		require_once ABSPATH . 'wp-admin/includes/media.php';
		require_once ABSPATH . 'wp-admin/includes/file.php';
		require_once ABSPATH . 'wp-admin/includes/image.php';

		if ( ! empty( $file ) ) {

			// Set variables for storage, fix file filename for query strings.
			preg_match( '/[^\?]+\.(jpe?g|jpe|gif|png)\b/i', $file, $matches );
			$tmp                = explode( '.', basename( $matches[0] ) );
			$file_ext           = end( $tmp );
			$file_array         = array();
			$file_array['name'] = sanitize_title( get_the_title( $post_id ) ) . '.' . $file_ext;
			unset( $tmp, $file_ext );

			// Download file to temp location.
			$file_array['tmp_name'] = download_url( $file );

			// If error storing temporarily, return the error.
			if ( is_wp_error( $file_array['tmp_name'] ) ) {
				return $file_array['tmp_name'];
			}

			// Do the validation and storage stuff.
			$id = media_handle_sideload( $file_array, $post_id, $desc );

			// If error storing permanently, unlink.
			if ( is_wp_error( $id ) ) {
				unlink( $file_array['tmp_name'] );
				return $id;
			}
			$src = wp_get_attachment_url( $id );
		}

		// Finally check to make sure the file has been saved, then return the HTML.
		if ( ! empty( $src ) ) {
			$alt  = isset( $desc ) ? esc_attr( $desc ) : '';
			$html = "<img src='$src' alt='$alt' />";
			return $html;
		}
	}
}
