<?php
/**
 * Plugin Name: Easy Digital Downloads - Paypal Checkout
 * Plugin URI: https://easydigitaldownloads.com/downloads/paypal-checkout
 * Description: The Paypal Checkout gateway for Easy Digital Downloads
 * Author: Easy Digital Downloads
 * Author URI: https://easydigitaldownloads.com
 * Version: 1.0.0
 * Text Domain: edd-ppc
 * Domain Path: languages
 *
 * Easy Digital Downloads - Paypal Checkout is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * any later version.
 *
 * Easy Digital Downloads - Paypal Checkout is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Easy Digital Downloads - Paypal Checkout. If not, see <http://www.gnu.org/licenses/>.
 *
 * @package EDDPPC
 * @category Extensions
 */

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

/**
 * The main plugin requirements checker
 *
 * @since 1.0
 */
final class EDD_Paypal_Checkout_Requirements_Check {

	/**
	 * Plugin file
	 *
	 * @since 1.0
	 * @var string
	 */
	private $file = '';

	/**
	 * Plugin basename
	 *
	 * @since 1.0
	 * @var string
	 */
	private $base = '';

	/**
	 * Requirements array
	 *
	 * @todo Extend WP_Dependencies
	 * @var array
	 * @since 1.0
	 */
	private $requirements = array(

		// PHP requirements.
		'php'                    => array(
			'minimum' => '5.4.0',
			'name'    => 'PHP',
			'exists'  => true,
			'current' => false,
			'checked' => false,
			'met'     => false,
		),

		// WordPress requirements.
		'wp'                     => array(
			'minimum' => '4.4.0',
			'name'    => 'WordPress',
			'exists'  => true,
			'current' => false,
			'checked' => false,
			'met'     => false,
		),

		// Easy Digital Downloads requirements.
		'easy-digital-downloads' => array(
			'minimum' => '2.0',
			'name'    => 'Easy Digital Downloads',
			'exists'  => false,
			'current' => false,
			'checked' => false,
			'met'     => false,
		),
	);

	/**
	 * Setup plugin requirements
	 *
	 * @since 1.0
	 */
	public function __construct() {

		// Setup file & base.
		$this->file = __FILE__;
		$this->base = plugin_basename( $this->file );

		// Always load translations.
		add_action( 'plugins_loaded', array( $this, 'load_textdomain' ) );

		// Load or quit.
		$this->met()
			? $this->load()
			: $this->quit();
	}

	/**
	 * Quit without loading
	 *
	 * @since 1.0
	 */
	private function quit() {
		add_action( 'admin_head', array( $this, 'admin_head' ) );
		add_filter( "plugin_action_links_{$this->base}", array( $this, 'plugin_row_links' ) );
		add_action( "after_plugin_row_{$this->base}", array( $this, 'plugin_row_notice' ) );
	}

	/** Specific Methods ******************************************************/

	/**
	 * Load normally
	 *
	 * @since 1.0
	 */
	private function load() {

		// Maybe include the bundled bootstrapper.
		if ( ! class_exists( 'Easy_Digital_Downloads_Paypal_Checkout' ) ) {
			require_once dirname( $this->file ) . '/includes/class-edd-ppc.php';
		}

		// Maybe hook-in the bootstrapper.
		if ( class_exists( 'Easy_Digital_Downloads_Paypal_Checkout' ) ) {

			// Bootstrap to plugins_loaded before priority 101 because Recurring Payments waits until 100.
			add_action( 'plugins_loaded', array( $this, 'bootstrap' ), 101 );

			// Register the activation hook.
			register_activation_hook( $this->file, array( $this, 'install' ) );
		}
	}

	/**
	 * Install, usually on an activation hook.
	 *
	 * @since 1.0
	 */
	public function install() {

		// Bootstrap to include all of the necessary files.
		$this->bootstrap();

		// Network wide?
		$network_wide = ! empty( $_GET['networkwide'] ) // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			? (bool) $_GET['networkwide'] // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			: false;

		// Call the installer directly during the activation hook.
		edd_install( $network_wide );
	}

	/**
	 * Bootstrap everything.
	 *
	 * @since 1.0
	 */
	public function bootstrap() {
		Easy_Digital_Downloads_Paypal_Checkout::instance( $this->file );
	}

	/**
	 * Plugin specific URL for an external requirements page.
	 *
	 * @since 1.0
	 * @return string
	 */
	private function unmet_requirements_url() {
		return 'https://docs.easydigitaldownloads.com/article/2051-minimum-requirements-for-edd-3-0';
	}

	/**
	 * Plugin specific text to quickly explain what's wrong.
	 *
	 * @since 1.0
	 * @return void
	 */
	private function unmet_requirements_text() {
		esc_html_e( 'This plugin is not fully active.', 'edd-ppc' );
	}

