<?php
/**
 * Licensing and Update Manager Class
 * 
 * @package      Licensing Update Manager
 * @author       Tim Carr
 * @version      3.0.0
 * @copyright    WP Zinc
 */
class LicensingUpdateManager {

    /**
     * Flag to determine if we've queried the remote endpoint
     * for updates. Prevents plugin update checks running
     * multiple times
     *
     * @since   1.0.0
     *
     * @var     boolean
     */
    public $update_check = false;

    /**
     * Constructor.
     *
     * @since   1.0.0
     * 
     * @param   object  $plugin    WordPress Plugin
     * @param   string  $endpoint  Licensing Endpoint
     */
    public function __construct( $plugin, $endpoint ) {

        global $pagenow;

        // Set Plugin and Endpoint
        $this->plugin = $plugin;
        $this->endpoint = $endpoint;
        
        // Admin Notice
        $this->notice = new stdClass;

        if ( is_admin() ) {
            /**
             * Updates
             * - Delete cache if we're forcing an update check via WordPress Admin > Updates
             * - Load some JS for whitelabelling the Plugin Name, as there's no filter to use on this screen
             */
            if ( $pagenow == 'update-core.php' ) {
                add_action( 'admin_footer', array( $this, 'whitelabel_js' ) );
            }

            /**
             * Licensing Screen
             */
            if ( isset( $_GET['page'] ) && sanitize_text_field( $_GET['page'] ) == $this->plugin->name ) {
                if ( isset( $_POST[ $this->plugin->name ] ) && is_array( $_POST[ $this->plugin->name ] ) && array_key_exists( 'licenseKey', $_POST[ $this->plugin->name ] ) ) {
                    update_option( $this->plugin->name . '_licenseKey', sanitize_text_field( $_POST[ $this->plugin->name ]['licenseKey'] ) );
                }

                // Force license key check
                $this->check_license_key_valid( true );
            } else {
                // Check license key, trusting cache
                $this->check_license_key_valid( false );
            }

            // Hooks and Filters
            add_action( 'admin_notices', array( $this, 'admin_notices' ) );
            add_filter( 'plugins_api', array( $this, 'plugins_api' ), 10, 3 );

            // Whitelabelling Filters
            add_filter( 'all_plugins', array( $this, 'maybe_filter_plugin_name' ) ); // Admin > Plugins
        } else {
            // Check license key, trusting cache
            $this->check_license_key_valid( false );
        }

        // Check for updates, outside of is_admin() so WP-CLI is supported
        add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'api_check' ), 50 );
        add_action( 'delete_site_transient_update_plugins', array( $this, 'cache_delete' ) );
    
    }

    /**
     * Injects JS into the footer at Dashboard > Updates if whitelabelling is enabled
     * and the Plugin Name needs to be changed, as there is no WordPress Filter/Hook
     * to achieve this on this screen
     *
     * @since   1.0.0
     */
    public function whitelabel_js() {
        // Use JS to replace the name
        // $this->plugin->displayName will have been whitelabelled by now
        ?>
        <script>
            jQuery(document).ready(function($){
                if ( $('input[value="<?php echo $this->plugin->name . '/' . $this->plugin->name . '.php'; ?>"]').length > 0 ) {
                    $( 'td.plugin-title p strong', $('input[value="<?php echo $this->plugin->name . '/' . $this->plugin->name . '.php'; ?>"]').closest( 'tr' ) ).text( '<?php echo $this->plugin->displayName; ?>' );   
                }
            });
        </script>
        <?php

    }

    /**
     * Outputs Administration Notices relating to license key validation
     *
     * @since 3.0.0
     */
    public function admin_notices() {

        // Get cache
        $cache = $this->cache_get();
        // If here, the license is valid. Only show that it's valid if we're on the Licensing Screen
        // so we don't bombard the user with this message site-wide
        $screen = get_current_screen();
        if ( $screen->base == 'toplevel_page_' . $this->plugin->name ||
            ( isset( $_REQUEST['page'] ) && sanitize_text_field( $_REQUEST['page'] ) == $this->plugin->name ) ) {
            ?>
            <?php $cache['message'] = 'License is activated!'; ?>
            <div class="notice updated"><p><?php echo $cache['message']; ?></p></div>
            <?php
            return;
        }
    
    }

    /**
     * Gets the license key from either the wp-config constant, or the options table
     *
     * @since   3.0.0
     *
     * @return  string  License Key
     */
    public function get_license_key() {

        return 'L12345678';

    }

    /**
     * Returns a flag denoting whether the license key is stored as a PHP constant
     *
     * @since   3.0.0
     *
     * @return  bool
     */
    public function is_license_key_a_constant() {

        return false;

    }
    
    /**
     * Checks whether a license key has been specified in the settings table.
     * 
     * @since   3.0.0
     *
     * @return  bool    License Key Exists
     */                   
    public function check_license_key_exists() {
        return true;
    }   
    
    /**
     * Checks whether the license key stored in the settings table exists and is valid.
     *
     * If so, we store the latest remote plugin details in our own 'cache', which can then be used when
     * updating plugins.
     * 
     * @since   3.0.0
     *
     * @param   bool $force     Force License Key Check, ignoring cache
     * @return  bool            License Key Valid
     */
    public function check_license_key_valid( $force = false ) { 
        $this->cache_set( 
            200,
            'Page Generator Pro: Generate multiple Pages, Posts and Custom Post Types, using dynamic content selected from a number of sources.',
            '3.0.0',
            'page-generator-pro',
            ( isset( $result->features ) ? $result->features : '' ),
            ( isset( $result->features_parameters ) ? $result->features_parameters : '' )
        );

        // Maybe whitelabel the Plugin Name, now we know the license is valid
        $plugin_display_name = $this->get_feature_parameter( 'whitelabelling', 'display_name', $this->plugin->displayName );
        
        // If the Whitelabelled name exists and is different, update it in the cache now
        if ( $plugin_display_name != $this->plugin->displayName ) {
            $this->cache_set( 
                200,
                $plugin_display_name . ': ' . (string) $result->codeDescription,
                '3.0.0',
                ( isset( $result->product ) ? $result->product : '' ),
                ( isset( $result->features ) ? $result->features : '' ),
                ( isset( $result->features_parameters ) ? $result->features_parameters : '' )
            );
        }

        return true;

    }  

    /**
     * Checks to see if the License has access to a given Feature.
     *
     * @since   1.0.0
     *
     * @param   string  $feature    Feature
     */
    public function has_feature( $feature ) {


        return true;

    }

    /**
     * Returns a feature's parameter (such as whitelabelling > display name), if
     * the license's license type permits the feature and the parameter exists
     * in either wp-config (1st) or the license payload (2nd)
     *
     * @since   1.0.0
     *
     * @param   string  $feature        Feature
     * @param   string  $parameter      Parameter
     * @param   mixed   $default_value  Default Value, if Feature or Feature Parameter is not defined
     * @return  mixed                   bool| string
     */
    public function get_feature_parameter( $feature, $parameter, $default_value ) {

        // Check the license has the feature
        $has_feature = $this->has_feature( $feature );
        if ( ! $has_feature ) {
            return $default_value;
        }

        // If the Feature Parameter exists in wp-config, use that
        if ( defined( strtoupper( $this->plugin->name ) . '_' . strtoupper( $parameter ) ) ) {
            // Convert to an array depending on the parameter
            switch ( $parameter ) {
                case 'show_submenus':
                case 'permitted_users':
                    return explode( ',', constant( strtoupper( $this->plugin->name ) . '_' . strtoupper( $parameter ) ) );
                    break;

                default:
                    return constant( strtoupper( $this->plugin->name ) . '_' . strtoupper( $parameter ) );
                    break;
            } 
        }

        // Check if the Feature Parameter exists in the license payload's cache
        $cache = $this->cache_get();

        // If no feature parameter exists, bail
        if ( ! isset( $cache['features_parameters']->{ $feature } ) ) {
            return $default_value; // assumptive
        }
        if ( ! isset( $cache['features_parameters']->{ $feature }->{ $parameter } ) ) {
            return $default_value;
        }

        // Return feature parameter
        return $cache['features_parameters']->{ $feature }->{ $parameter };

    }
    
    /**
     * Hooks into the plugin update check process, telling WordPress if a newer version of our
     * Plugin is available.
     *
     * @since   3.0.0
     *
     * @param   array   $transient  Transient
     * @return  array               Transient Plugin Data
     */
    public function api_check( $transient ) {

   
        return $transient;

    }

    /**
     * Hooks into the plugins_api process, telling WordPress information about our plugin, such
     * as the WordPress compatible version and the changelog.
     *
     * @since 3.0.0
     *
     * @param object    $api    The original plugins_api object.
     * @param string    $action The action sent by plugins_api.
     * @param array     $args   Additional args to send to plugins_api.
     * @return object           New stdClass with plugin information on success, default response on failure.
     */
    public function plugins_api( $api, $action = '', $args = null ) {

        return $api;

    }

    /**
     * Filter the Plugin Name, Author Name and Plugin URI
     * if whitelabelling is enabled.
     *
     * @since   1.0.0
     *
     * @param   array   $plugins    All Installed Plugins
     * @return  array               All Installed Plugins
     */
    public function maybe_filter_plugin_name( $plugins ) {


        // Get whitelabelling values
        $display_name = $this->get_feature_parameter( 'whitelabelling', 'display_name', $this->plugin->displayName );
        $author_name = $this->get_feature_parameter( 'whitelabelling', 'author_name', $this->plugin->author_name );
        $support_url = $this->get_feature_parameter( 'whitelabelling', 'support_url', $this->plugin->support_url );
        
        // Change the Plugin Name, Author Name and URIs
        $plugins[ $this->plugin->name . '/' . $this->plugin->name . '.php' ]['Name'] = $display_name;
        $plugins[ $this->plugin->name . '/' . $this->plugin->name . '.php' ]['Title'] = $display_name;
        
        $plugins[ $this->plugin->name . '/' . $this->plugin->name . '.php' ]['Author'] = $author_name;
        $plugins[ $this->plugin->name . '/' . $this->plugin->name . '.php' ]['AuthorName'] = $author_name;
        
        $plugins[ $this->plugin->name . '/' . $this->plugin->name . '.php' ]['PluginURI'] = $support_url;
        $plugins[ $this->plugin->name . '/' . $this->plugin->name . '.php' ]['AuthorURI'] = $support_url;
    
        // Return
        return $plugins;

    }

    /**
     * Fetches cached data from the WordPress options table
     *
     * @since   1.0.0
     *
     * @return  array   Cached Data
     */
    private function cache_get() {

        // Define defaults
        $cache = array(
            'valid'     => 1,
            'message'   => '',
            'version'   => '3.0.0',
            'package'   => '',
            'features'  => '',
            'expires'   => 4070908800,
        );

        return $cache;

    } 

    /**
     * Sets cached data in the WordPress options table for a day
     *
     * @since   1.0.0
     *
     * @param   bool    $valid                  License Key Valid
     * @param   string  $message                License Key Message
     * @param   string  $version                Remote Package Version Available
     * @param   object  $package                Package Details
     * @param   array   $features               Package Features
     * @param   array   $features_parameters    Package Features Parameters
     */
    private function cache_set( $valid = false, $message = '', $version = '', $package = '', $features = '', $features_parameters = '' ) {

        update_option( $this->plugin->name . '_lum', array(
            'valid'                 => true,
            'message'               => '',
            'version'               => '3.0.0',
            'package'               => $package,
            'features'              => $features,
            'features_parameters'   => $features_parameters,
            'expires'               => 4070908800,
        ) );

        // Clear options cache, so that persistent caching solutions
        // have to fetch the latest options data from the DB
        wp_cache_delete( 'alloptions', 'options' );
        wp_cache_delete( $this->plugin->name . '_lum', 'options' );

    }

    /**
     * Deletes the cached data in the WordPress option table
     *
     * @since   1.0.0
     */
    public function cache_delete() {

        delete_option( $this->plugin->name . '_lum' );

        // Clear options cache, so that persistent caching solutions
        // have to fetch the latest options data from the DB
        wp_cache_delete( 'alloptions', 'options' );
        wp_cache_delete( $this->plugin->name . '_lum', 'options' );

    } 

}