<?php
/*
Plugin Name: IVersionWP Updater for Authors
Plugin URI: http://codecanyon.net/user/IntenseVisions
Description: IVersionWP Updater for Authors - Allows Envato WordPress authors to easily provide automatic updates.
			 This is the client portion of the plugin, to be included with author themes/plugins.
Author: Intense Visions, Inc.
Author URI: http://intensevisions.com
*/


if ( !class_exists( 'IVersionWP_Client' ) ) {
	/**
	 * Class used to handle all client side license activations and auto updates of WordPress files
	 */
	class IVersionWP_Client {
		//Product Key that uniquely identifies the product on the server
		protected $product_key;

		//URL to the server that includes the server portion of this plugin
		protected $server_url;

		//The installed version of the product
		protected $current_version;

		//The plugin slug. This is used as an array key and also used to find the slug. Typically
		//it will be the directory and file name of the plugin (ex. intense/intense.php)
		protected $plugin_slug;

		//The slug will be a unique identifier for the product. It is calculated by taking the text after
		//the last slash in the $plugin_slug and removing .php from the end
		protected $slug;

		//Envato username used for marketplace api calls. This is the username of the buyer.
		protected $username;

		//Envato api key used for marketplace api calls. This is the api key of the buyer.
		protected $api_key;

		//Message displayed to remind the user to activate
		protected $activation_message;

		/**
		 * Instantiates a new IVersionWP_Client
		 *
		 * @param string  $server_url      the url to the WordPress IVersionWP Server
		 * @param string  $product_key     the product key of the product on the IVersionWP server
		 * @param string  $plugin_slug     the plugin slug including directory and file name
		 * @param string  $current_version the version of the installed product
		 */
		function __construct( $server_url, $product_key, $plugin_slug, $current_version ) {
			$this->server_url = $server_url;
			$this->product_key = $product_key;

			list ( $t1, $t2 ) = explode( '/', $plugin_slug );

			$this->plugin_slug = $plugin_slug;
			$this->slug = str_replace( '.php', '', $t2 );
			$this->current_version = $current_version;
		}

		/**
		 * Ties into the WordPress filters to make the autoupdate work. Should be called in the init phase
		 *
		 * @param string  $username the buyer username which is needed to get the download link
		 * @param string  $api_key  the buyer api key which is needed to get the download link
		 */
		public function autoupdate( $username, $api_key ) {
			$this->username = $username;
			$this->api_key = $api_key;

			// define the alternative API for update checking
			add_filter( 'pre_set_site_transient_update_plugins', array( &$this, 'update_check' ) );

			// Define the alternative response for information checking
			add_filter( 'plugins_api', array( &$this, 'check_info' ), 10, 3 );
		}

		/**
		 * Checks for a new version of the product and sets up the necessary information
		 * for WordPress to download and install the update
		 *
		 * @param object  $transient keeps track of updates. Adding to the transient lets
		 * WordPress know there is an update
		 */
		public function update_check( $transient ) {
			//Comment out these two lines during testing.
			if ( empty( $transient->checked ) )
				return $transient;

			//Get information from the server about the product. The information is used
			//to determine if an update should occur and includes information about the update
			$result = $this->server_update_check();

			if ( !empty( $result['status'] ) && $result['status'] == 'Success' && version_compare( $this->current_version, $result['version'], '<' ) ) {
				$download_url = $this->get_download_url( $result['product_id'] );

				if ( !empty( $download_url ) ) {
					$obj = new stdClass();
					$obj->slug = $this->slug;
					$obj->new_version = $result['version'];
					$obj->url = $result['product_url'];
					$obj->package = $download_url;
					$transient->response[ $this->plugin_slug ] = $obj;
				}
			}

			return $transient;
		}

		/**
		 * Gets the download url of the product that WordPress will used to install
		 * the update
		 *
		 * @return string the download url
		 */
		private function get_download_url( $product_id ) {
			add_filter( 'https_ssl_verify', '__return_false' );
			$result_from_json = wp_remote_get( 'http://marketplace.envato.com/api/edge/' . $this->username . '/' . $this->api_key . '/wp-download:' . $product_id . '.json', array( 'timeout' => 120 ) );

			if ( is_wp_error( $result_from_json ) ) {
				return null;
			}

			$result = json_decode( $result_from_json['body'], true );

			return $result['wp-download']['url'];
		}

		/**
		 * Sets up the update information which WordPress shows to the user.
		 *
		 * @param [type]  $false  [description]
		 * @param [type]  $action [description]
		 * @param [type]  $arg    [description]
		 * @return [type]         [description]
		 */
		public function check_info( $false, $action, $arg ) {
			$activation_code = $this->get_activation_code();
			
			if ( !empty( $this->slug ) &&  !empty( $arg->slug ) && $arg->slug === $this->slug && !empty( $activation_code ) ) {
				$result = $this->server_update_check();

				if ( !empty( $result ) ) {
					$obj = new stdClass();
					$obj->slug = $this->slug;
					$obj->name = $result['product_name'];
					$obj->new_version = $result['version'];
					$obj->requires = $result['requires']; //WordPress version required for product
					$obj->tested = $result['tested']; //Update tested in this WordPress version
					//$obj->downloaded = 12345;
					$obj->last_updated = $result['last_update'];
					$obj->sections = array(); //each section will show as a tab in the update info

					if ( !empty( $result['product_description'] ) ) {
						$obj->sections['description'] = $result['product_description'];
					}

					if ( !empty( $result['installation'] ) ) {
						$obj->sections['installation'] = $result['installation'];
					}

					if ( !empty( $result['changelog'] ) ) {
						$obj->sections['changelog'] = $result['changelog'];
					}

					if ( !empty( $result['notes'] ) ) {
						$obj->sections['notes'] = $result['notes'];
					}

					return $obj;
				} else {
					return false;
				}
			}

			return false;
		}

		/**
		 * Gets the latest information about the product from the IVersionWP server
		 *
		 * @return array the information about the product
		 */
		public function server_update_check( ) {
			$activation_code = $this->get_activation_code();

			if ( !empty( $activation_code ) ) {
				add_filter( 'https_ssl_verify', '__return_false' );
				$result_from_json = wp_remote_get( $this->server_url . '/wp-admin/admin-ajax.php?action=iversionwp&mode=checkupdate&activation_code=' . rawurlencode( $activation_code ), array( 'timeout' => 120 ) );

				if ( is_wp_error( $result_from_json ) ) {
                    echo '<div id="message" class="error"><p>' . $result_from_json->get_error_message() . '</p></div>';                    
                    return null; 
                }

				$result = json_decode( $result_from_json['body'], true );
			} else {
				$result = null;
			}

			return $result;
		}

		/**
		 * Gets the recorded activation code
		 *
		 * @return string the code saved after a successful activation
		 */
		public function get_activation_code() {
			if ( is_multisite() ) {
				return get_site_option( 'ivwp_' . $this->product_key . '_activation_code' );
			} else {
				return get_option( 'ivwp_' . $this->product_key . '_activation_code' );
			}
		}

		/**
		 * Indicates if the product has been activated
		 *
		 * @return boolean [description]
		 */
		public function is_activated() {
			$activation_code = $this->get_activation_code();
			$activated = !empty( $activation_code  );

			return $activated;
		}

		/**
		 * Activates the product with the IVersionWP server
		 *
		 * @param string  $username      The buyer username
		 * @param string  $api_key       The buyer Envato api key
		 * @param string  $purchase_code The Envato purchase code
		 * @param string  $email         The user's email (optional)
		 * @param string  $first_name    The user's first name (optional)
		 * @param string  $last_name     The user's last name (optional)
		 * @param bool    $subscribe     Subscribe the user to email notifications
		 * @return array                The activation results
		 */
		public function activate( $username, $api_key, $purchase_code, $email, $first_name, $last_name, $subscribe ) {
			add_filter( 'https_ssl_verify', '__return_false' );		
			$result_from_json = wp_remote_get( $this->server_url . '/wp-admin/admin-ajax.php?action=iversionwp&mode=activate&username=' . rawurlencode( $username ) . '&api_key=' . rawurlencode( $api_key ) . '&purchase_code=' . rawurlencode( $purchase_code ) . '&product=' . rawurlencode( $this->product_key ) . '&email=' . rawurlencode( $email ) . '&first_name=' . rawurlencode( $first_name ) . '&last_name=' . rawurlencode( $last_name ) . '&subscribe=' . rawurlencode( $subscribe ), array( 'timeout' => 120 ) );

			if ( is_wp_error( $result_from_json ) ) {
				return array('status' => 'Failed', 'description' => $result_from_json->get_error_message());				
			}

			$result = json_decode( $result_from_json['body'], true );
			if ( !empty( $result['status'] ) && $result['status'] == 'Success' ) {
				//add/update activation-code for this product_key
				$activation_code = $result['activation_code'];

				if ( is_multisite() ) {
					update_site_option( 'ivwp_' . $this->product_key . '_activation_code', $result['activation_code'] );
				} else {
					update_option( 'ivwp_' . $this->product_key . '_activation_code', $result['activation_code'] );
				}
			}

			return $result;
		}

		/**
		 * Deactivates the product with the IVersionWP server
		 *
		 * @return array The deactivation results
		 */
		public function deactivate() {
			$activation_code = $this->get_activation_code();
			add_filter( 'https_ssl_verify', '__return_false' );
			$result_from_json = wp_remote_get( $this->server_url . '/wp-admin/admin-ajax.php?action=iversionwp&mode=deactivate&activation_code=' . rawurlencode( $activation_code ), array( 'timeout' => 120 ) );

			if ( is_wp_error( $result_from_json ) ) {
				return array('status' => 'Failed', 'description' => $result_from_json->get_error_message());
			}

			$result = json_decode( $result_from_json['body'], true );

			if ( !empty( $result['status'] ) && $result['status'] == 'Success' ) {
				//add/update activation-code for this product_key
				$activation_code = false;

				if ( is_multisite() ) {
					delete_site_option( 'ivwp_' . $this->product_key . '_activation_code' );
				} else {
					delete_option( 'ivwp_' . $this->product_key . '_activation_code' );
				}
				
			} else if ( !empty( $result['status'] ) && $result['status'] == 'Failed' && $result['description'] == 'The activation was missing.' ) {
				//add/update activation-code for this product_key
				$activation_code = false;
				
				if ( is_multisite() ) {
					delete_site_option( 'ivwp_' . $this->product_key . '_activation_code' );
				} else {
					delete_option( 'ivwp_' . $this->product_key . '_activation_code' );
				}
			}

			return $result;
		}

		/**
		 * Sets up a reminder notice about plugin activation
		 * @param  [type] $message [description]
		 * @return [type]          [description]
		 */
		public function setup_activation_reminder( $message ) {
			$this->activation_message = $message;

			if ( ! $this->is_activated() && empty( $_COOKIE[ 'iversionwp-hide-activation-reminder-' . $this->slug ] ) ) {
				add_action( 'admin_notices', array( &$this, 'activation_reminder' ) );					
			}
		}

		/**
		 * Activation reminder html/css/js		 
		 */
		public function activation_reminder(  ) {
			global $iversionwp_reminder_script_set;

			echo '<div class="updated iversionwp ' . $this->slug . '" style="position: relative;" data-slug="' . $this->slug . '"><p>' . $this->activation_message . '</p><div class="iversionwp-activation-reminder-close">&times;</div></div>';		

			if ( empty( $iversionwp_reminder_script_set ) ) {
				$iversionwp_reminder_script_set = true;
				?>
				<style>
				.updated.iversionwp .iversionwp-activation-reminder-close {
					position: absolute;
					top: 5px;
					right: 6px;
					cursor: pointer;
					font-weight: bold;
					font-size: 20px;
					color: #aaa;
				}
				</style>
				<script>

				jQuery(function($) {
					function iversionwpSetCookie(cname, cvalue, exdays) {
						var d = new Date();						
						d.setTime(d.getTime() + (exdays*24*60*60*1000));
						var expires = "expires="+d.toUTCString();
						document.cookie = cname + "=" + cvalue + "; " + expires;
					}

					$(document).ready(function() {
						$('.iversionwp-activation-reminder-close').click(function(e) {
							var slug = $(this).parent().data('slug');

							e.preventDefault();
							iversionwpSetCookie('iversionwp-hide-activation-reminder-' + slug, 1, 14);
							$(this).parent().slideUp();
						});
					});
				});

				</script>
				<?php
			}
		}
	}
}