	/**
	 * Plugin specific text to describe a single unmet requirement.
	 *
	 * @since 1.0
	 * @return string
	 */
	private function unmet_requirements_description_text() {
		// Translators: The required version, and then the version that is currently installed.
		return esc_html__( 'Requires %1$s (%2$s), but (%3$s) is installed.', 'edd-ppc' );
	}

	/**
	 * Plugin specific text to describe a single missing requirement.
	 *
	 * @since 1.0
	 * @return string
	 */
	private function unmet_requirements_missing_text() {
		// Translators: The required version, and the thing that is missing.
		return esc_html__( 'Requires %1$s (%2$s), but it appears to be missing.', 'edd-ppc' );
	}

	/**
	 * Plugin specific text used to link to an external requirements page.
	 *
	 * @since 1.0
	 * @return string
	 */
	private function unmet_requirements_link() {
		return esc_html__( 'Requirements', 'edd-ppc' );
	}

	/**
	 * Plugin specific aria label text to describe the requirements link.
	 *
	 * @since 1.0
	 * @return string
	 */
	private function unmet_requirements_label() {
		return esc_html__( 'Easy Digital Downloads Paypal Checkout Requirements', 'edd-ppc' );
	}

	/**
	 * Plugin specific text used in CSS to identify attribute IDs and classes.
	 *
	 * @since 1.0
	 * @return string
	 */
	private function unmet_requirements_name() {
		return 'eddppc-requirements';
	}

	/** Agnostic Methods ******************************************************/

	/**
	 * Plugin agnostic method to output the additional plugin row
	 *
	 * @since 1.0
	 */
	public function plugin_row_notice() {
		?><tr class="active <?php echo esc_attr( $this->unmet_requirements_name() ); ?>-row">
		<th class="check-column">
			<span class="dashicons dashicons-warning"></span>
		</th>
		<td class="column-primary">
			<?php $this->unmet_requirements_text(); ?>
		</td>
		<td class="column-description">
			<?php $this->unmet_requirements_description(); ?>
		</td>
		</tr>
		<?php
	}

	/**
	 * Plugin agnostic method used to output all unmet requirement information
	 *
	 * @since 1.0
	 */
	private function unmet_requirements_description() {
		foreach ( $this->requirements as $properties ) {
			if ( empty( $properties['met'] ) ) {
				$this->unmet_requirement_description( $properties );
			}
		}
	}

	/**
	 * Plugin agnostic method to output specific unmet requirement information
	 *
	 * @since 1.0
	 * @param array $requirement The list of requirements.
	 */
	private function unmet_requirement_description( $requirement = array() ) {

		// Requirement exists, but is out of date.
		if ( ! empty( $requirement['exists'] ) ) {
			$text = sprintf(
				$this->unmet_requirements_description_text(),
				'<strong>' . esc_html( $requirement['name'] ) . '</strong>',
				'<strong>' . esc_html( $requirement['minimum'] ) . '</strong>',
				'<strong>' . esc_html( $requirement['current'] ) . '</strong>'
			);

			// Requirement could not be found.
		} else {
			$text = sprintf(
				$this->unmet_requirements_missing_text(),
				'<strong>' . esc_html( $requirement['name'] ) . '</strong>',
				'<strong>' . esc_html( $requirement['minimum'] ) . '</strong>'
			);
		}

		// Output the description.
		echo '<p>' . wp_kses_post( $text ) . '</p>';
	}

	/**
	 * Plugin agnostic method to output unmet requirements styling
	 *
	 * @since 1.0
	 */
	public function admin_head() {

		// Get the requirements row name.
		$name = $this->unmet_requirements_name();
		?>

		<style id="<?php echo esc_attr( $name ); ?>">
			.plugins tr[data-plugin="<?php echo esc_html( $this->base ); ?>"] th,
			.plugins tr[data-plugin="<?php echo esc_html( $this->base ); ?>"] td,
			.plugins .<?php echo esc_html( $name ); ?>-row th,
			.plugins .<?php echo esc_html( $name ); ?>-row td {
				background: #fff5f5;
			}
			.plugins tr[data-plugin="<?php echo esc_html( $this->base ); ?>"] th {
				box-shadow: none;
			}
			.plugins .<?php echo esc_html( $name ); ?>-row th span {
				margin-left: 6px;
				color: #dc3232;
			}
			.plugins tr[data-plugin="<?php echo esc_html( $this->base ); ?>"] th,
			.plugins .<?php echo esc_html( $name ); ?>-row th.check-column {
				border-left: 4px solid #dc3232 !important;
			}
			.plugins .<?php echo esc_html( $name ); ?>-row .column-description p {
				margin: 0;
				padding: 0;
			}
			.plugins .<?php echo esc_html( $name ); ?>-row .column-description p:not(:last-of-type) {
				margin-bottom: 8px;
			}
		</style>
		<?php
	}

