<?php 
/**
 * Envato Protected API
 *
 * Wrapper class for the Envato marketplace protected API methods specific
 * to the Envato WordPress Toolkit plugin.
 *
 * @package     WordPress
 * @subpackage  Envato WordPress Toolkit
 * @author      Derek Herman <derek@envato.com>
 * @since       1.0
 */ 
class Envato_Protected_API {
  /**
   * The buyer's Username
   *
   * @var       string
   *
   * @access    public
   * @since     1.0
   */
  public $user_name;
  
  /**
   * The buyer's API Key
   *
   * @var       string
   *
   * @access    public
   * @since     1.0
   */
  public $api_key;
  
  /**
   * The default API URL
   *
   * @var       string
   *
   * @access    private
   * @since     1.0
   */
  protected $public_url = 'http://marketplace.envato.com/api/edge/set.json';
  
  /**
   * Error messages
   *
   * @var       array
   *
   * @access    public
   * @since     1.0
   */
  public $errors = array( 'errors' => '' );
  
  /**
   * Class contructor method
   *
   * @param     string      The buyer's Username
   * @param     string      The buyer's API Key can be accessed on the marketplaces via My Account -> My Settings -> API Key
   * @return    void        Sets error messages if any.
   *
   * @access    public
   * @since     1.0
   */
  public function __construct( $user_name = '', $api_key = '' ) {
  
    if ( $user_name == '' ) {
      $this->set_error( 'user_name', esc_html__( 'Please enter your Envato Marketplace Username.', 'consulting' ) );
    }
      
    if ( $api_key == '' ) {
      $this->set_error( 'api_key', esc_html__( 'Please enter your Envato Marketplace API Key.', 'consulting' ) );
    }
      
    $this->user_name  = $user_name;
    $this->api_key    = $api_key;
    
  }
  
  /**
   * Get private user data.
   *
   * @param     string      Available sets: 'vitals', 'earnings-and-sales-by-month', 'statement', 'recent-sales', 'account', 'verify-purchase', 'download-purchase', 'wp-list-themes', 'wp-download'
   * @param     string      The buyer/author username to test against.
   * @param     string      Additional set data such as purchase code or item id.
   * @param     bool        Allow API calls to be cached. Default false.
   * @param     int         Set transient timeout. Default 300 seconds (5 minutes).
   * @return    array       An array of values (possibly cached) from the requested set, or an error message.
   *
   * @access    public
   * @since     1.0
   * @updated   1.3
   */ 
  public function private_user_data( $set = '', $user_name = '', $set_data = '', $allow_cache = false, $timeout = 300 ) { 
    
    if ( $set == '' ) {
      $this->set_error( 'set', esc_html__( 'The API "set" is a required parameter.', 'consulting' ) );
    }
      
    if ( $user_name == '' ) {
      $user_name = $this->user_name;
    }
      
    if ( $set_data !== '' ) {
      $set_data = ":$set_data";
    }
      
    $url = "http://marketplace.envato.com/api/edge/$user_name/$this->api_key/$set$set_data.json";
    
    /* set transient ID for later */
    $transient = $user_name . '_' . $set . $set_data;
    
    if ( $allow_cache ) {
      $cache_results = $this->set_cache( $transient, $url, $timeout );
      $results = $cache_results;
    } else {
      $results = $this->remote_request( $url );
    }
    
    if ( isset( $results->error ) ) {
      $this->set_error( 'error_' . $set, $results->error );
    }
    
    if ( $errors = $this->api_errors() ) {
      $this->clear_cache( $transient );
      return $errors;
    }
    
    if ( isset( $results->$set ) ) {
      return $results->$set;
    }
    
    return false;
    
  }
  
  /**
   * Used to list purchased themes.
   *
   * @param     bool        Allow API calls to be cached. Default true.
   * @param     int         Set transient timeout. Default 300 seconds (5 minutes).
   * @return    object      If user has purchased themes, returns an object containing those details.
   *
   * @access    public
   * @since     1.0
   * @updated   1.3
   */
  public function wp_list_themes( $allow_cache = true, $timeout = 300 ) {
  
    return $this->private_user_data( 'wp-list-themes', $this->user_name, '', $allow_cache, $timeout );
    
  }
  
  /**
   * Used to download a purchased item.
   *
   * This method does not allow caching.
   *
   * @param     string      The purchased items id
   * @return    string|bool If item purchased, returns the download URL.
   *
   * @access    public
   * @since     1.0
   */ 
  public function wp_download( $item_id ) {
    
    if ( ! isset( $item_id ) ) {
      $this->set_error( 'item_id', esc_html__( 'The Envato Marketplace "item ID" is a required parameter.', 'consulting' ) );
    }
      
    $download = $this->private_user_data( 'wp-download', $this->user_name, $item_id );
    
    if ( $errors = $this->api_errors() ) {
      return $errors;
    } else if ( isset( $download->url ) ) {
      return $download->url;
    }
    
    return false;
  }
  
