<?php
/**
 * This class is based on the new ENVATO 3.0 API and handles the automatic theme update
 *
 * @since 4.4.3
 * @added_by Günter
 *
 * to debug: set_site_transient('update_themes',null);
 */
if( ! defined( 'ABSPATH' ) ) {  exit;  }    // Exit if accessed directly


if( ! class_exists( 'Avia_Theme_Updater' ) )
{
	class Avia_Theme_Updater
	{
		/**
		 * Holds the instance of this class
		 *
		 * @since 4.4.3
		 * @var Avia_Theme_Updater
		 */
		static private $_instance = null;

		/**
		 * Envato author name(s) for the themes/plugins to check
		 *
		 * @var string|array
		 */
		protected $authors;

		/**
		 * Envato Personal Token Key
		 *
		 * @since 4.4.3
		 * @var string
		 */
		protected $personal_token;

		/**
		 *
		 * @since 4.4.3
		 * @var Avia_Envato_Base_API
		 */
		protected $envato_api;

		/**
		 * function wp_update_themes calls filter pre_set_site_transient_update_themes twice during theme version check.
		 * As we have a rate limiting by Envato we cache the result here. We also cache the results in a transient.
		 *
		 * @since 4.4.3
		 * @var array
		 */
		protected $envato_results_cache;

		/**
		 * Optionname that saves state of last update - especially if there are Rate Limiting errors
		 *
		 * @since 4.4.3
		 * @var string
		 */
		protected $transient_logfile_name;

		/**
		 * Optionname that saves last update from envato to avoid multiple calls within a given period
		 *
		 * @since 4.5.2
		 * @var string
		 */
		protected $transient_cache_name;

		/**
		 * Return the instance of this class
		 *
		 * @since 4.4.3
		 * @param array $args
		 * @return Avia_Theme_Updater
		 */
		static public function instance( array $args = array() )
		{
			if( is_null( Avia_Theme_Updater::$_instance ) )
			{
				Avia_Theme_Updater::$_instance = new Avia_Theme_Updater( $args );
			}

			return Avia_Theme_Updater::$_instance;
		}

		/**
		 * @since 4.4.3
		 * @param array $args
		 */
		protected function __construct( array $args )
		{
			$this->authors = array();
			$this->personal_token = '';
			$this->envato_api = null;
			$this->envato_results_cache = null;
			$this->transient_logfile_name = '';
			$this->transient_cache_name = '';

			$this->init( $args );

			add_filter( 'pre_set_site_transient_update_themes', array( $this, 'handler_pre_set_site_transient_update_themes' ), 10, 1 );
			add_filter( 'upgrader_package_options', array( $this, 'handler_upgrader_package_options' ), 1000, 1 );
//			add_filter( 'upgrader_post_install', array( $this, 'handler_upgrader_post_install' ), 1000, 3 );
		}

		/**
		 * @since 4.4.3
		 */
		public function __destruct()
		{
			unset( $this->authors );
			unset( $this->envato_api );
			unset( $this->envato_results_cache );
		}

		/**
		 * Allows a late initialisation of the object
		 *
		 * @since 4.4.3
		 * @param array $args
		 */
		public function init( array $args )
		{
			if( isset( $args['authors'] ) )
			{
				$this->authors = $args['authors'];

				if( ! is_array( $this->authors ) )
				{
					$this->authors = array( $this->authors );
				}
			}

			$old_token = $this->personal_token;

			if( isset( $args['personal_token'] ) )
			{
				$this->personal_token = $args['personal_token'];
			}

			if( $old_token != $this->personal_token )
			{
				unset( $this->envato_api );
				$this->envato_api = null;
			}
		}


		/**
		 *
		 * @since 4.4.3
		 * @param string $new_token
		 * @return Avia_Envato_Base_API|false
		 */
		protected function get_envato_api( $new_token = '' )
		{
			$token = ( empty( $new_token ) ) ? $this->personal_token : $new_token;

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

			if( ! class_exists( 'Avia_Envato_Base_API' ) )
			{
				require_once( 'class-avia-envato-base-api.php' );
			}

			if( ! empty( $new_token ) )
			{
				return new Avia_Envato_Base_API( $new_token, avia_auto_updates::get_theme_name(), avia_auto_updates::get_version() );
			}

			if( empty( $this->envato_api ) )
			{
				$this->envato_api = new Avia_Envato_Base_API( $this->personal_token, avia_auto_updates::get_theme_name(), avia_auto_updates::get_version() );
			}

			return $this->envato_api;
		}


		/**
		 * Checks for theme update and adds theme package to update array
		 *
		 * @since 4.4.3
		 * @param stdClass $updates
		 * @return stdClass
		 */
		public function handler_pre_set_site_transient_update_themes( $updates )
		{
			/**
			 * Filter for theme updater transient
			 */
			if( ! isset( $updates->checked ) )
			{
				return $updates;
			}

			$this->authors = apply_filters( 'avf_theme_updater_authors', $this->authors );
			$this->personal_token = apply_filters( 'avf_theme_updater_personal_token', $this->personal_token );

			$api = $this->get_envato_api();
			if( ! $api instanceof Avia_Envato_Base_API )
			{
				/**
				 * We have no Envato token -> clear all saved log data and cache
				 */
				$this->clear_updater_log();
				$this->clear_cache();

				return $updates;
			}

			if( current_theme_supports( 'avia_envato_extended_log' ) )
			{
				$this->add_to_updater_log( new Avia_Envato_Exception( __( 'Theme update check started', 'avia_framework' ) ) );
			}

			/**
			 * If we have already cached the result from Envato we can take this and avoid multiple requests for the same data
			 */
			if( $this->get_cache() )
			{
				if( ! empty( $this->envato_results_cache ) )
				{
					$purchases = avia_auto_updates::get_theme_keys();

					/**
					 * Check if theme has updated already and remove from cache
					 */
					foreach( $this->envato_results_cache as $theme => $update )
					{
						$theme_key = '';
						$stylesheet = '';
						foreach( $purchases as $name => $purchase )
						{
							if( $purchase['item']['wordpress_theme_metadata']['stylesheet'] == $theme )
							{
								$theme_key = $name;
								$stylesheet = $purchases[ $name ]['item']['wordpress_theme_metadata']['stylesheet'];
								break;
							}
						}

						$do_update = false;
						if( ! empty( $theme_key ) && isset( $purchases[ $theme_key ]['item']['wordpress_theme_metadata']['version'] ) )
						{
							if( version_compare( $purchases[ $theme_key ]['item']['wordpress_theme_metadata']['version'], $update['new_version'], '<' ) )
							{
								$do_update = true;
							}
							else if( version_compare( $purchases[ $theme_key ]['item']['wordpress_theme_metadata']['version'], $update['new_version'], '=' ) )
							{
								unset( $this->envato_results_cache[ $theme ] );
								$this->update_cache();
							}
						}

						if( $do_update )
						{
							$updates->response[ $theme ] = $update;
						}
						else if( array_key_exists( $theme, $updates->response ) )
						{
							unset( $updates->response[ $theme ] );
						}
					}
				}

				if( current_theme_supports( 'avia_envato_extended_log' ) )
				{
					$this->add_to_updater_log( new Avia_Envato_Exception( __( 'Cache used', 'avia_framework' ) ) );
				}

				return $updates;
			}

			if( current_theme_supports( 'avia_envato_extended_log' ) )
			{
				$this->add_to_updater_log( new Avia_Envato_Exception( __( 'No cache, Envato API request started', 'avia_framework' ) ) );
			}

			try
			{
				$purchases = avia_auto_updates::get_theme_keys();

				/**
				 * Backwards comp. for WP - keep existing code in case we need a fallback
				 * @since 4.5.3
				 */
				if( current_theme_supports( 'avia_envato_purchase_query' ) || ! function_exists( 'wp_get_themes' ) )
				{
					$purchases = $api->get_purchases();
				}
				else
				{
					$purchases = $api->get_product_infos( $purchases );
				}

				$installed = function_exists( 'wp_get_themes' ) ? wp_get_themes() : get_themes();
				$filtered = array();

				/**
				 * Attention:	In case there are multiple installs of the same theme in different folders
				 * =========	only the last folder is kept for update. As this is a rare situation in
				 *				production sites we can ignore this.
				 */
				foreach( $installed as $theme )
				{
					if( ! in_array( $theme->{'Author Name'}, $this->authors ) )
					{
						continue;
					}

					$filtered[ $theme->Name ] = $theme;
				}
			}
			catch ( Avia_Envato_Exception $ex )
			{
				$this->add_to_updater_log( $api );
				return $updates;
			}

			$errors_occured = false;
			$package_errors = array();

			foreach( $purchases as $purchase )
			{
				$theme_name = isset( $purchase['item']['wordpress_theme_metadata']['theme_name'] ) ? $purchase['item']['wordpress_theme_metadata']['theme_name'] : '';
				if( ! empty( $theme_name ) && isset( $filtered[ $theme_name ] ) )
				{
					/**
					 * Found the theme - check if we need to update
					 */
					$current = $filtered[ $theme_name ];
					if( version_compare( $current->Version, $purchase['item']['wordpress_theme_metadata']['version'], '<' ) )
					{
						try
						{
							$update = array(
											'url'				=> $purchase['item']['url'],
											'new_version'		=> $purchase['item']['wordpress_theme_metadata']['version'],
											'envato_item_id'	=> $purchase['item']['id'],
											'package'			=> ''
										);

							$updates->response[ $current->Stylesheet ] = $update;
							$this->add_to_cache( $current->Stylesheet, $update );

							if( current_theme_supports( 'avia_envato_extended_log' ) )
							{
								$this->add_to_updater_log( new Avia_Envato_Exception( sprintf( __( 'Existing download package found for %s - %s', 'avia_framework' ), $current->Name, $update['new_version'] ) ) );
							}
						}
						catch( Avia_Envato_Exception $ex )
						{
							$errors_occured = true;
							$package_errors[] = $current->Name . ' - ' . $purchase['item']['wordpress_theme_metadata']['version'];
							continue;
						}
					}
				}
			}

			/**
			 * In case of an error we should try again to get the results.
			 * As we had troubles with too many requests we keep what we have and try again
			 * when cache is expired.
			 */
			if( $errors_occured )
			{
//				$this->clear_local_cache();
			}

			$this->update_cache();

			$this->add_to_updater_log( $api, $package_errors );
			return $updates;
		}


		/**
		 * Get download URL for our products from Envato
		 *
		 * @since 4.5.3
		 * @param array $options
		 * @return array
		 */
		public function handler_upgrader_package_options( array $options )
		{
			/**
			 * Ignore, if a package URL is already set - not our product
			 */
			if( ! empty( $options['package'] ) )
			{
				return $options;
			}


			$api = $this->get_envato_api();
			if( ! $api instanceof Avia_Envato_Base_API )
			{
				return $options;
			}

			/**
			 * At the moment we only have theme(s) to update
			 */
			if( empty( $options['hook_extra']['theme'] ) )
			{
				return $options;
			}

			$stylesheet = $options['hook_extra']['theme'];

			$purchases = avia_auto_updates::get_theme_keys();

			$product = null;
			foreach( $purchases as $theme => $purchase )
			{
				if( $purchase['item']['wordpress_theme_metadata']['stylesheet'] == $stylesheet )
				{
					$product = $purchase;
					break;
				}
			}

			if( is_null( $product ) )
			{
				return $options;
			}

			if( current_theme_supports( 'avia_envato_extended_log' ) )
			{
				$this->add_to_updater_log( new Avia_Envato_Exception( $purchase['item']['wordpress_theme_metadata']['theme_name'] . ': ' . __( 'Envato API request for download URL started', 'avia_framework' ) ) );
			}

			$errors_occured = false;
			$package_errors = array();

			try
			{
				$options['package'] = $api->get_wp_download_url( $product['item']['id'] );
			}
			catch( Avia_Envato_Exception $ex )
			{
				$options['package'] = '';
				$errors_occured = true;
				$package_errors[] = $purchase['item']['wordpress_theme_metadata']['theme_name'] . ' - ' . __( 'Request for Download URL failed.', 'avia_framework' );
			}

			if( $errors_occured )
			{
				$this->add_to_updater_log( $api, $package_errors );
			}

			if( current_theme_supports( 'avia_envato_extended_log' ) )
			{
				$this->add_to_updater_log( new Avia_Envato_Exception( $purchase['item']['wordpress_theme_metadata']['theme_name'] . ': ' . __( 'Envato API request for download URL finished', 'avia_framework' ) ) );
			}

			return $options;
		}


		/**
		 * Not needed - only kept for reference in case we might need it
		 *
		 * @since 4.5.4
		 * @param bool  $response   Installation response.
		 * @param array $hook_extra Extra arguments passed to hooked filters.
		 * @param array $result     Installation result data.
		 * @return boolean
		 */
		public function handler_upgrader_post_install( $response, array $hook_extra, array $result )
		{
//			if( true !== $response )
//			{
//				return $response;
//			}

//			$cache = $this->get_cache();
//			if( false === $cache )
//			{
//				return $response;
//			}
//
//			if( empty( $hook_extra['theme'] ) )
//			{
//				return $response;
//			}
//
//			if( isset( $this->envato_results_cache[ $hook_extra['theme'] ] ) )
//			{
//				unset( $this->envato_results_cache[ $hook_extra['theme'] ] );
//				$this->update_cache();
//			}

			return $response;
		}

		/**
		 * Output the HTML below the verify input field
		 * Keep backwards comp with old API - but do not allow to enter new values
		 *
		 * @since 4.4.3
		 * @param string $new_token
		 * @param boolean $ajax
		 * @return string
		 */
		public function backend_html( $new_token, $ajax )
		{
			$new_token = trim( $new_token );

			$data = array(
					'updates_envato_token'			=> trim( avia_get_option( 'updates_envato_token' ) ),
					'updates_envato_token_state'	=> trim( avia_get_option( 'updates_envato_token_state' ) ),
					'updates_envato_verified_token'	=> trim( avia_get_option( 'updates_envato_verified_token' ) ),
					'updates_username'				=> trim( avia_get_option( 'updates_username' ) ),
					'updates_api_key'				=> trim( avia_get_option( 'updates_api_key' ) ),
					'updates_envato_info'			=> trim( avia_get_option( 'updates_envato_info' ) )
				);

			if( $ajax )
			{
				$data = $this->verify_token( $data, $new_token );
			}

			$notice = '';
			$deprecated = '';

			if( ! empty( $new_token ) )
			{
				$default = array(
								'purchases'	=> '',
								'username'	=> '',
								'email'		=> '',
								'errors'	=> ''
							);

				$arr_info = json_decode( $data['updates_envato_info'] );
				$arr_info = wp_parse_args( $arr_info, $default );


				$purchases = ! empty( $arr_info['purchases'] ) ? __( 'Your purchases', 'avia_framework' ) : __( 'Purchases could not be accessed', 'avia_framework' );
				$username = ! empty( $arr_info['username'] ) ? __( 'Your username: ', 'avia_framework' ) . $arr_info['username'] : __( 'Username could not be accessed (needed for your information only)', 'avia_framework' );
				$email = ! empty( $arr_info['email'] ) ? __( 'Your E-Mail: ', 'avia_framework' ) . $arr_info['email']  : __( 'E-Mail could not be accessed (needed for your information only)', 'avia_framework' );

				$error_msg = '';
				if( ! empty( $arr_info['errors'] ) )
				{
					$error_msg .=	'<p>';
					$error_msg .=		__( 'Following errors occurred:', 'avia_framework' );
					$error_msg .=	'</p>';
					$error_msg .=	'<ul>';
					foreach ( $arr_info['errors'] as $value )
					{
						$error_msg .=	'<li>' . $value . '</li>';
					}
					$error_msg .=	'</ul>';
				}

				if( ! empty( $data['updates_envato_token_state'] ) )
				{
					$warning = '';
					if( $ajax )
					{
						$data['updates_envato_verified_token'] = $new_token;
					}
					else if( $data['updates_envato_token'] != $data['updates_envato_verified_token'] )
					{
						$warning .=		'<div class="av-verification-cell av-privacy-token-notice av-update-token-changed" style="font-size: 1.5em;">';

						if( '' == $data['updates_envato_verified_token'] )
						{
							$warning .=		__( 'Please verify the key.', 'avia_framework' );
						}
						else
						{
							$warning .=		__( 'Please verify the key - the last verified key is different.', 'avia_framework' );
						}

						$warning .=		'</div>' ;
					}

					$notice .=	'<div class="av-text-notice">';
					$notice .=		$warning;
					$notice .=		'<p>';
					$notice .=			sprintf( __( 'We checked the token on %s and we were able to connect to Envato and could access the following information:', 'avia_framework' ), $data['updates_envato_token_state'] );
					$notice .=		'</p>';
					$notice .=		'<ul>';
					$notice .=			'<li>' . $purchases . '</li>';
					$notice .=			'<li>' . $username . '</li>';
					$notice .=			'<li>' . $email . '</li>';
					$notice .=		'</ul>';
					$notice .=		$error_msg;
					$notice .=	'</div>';

					$notice .=	'<div class="av-verification-cell av-privacy-token-notice">';
					$notice .=		__( 'If you ever edit the restrictions of your personal token please re-validate it again to test if it works properly', 'avia_framework' );
					$notice .=	'</div>';
				}
				else
				{
					$notice .=	'<div class="av-text-notice av-notice-error">';
					$notice .=		'<p>';
					$notice .=			sprintf( __( 'Last time we checked the token we were not able to connected to Envato:', 'avia_framework' ), $data['updates_envato_token_state'] );
					$notice .=		'</p>';
					$notice .=		'<ul>';
					$notice .=			'<li>' . $purchases . '</li>';
					$notice .=			'<li>' . $username . '</li>';
					$notice .=			'<li>' . $email . '</li>';
					$notice .=		'</ul>';
					$notice .=		$error_msg;
					$notice .=	'</div>';
				}
			}

			/**
			 * Backwards compatibility (can be removed in future when Envato API < 3.0 is deprecated):
			 *
			 * Add a message to switch to new API and show old API access info.
			 *
			 * @since 4.4.3
			 */
			if( empty( $new_token ) && ! empty( $data['updates_username'] ) && ! empty( $data['updates_api_key'] ) )
			{
				$old_api = '';
				$info = '';

				$old_api .=		'<p class="av-text-notice av-notice-error av-notice-noborder">';
				$old_api .=			__( 'Attention: The old Envato API is deprecated and will be shut down soon. In order to be able to use automated theme updates please generate a new valid API token and enter it above. Your themeforest username and your old API key will then be removed from your installation since they are no longer required.', 'avia_framework' );
				$old_api .=		'</p>';

				$info .=	'<div class="avia_section avia_text">';
				$info .=		'<h4>' . __( 'Your Themeforest User Name:', 'avia_framework' ) . '</h4>';
				$info .=		'<div class="avia_control_container">';
				$info .=			'<div class="avia_control">';
				$info .=				'<div class="avia_style_wrap">';
				$info .=					'<input class="" value="' . $data['updates_username'] . '" readonly="readonly" type="text">';
				$info .=				'</div>';
				$info .=			'</div>';
				$info .=		'</div>';
				$info .=	'</div>';

				$info .=	'<div class="avia_section avia_text">';
				$info .=		'<h4>' . __( 'Your Themeforest API Key', 'avia_framework' ) . '</h4>';
				$info .=		'<div class="avia_control_container">';
				$info .=			'<div class="avia_control">';
				$info .=				'<div class="avia_style_wrap">';
				$info .=					'<input class="" value="' . $data['updates_api_key'] . '" readonly="readonly" type="text">';
				$info .=				'</div>';
				$info .=			'</div>';
				$info .=		'</div>';
				$info .=	'</div>';


				$deprecated .=	'<div class="avia_section avia_envato_deprecated-section">';
				$deprecated .=		$old_api;
				$deprecated .=		$info;
				$deprecated .=	'</div>';
			}

			$output  = 'avia_trigger_save ';
			$output .=	'<div class="av-verification-response-wrapper">';
			$output .=		$notice;
			$output .=		$deprecated;
			$output .=	'</div>';

			if( $ajax )
			{
				$response['html'] = $output;
				unset( $data['updates_envato_token'] );
				$response['update_input_fields'] = $data;
			}
			else
			{
				$response = $output;
			}

			return $response;
		}

		/**
		 * Check the given token with Envato API. Tries to access:
		 *		- purchases
		 *		- username
		 *		- email
		 *
		 * @since 4.4.3
		 * @param array $data
		 * @param string $new_token
		 * @return array
		 */
		protected function verify_token( array $data, $new_token )
		{
			$old_token = $data['updates_envato_token'];

			if( '' == $new_token )
			{
				$this->clear_updater_log();

				$data['updates_envato_token_state'] = '';
				$data['updates_envato_info'] = '';
				return $data;
			}

			if( $old_token != $new_token )
			{
				$this->clear_updater_log();
			}

			$api = $this->get_envato_api( $new_token );

			$info = array();

			try
			{
				$purchases = $api->get_purchases();
				$info['purchases'] = 'success';
			}
			catch ( Avia_Envato_Exception $ex )
			{
				$info['purchases'] = '';
			}

			try
			{
				$info['username'] = $api->get_userdata( 'username' );
			}
			catch ( Avia_Envato_Exception $ex )
			{
				$info['username'] = '';
			}

			try
			{
				$info['email'] = $api->get_userdata( 'email' );
			}
			catch ( Avia_Envato_Exception $ex )
			{
				$info['email'] = '';
			}

			$errors = $api->get_errors();
			if( $errors instanceof WP_Error )
			{
				$info['errors'] = $errors->get_error_messages();
			}

			$data['updates_envato_token'] = $new_token;
			$data['updates_envato_token_state'] = ! empty( $info['purchases'] ) ? date( 'Y/m/d H:i' ) : '';
			$data['updates_envato_info']  = json_encode( $info );

			/**
			 * Remove deprecated data
			 */
			$data['updates_username'] = '';
			$data['updates_api_key'] = '';

			return $data;
		}


		/**
		 * Returns the transient logfile name depending on theme name
		 *
		 * @since 4.4.3
		 * @return string
		 */
		public function get_logfile_name()
		{
			if( empty( $this->transient_logfile_name ) )
			{
				$this->transient_logfile_name = apply_filters( 'avf_theme_updater_transient_logfile_name', '_av_' . avia_auto_updates::get_themename( 'parent' ) . '_updater_log' );
			}

			return Avia_Theme_Updater::validate_transient( $this->transient_logfile_name );
		}

		/**
		 * Returns the transient logfile name depending on theme name
		 *
		 * @since 4.5.2
		 * @return string
		 */
		public function get_cache_name()
		{
			if( empty( $this->transient_cache_name ) )
			{
				$this->transient_cache_name = apply_filters( 'avf_theme_updater_transient_cache_name', '_av_' . avia_auto_updates::get_themename( 'parent' ) . '_updater_cache' );
			}

			return Avia_Theme_Updater::validate_transient( $this->transient_cache_name );
		}


		/**
		 * Tries to read cache from transient and stores it in local array
		 *
		 * @since 4.5.2
		 * @return boolean				true, if cache exists
		 */
		protected function get_cache()
		{
			static $force_check_executed = false;

			if( is_array( $this->envato_results_cache ) )
			{
				return true;
			}

			/**
			 * From theme option page we want to force a check
			 */
			if( isset( $_REQUEST['force-check'] ) && ! $force_check_executed )
			{
				$force_check_executed = true;
				return false;
			}

			$transient = $this->get_cache_name();
			$cache = get_transient( $transient );

			if( false === $cache || ! is_array( $cache ) )
			{
				return false;
			}

			$this->envato_results_cache = $cache;
			return true;
		}

		/**
		 * Add update info to internal cache array
		 *
		 * @since 4.5.2
		 * @param string $theme_name
		 * @param array $update
		 */
		protected function add_to_cache( $theme_name, $update )
		{
			if( ! is_array( $this->envato_results_cache ) )
			{
				$this->envato_results_cache = array();
			}

			$this->envato_results_cache[ $theme_name ] = $update;
		}

		/**
		 * Clears the local cache
		 *
		 * @since 4.5.2
		 */
		protected function clear_local_cache()
		{
			unset( $this->envato_results_cache );
			$this->envato_results_cache = null;
		}

		/**
		 * Saves cache to transient
		 *
		 * @since 4.5.2
		 * @param boolean $set_locale
		 */
		protected function update_cache( $set_locale = false )
		{
			/**
			 * We block update requests in any case to limit Envato API calls for download URL's !!
			 */
			$cache = is_array( $this->envato_results_cache ) ? $this->envato_results_cache : array();

			if( $set_locale )
			{
				$this->envato_results_cache = $cache;
			}

			$transient = $this->get_cache_name();
			$timeout = apply_filters( 'avf_updater_cache_timeout', 12 * HOUR_IN_SECONDS );

			return set_transient( $transient, $cache, $timeout );
		}

		/**
		 * Clears local and saved cache and removes the transient
		 *
		 * @since 4.5.2
		 */
		protected function clear_cache()
		{
			$this->clear_local_cache();

			$transient = $this->get_cache_name();
			delete_transient( $transient );
		}

		/**
		 * Returns the stored transient or an empty array
		 *
		 * @since 4.4.3
		 * @return array
		 */
		public function get_updater_log()
		{
			$transient = $this->get_logfile_name();
			$log = get_transient( $transient );
			return ( false !== $log ) ? $log : array();
		}

		/**
		 * Updates the transient
		 *
		 * @since 4.4.3
		 * @param array $log
		 * @return boolean
		 */
		protected function update_updater_log( array $log )
		{
			$transient = $this->get_logfile_name();
			$timeout = apply_filters( 'avf_updater_log_timeout', MONTH_IN_SECONDS );

			return set_transient( $transient, $log, $timeout );
		}

		/**
		 * Reset transient to an empty array
		 *
		 * @since 4.4.3
		 * @return boolean
		 */
		protected function clear_updater_log()
		{
			return $this->update_updater_log( array() );
		}


		/**
		 * Adds an update message to the queue and removes the oldest if necessary
		 *
		 * @since 4.4.3
		 * @param Avia_Envato_Base_API|Avia_Envato_Exception  $info
		 * @param array $package_errors
		 * @param string $clear_errors									'clear_errors' | 'no_clear_errors'
		 * @return boolean
		 */
		protected function add_to_updater_log( $info, $package_errors = null, $clear_errors = 'clear_errors' )
		{
			$log = $this->get_updater_log();

			$entries = ! current_theme_supports( 'avia_envato_extended_log' ) ? 20 : 500;
			$max_entries = apply_filters( 'avf_updater_log_max_entries', $entries );

			if( count( $log ) >= $max_entries )
			{
				$log = array_slice( $log, count( $log ) - $max_entries + 1 );
			}

			if( $info instanceof Avia_Envato_Base_API )
			{
				$entry = array(
								'time'		=> date( 'Y/m/d H:i' ),
								'errors'	=> array(),
							);

				$errors = $info->get_errors();
				if( $errors instanceof WP_Error )
				{
					$entry['errors'] = $errors->get_error_messages();
				}

				if( is_array( $package_errors ) )
				{
					$entry['package_errors'] = $package_errors;
				}

				$log[] = $entry;

				if( 'clear_errors' == $clear_errors )
				{
					$info->clear_errors();
				}
			}
			else if( $info instanceof Avia_Envato_Exception )
			{
				$log[] = array(
							'time'		=> date( 'Y/m/d H:i' ),
							'info'		=> $info->getMessage()
						);
			}

			return $this->update_updater_log( $log );
		}

		/**
		 * Helper function to validate transient ID's.
		 *
		 * @since 4.4.3
		 * @param string $transient
		 * @return string
		 */
		static public function validate_transient( $transient = '' )
		{
		  return preg_replace( '/[^A-Za-z0-9\_\-]/i', '', str_replace( ':', '_', $transient ) );
		}

	}

	/**
	 * Get the only instance of this class
	 *
	 * @since 4.4.3
	 * @return Avia_Theme_Updater
	 */
	function AviaThemeUpdater( array $args = array() )
	{
		return Avia_Theme_Updater::instance( $args );
	}
}

if( ! class_exists( 'Avia_Envato_Exception' ) )
{
	/**
	 * Simple base class to allow use of try / catch blocks
	 *
	 * @since 4.4.3
	 */
	class Avia_Envato_Exception extends Exception
	{

		/**
		 *
		 * @since 4.4.3
		 * @param string $message
		 * @param int $code
		 * @param \Throwable $previous
		 */
		public function __construct( $message = "", $code = 0, $previous = null )
		{
			parent::__construct( $message, $code, $previous );
		}

	}
}


