<?php
/**
 * @version    $Id$
 * @package    IT_Theme_Framework
 * @author     InnoThemes Team <support@innothemes.com>
 * @copyright  Copyright (C) 2012 InnoThemes.com. All Rights Reserved.
 * @license    GNU/GPL v2 or later http://www.gnu.org/licenses/gpl-2.0.html
 *
 * Websites: http://www.innothemes.com
 */

class IT_Gadget_Base {
	/**
	 * An array to hold instantiated gadget object.
	 *
	 * @var  array
	 */
	private static $_instance = array();

	/**
	 * Gadget file name without extension.
	 *
	 * @var  string
	 */
	protected $gadget = 'base';

	/**
	 * Hook into WordPress system.
	 *
	 * @return  void
	 */
	public static function hook() {
		// Check if any gadget is requested
		if ( isset( $_REQUEST['it-gadget'] ) ) {
			// Prepare gadget action
			$action = isset( $_REQUEST['action'] ) ? $_REQUEST['action'] : null;

			// Execute gadget action
			self::execute( $_REQUEST['it-gadget'], $action );
		}
	}

	/**
	 * Execute an action of specified gadget.
	 *
	 * @param   string   $gadget  Gadget to search for action.
	 * @param   string   $action  Action to be executed.
	 *
	 * @return  string
	 */
	public static function execute( $gadget, $action = 'default' ) {
		// Prepare gadget action
		if ( empty( $action ) ) {
			$action = 'default';
		}

		// Instatiate gadget
		if ( $instance = self::get_instance( $gadget ) ) {
			// Check if gadget action exists
			$method = str_replace( '-', '_', $action ) . '_action';

			if ( method_exists( $instance, $method ) ) {
				try {
					// Execute gadget action
					$response = call_user_func( array( $instance, $method ) );

					if ( $response ) {
						// Set response for lazy gadget
						$instance->set_response( 'success', $response );
					}
				}
				catch ( Exception $e ) {
					// Set response for lazy gadget
					$instance->set_response( 'failure', $e->getMessage() );
				}
			}

			return $instance->render( $action );
		}

		return;
	}

	/**
	 * Get an instance of specified gadget class.
	 *
	 * @param   string  $gadget  Gadget to instantiate.
	 *
	 * @return  mixed  An object instance on success, or boolean FALSE on failure.
	 */
	protected static function get_instance( $gadget ) {
		// Instantiate gadget class only if not already instantiated
		if ( ! isset( self::$_instance[ $gadget ] ) ) {
			// Preset variable
			self::$_instance[$gadget] = false;

			// Check if gadget class exists
			$class = explode( '-', $gadget );
			$class = array_map( 'ucfirst', $class );
			$class = 'IT_Gadget_' . implode( '_', $class );

			// Try to autoload gadget class
			if ( class_exists( $class, true ) ) {
				self::$_instance[$gadget] = new $class();
			}
		}

		return self::$_instance[$gadget];
	}

	/**
	 * Store response.
	 *
	 * @param   string  $status  Status of gadget action execution.
	 * @param   mixed   $data    Data generated by gadget action.
	 *
	 * @return  void
	 */
	protected function set_response( $status, $data ) {
		$this->response = array(
			'status' => $status,
			'data'   => $data,
		);
	}

	/**
	 * Get response.
	 *
	 * @param   string  $status  Default status.
	 * @param   mixed   $data    Default data.
	 *
	 * @return  mixed
	 */
	protected function get_response( $status = 'success', $data = '' ) {
		if ( ! isset( $this->response ) ) {
			$this->set_response( $status, $data );
		}

		return $this->response;
	}

	/**
	 * Render the output.
	 *
	 * @param   string  $action  Gadget action to execute.
	 *
	 * @return  void
	 */
	protected function render( $action = 'default' ) {
		// Clean all buffered output
		while ( ob_get_level() ) {
			ob_end_clean();
		}

		// Prepare gadget action
		if ( empty( $action ) ) {
			$action = 'default';
		}

		// Get response
		$response = $this->get_response();

		// Tell browser that JSON string is returned
		@header( 'Content-Type: application/json' );

		// Check if template file exists for requested gadget action
		$file = IT_Loader::get_path( "gadget/tmpl/{$this->gadget}/{$action}.php" );

		if ( 'success' == $response['status'] && ! empty( $file ) ) {
			// Start output buffering
			ob_start();

			// Extract response array to variables: $status and $data
			extract( $response );

			// Load template file to render output
			include_once $file;

			// Get final response
			$response['data'] = ob_get_clean();

			if ( empty( $response['data'] ) && $response != $this->get_response() ) {
				$response = $this->get_response();
			}
		}

		// Print the JSON encoded response then xxit immediately to prevent WordPress from processing further
		exit( json_encode( $response ) );
	}

	/**
	 * Fetch a remote URI then return results.
	 *
	 * @param   string   $uri     Remote URI for fetching content.
	 * @param   string   $target  Local file path to store fetched content.
	 *
	 * @return  string
	 */
	protected function download( $uri, $target = '' ) {
		global $wp_filesystem;

		// Init WordPress Filesystem Abstraction
		if ( ! function_exists( 'WP_Filesystem' ) ) {
			include_once ABSPATH . 'wp-admin/includes/file.php';

			WP_Filesystem();
		}

		// Use WordPress API to download content from the given URI
		$result = download_url( $uri );

		if ( is_wp_error( $result ) ) {
			throw new Exception( $result->get_error_message() );
		}

		if ( ! empty( $target ) ) {
			// Create a local file by copying temporary file
			if ( ! $wp_filesystem->copy( $result, $target, true, FS_CHMOD_FILE ) ) {
				// If copy failed, chmod file to 0644 and try again
				$wp_filesystem->chmod( $target, 0644 );

				if ( ! $wp_filesystem->copy( $result, $target, true, FS_CHMOD_FILE ) ) {
					throw new Exception( sprintf( __( 'Unable to save downloaded sample data package to %s', IT_THEME_TEXTDOMAIN ), $target ) );
				}
			}

			$content = $wp_filesystem->size( $target );
		} else {
			$content = $wp_filesystem->get_contents( $result );
		}

		// Remove temporary file
		$wp_filesystem->delete( $result );

		return $content;
	}
}