  /**
   * Retrieve the details for a specific marketplace item.
   *
   * @param     string      $item_id The id of the item you need information for. 
   * @return    object      Details for the given item.
   *
   * @access    public
   * @since     1.0
   * @updated   1.3
   */
  public function item_details( $item_id, $allow_cache = true, $timeout = 300 ) {
    
    $url = preg_replace( '/set/i', 'item:' . $item_id, $this->public_url );
    
    /* set transient ID for later */
    $transient = 'item_' . $item_id;
      
    if ( $allow_cache ) {
      $cache_results = $this->set_cache( $transient, $url, $timeout );
      $results = $cache_results;
    } else {
      $results = $this->remote_request( $url );
    }
    
    if ( isset( $results->error ) ) {
      $this->set_error( 'error_item_' . $item_id, $results->error );
    }
    
    if ( $errors = $this->api_errors() ) {
      $this->clear_cache( $transient );
      return $errors;
    }
      
    if ( isset( $results->item ) ) {
      return $results->item;
    }
    
    return false;
    
  }
  
  /**
   * Set cache with the Transients API.
   *
   * @link      http://codex.wordpress.org/Transients_API
   *
   * @param     string      Transient ID.
   * @param     string      The URL of the API request.
   * @param     int         Set transient timeout. Default 300 seconds (5 minutes).
   * @return    mixed
   *
   * @access    public
   * @since     1.3
   */ 
  public function set_cache( $transient = '', $url = '', $timeout = 300 ) {
  
    if ( $transient == '' || $url == '' ) {
      return false;
    }
    
    /* keep the code below cleaner */
    $transient = $this->validate_transient( $transient );
    $transient_timeout = '_transient_timeout_' . $transient;
    
    /* set original cache before we destroy it */
    $old_cache = get_option( $transient_timeout ) < time() ? get_option( $transient ) : '';
    
    /* look for a cached result and return if exists */
    if ( false !== $results = get_transient( $transient ) ) {
      return $results;
    }
    
    /* create the cache and allow filtering before it's saved */
    if ( $results = apply_filters( 'envato_api_set_cache', $this->remote_request( $url ), $transient ) ) {
      set_transient( $transient, $results, $timeout );
      return $results;
    }
    
    return false;
    
  }
  
  /**
   * Clear cache with the Transients API.
   *
   * @link      http://codex.wordpress.org/Transients_API
   *
   * @param     string      Transient ID.
   * @return    void
   *
   * @access    public
   * @since     1.3
   */ 
  public function clear_cache( $transient = '' ) {
  
    delete_transient( $transient );
    
  }
  
  /**
   * Helper function to validate transient ID's.
   *
   * @param     string      The transient ID.
   * @return    string      Returns a DB safe transient ID.
   *
   * @access    public
   * @since     1.3
   */
  public function validate_transient( $id = '' ) {

    return preg_replace( '/[^A-Za-z0-9\_\-]/i', '', str_replace( ':', '_', $id ) );
    
  }
  
  /**
   * Helper function to set error messages.
   *
   * @param     string      The error array id.
   * @param     string      The error message.
   * @return    void
   *
   * @access    public
   * @since     1.0
   */
  public function set_error( $id, $error ) {
  
    $this->errors['errors'][$id] = $error;
    
  }
  
  /**
   * Helper function to return the set errors.
   *
   * @return    array       The errors array.
   *
   * @access    public
   * @since     1.0
   */
  public function api_errors() {
  
    if ( ! empty( $this->errors['errors'] ) ) {
      return $this->errors['errors'];
    }
    
  }
  
  /**
   * Helper function to query the marketplace API via wp_remote_request.
   *
   * @param     string      The url to access.
   * @return    object      The results of the wp_remote_request request.
   *
   * @access    private
   * @since     1.0
   */
  protected function remote_request( $url ) {
  
    if ( empty( $url ) ) {
      return false;
    }

    $request = wp_remote_request( $url );

    if ( is_wp_error( $request ) ) {
    	echo $request->get_error_message();
    	return false;
    }

    $data = json_decode( $request['body'] );
    
    if ( $request['response']['code'] == 200 ) {
      return $data;
    } else {
      $this->set_error( 'http_code', $request['response']['code'] );
    }
      
    if ( isset( $data->error ) ) {
      $this->set_error( 'api_error', $data->error ); 
    }
    
    return false;
  }
  
  /**
   * Helper function to print arrays to the screen ofr testing.
   *
   * @param     array       The array to print out
   * @return    string
   *
   * @access    public
   * @since     1.0
   */
  public function pretty_print( $array ) {
  
    echo '<pre>';
    print_r( $array );
    echo '</pre>';
    
  }
}

/* End of file class-envato-api.php */
/* Location: ./includes/class-envato-api.php */