	/**
	 * Plugin agnostic method to add the "Requirements" link to row actions
	 *
	 * @since 1.0
	 * @param array $links The links to add to the plugin row if requirements are not met.
	 * @return array
	 */
	public function plugin_row_links( $links = array() ) {

		// Add the Requirements link.
		$links['requirements'] =
			'<a href="' . esc_url( $this->unmet_requirements_url() ) . '" aria-label="' . esc_attr( $this->unmet_requirements_label() ) . '">'
			. esc_html( $this->unmet_requirements_link() )
			. '</a>';

		// Return links with Requirements link.
		return $links;
	}

	/** Checkers **************************************************************/

	/**
	 * Plugin specific requirements checker
	 *
	 * @since 1.0
	 */
	private function check() {

		// Loop through requirements.
		foreach ( $this->requirements as $dependency => $properties ) {

			// Which dependency are we checking?
			switch ( $dependency ) {

				// PHP.
				case 'php':
					$version = phpversion();
					break;

				// WP.
				case 'wp':
					$version = get_bloginfo( 'version' );
					break;

				// Easy Digital Downloads.
				case 'easy-digital-downloads':
					$version = defined( 'EDD_VERSION' ) ? EDD_VERSION : false;
					break;

				// Unknown.
				default:
					$version = false;
					break;
			}

			// Merge to original array.
			if ( ! empty( $version ) ) {
				$this->requirements[ $dependency ] = array_merge(
					$this->requirements[ $dependency ],
					array(
						'current' => $version,
						'checked' => true,
						'met'     => version_compare( $version, $properties['minimum'], '>=' ),
					)
				);
			}
		}
	}

	/**
	 * Have all requirements been met?
	 *
	 * @since 1.0
	 *
	 * @return boolean
	 */
	public function met() {

		// Run the check.
		$this->check();

		// Default to true (any false below wins).
		$retval  = true;
		$to_meet = wp_list_pluck( $this->requirements, 'met' );

		// Look for unmet dependencies, and exit if so.
		foreach ( $to_meet as $met ) {
			if ( empty( $met ) ) {
				$retval = false;
				continue;
			}
		}

		// Return.
		return $retval;
	}

	/** Translations **********************************************************/

	/**
	 * Plugin specific text-domain loader.
	 *
	 * @since 1.4
	 * @return void
	 */
	public function load_textdomain() {
		/*
		 * Due to the introduction of language packs through translate.wordpress.org,
		 * loading our textdomain is complex.
		 *
		 *
		 * We must look for translation files in several places and under several names.
		 *
		 * - wp-content/languages/plugins/edd-paypal-checkout (introduced with language packs)
		 * - wp-content/plugins/edd-paypal-checkout/languages/
		 *
		 * In wp-content/languages/edd-paypal-checkout/ we look for:
		 * - "edd-paypal-checkout-{lang}_{country}.mo"
		 *
		 * In wp-content/languages/plugins/edd-paypal-checkout/ we look for:
		 * - "edd-paypal-checkout-{lang}_{country}.mo"
		 *
		 */

		// Set filter for plugin's languages directory.
		$edd_lang_dir = dirname( $this->base ) . '/languages/';
		$get_locale   = function_exists( 'get_user_locale' )
			? get_user_locale()
			: get_locale();

		/**
		 * Defines the plugin language locale used in Easy Digital Downloads - Paypal Checkout.
		 *
		 * @var $get_locale The locale to use. Uses get_user_locale()` in WordPress 4.7 or greater,
		 *                  otherwise uses `get_locale()`.
		 */
		$locale = apply_filters( 'plugin_locale', $get_locale, 'edd-paypal-checkout' );
		$mofile = sprintf( '%1$s-%2$s.mo', 'edd-paypal-checkout', $locale );

		// Look in wp-content/languages/plugins/edd-paypal-checkout.
		$mofile_global1 = WP_LANG_DIR . "/plugins/edd-paypal-checkout/{$mofile}";

		// Look in wp-content/languages/edd-paypal-checkout.
		$mofile_global2 = WP_LANG_DIR . "/edd-paypal-checkout/{$mofile}";

		// Try to load from first global location.
		if ( file_exists( $mofile_global1 ) ) {
			load_textdomain( 'edd-ppc', $mofile_global1 );

			// Try to load from next global location.
		} elseif ( file_exists( $mofile_global2 ) ) {
			load_textdomain( 'edd-ppc', $mofile_global2 );

			// Load the default language files.
		} else {
			load_plugin_textdomain( 'edd-ppc', false, $edd_lang_dir );
		}
	}

}

// Invoke the checker.
new EDD_Paypal_Checkout_Requirements_Check();
