<?php
/**
 *
 * Template class
 *
 * @static
 * @version 1.0
 * @package JoomlaTune.Framework
 * @author Sergey M. Litvinov (smart@joomlatune.ru)
 * @copyright (C) 2006-2009 by Sergey M. Litvinov (http://www.joomlatune.ru)
 * @license GNU/GPL: http://www.gnu.org/copyleft/gpl.html
 *
 **/

// define directory separator short constant
if (!defined( 'DS' )) {
	define( 'DS', DIRECTORY_SEPARATOR );
}

/**
 * JoomlaTune base template class
 *
 * @abstract
 *
 */
class JoomlaTuneTemplate {

	/**
	* A hack to support __construct() on PHP 4
	* Hint: descendant classes have no PHP4 class_name() constructors,
	* so this constructor gets called first and calls the top-layer __construct()
	* which (if present) should call parent::__construct()
	*
	* @return Object
	*/
	function JoomlaTuneTemplate()
	{
		$args = func_get_args();
		call_user_func_array(array(&$this, '__construct'), $args);
	}

	/**
	* Class constructor
	*
	* @access protected
	*/
	function __construct()
	{
		$this->_vars = array();
	}

	/**
	* Render template into string
	*
	* @abstract Implement in child classes
	* @access	public
	* @return	string
	*/
	function render()
	{
	}

	/**
	* Sets global variables
	*
	* @access	public
	* @param	array	$value	array list of global variables
	* @return	void
	*/
	function setGlobalVars( &$value )
	{
		$this->_globals =& $value;
	}

	/**
	* Fetches and returns a given variable.
	*
	* @access	private
	* @param	string	$name		Variable name
	* @param	string	$default	Default value if the variable does not exist
	* @return	mixed	Requested variable
	*/
	function getVar( $name, $default = null )
	{
		if (isset($this->_vars[$name])) {
			// fetch variable from local variables list
			return $this->_vars[$name];
		} else if (isset($this->_globals[$name])) {
			// fetch variable from global variables list
			return $this->_globals[$name];
		} else {
			// return default value
			return $default;
		}
	}

	/**
	* Set a template variable, creating it if it doesn't exist
	*
	* @access	public
	* @param	string  $name    The name of the variable
	* @param	mixed   $value  The value of the variable
	* @return	void
 	*/
	function setVar( $name, $value )
	{
		$this->_vars[$name] = $value;
	}
}

/**
 *
 * JoomlaTune template renderer class
 *
 */
class JoomlaTuneTemplateRender {

	var $_root = null;
	var $_uri = null;
	var $_globals = null;
	var $_templates = null;

	/**
	* A hack to support __construct() on PHP 4
	* Hint: descendant classes have no PHP4 class_name() constructors,
	* so this constructor gets called first and calls the top-layer __construct()
	* which (if present) should call parent::__construct()
	*
	* @return Object
	*/
	function JoomlaTuneTemplateRender()
	{
		$args = func_get_args();
		call_user_func_array(array(&$this, '__construct'), $args);
	}

	/**
	* Class constructor
	*
	* @access protected
	*/
	function __construct()
	{
		$this->_globals		= array();
		$this->_templates	= array();

		//set root template directory
		$this->setRoot(dirname(__FILE__). DS. 'tpl' );
	}

	/**
	* Returns a reference to the global JoomlaTuneTemplateRender object, only creating it
	* if it doesn't already exist.
	*
	* This method must be invoked as:
	* 		<pre>  $tmpl = &JoomlaTuneTemplateRender::getInstance();</pre>
	*
	* @static
	* @access	public
	* @return	JoomlaTuneTemplate A template object
	*/
	function &getInstance()
	{
		static $instance = null;

		if (!is_object( $instance )) {
			$instance = new JoomlaTuneTemplateRender();
		}
		return $instance;
	}

	/**
	* Sets root base for the template
	*
	* The parameter depends on the reader you are using.
	*
	* @access	public
	* @param	string	root base of the templates
	* @return	void
	*/
	function setRoot( $root )
	{
		$this->_root = $root ? $root : dirname(__FILE__).DS.'tpl';
	}

	/**
	* Gets name of root base for the templates
	*
	* @access	public
	* @return	string
	*/
	function getRoot()
	{
		return $this->_root;
	}


	/**
	* Sets base url for the template images and css
	*
	* The parameter depends on the reader you are using.
	*
	* @access	public
	* @param	string	base url of the templates
	* @return	void
	*/
	function setBaseURI( $uri )
	{
		$this->_uri = $uri;
	}

	/**
	* Gets name of root base for the templates
	*
	* @access	public
	* @return	string
	*/
	function getBaseURI()
	{
		return $this->_uri;
	}

	/**
	* Load template class
	*
	* @access	public
	* @param	string	$template	name of the template
	* @return	boolean
	*/
	function load( $template ) {

		$templateFileName = $this->getRoot().DS.$template.'.php';

		if (is_file($templateFileName)) {
			ob_start();
			include_once( $templateFileName );
			ob_end_clean();

			$templateClass = 'jtt_' . $template;

			if (!class_exists($templateClass)) {
				$this->riseError( 'Template class not found in: ' . $template );
				return false;
			}

			ob_start();
			$tmpl =& new $templateClass;

			$isValidTemplate = false;
			if ((version_compare( phpversion(), '4.2.0' ) < 0)) {
				// PHP < 4.2.0 (function is_a not exists)
				$isValidTemplate = is_subclass_of($tmpl, 'JoomlaTuneTemplate');
			} else {
				// PHP > 4.2.0 (using is_a)
				$isValidTemplate = is_a( $tmpl, 'JoomlaTuneTemplate' );
			}
			ob_end_clean();

			if (!$isValidTemplate) {
			       unset( $tmpl );
			       $this->riseError( 'Incorrect template: ' . $template );
			       return false;
			}

			ob_start();
			$tmpl->setGlobalVars( $this->_globals );
			$this->_templates[$template] =& $tmpl;
			ob_end_clean();

			return true;
		}
		return false;
	}

	/**
	* Adds a global variable
	*
	* Global variables are valid in all templates of this object.
	*
	* @access	public
	* @param	string	$name	name of the global variable
	* @param	string	$value	value of the variable
	* @return	void
	* @see		addVar()
	*/
	function addGlobalVar( $name, $value )
	{
		$this->_globals[strtolower( $name )] = ( string )$value;
	}

	/**
	* Add a variable to a template
	*
	* @access	public
	* @param	string	$template	name of the template
	* @param	string	$name		name of the variable
	* @param	mixed	$value		value of the variable
	* @return	void
	* @see		addGlobalVar()
	*/
	function addVar( $template, $name, $value )
	{
		$this->_templates[$template]->_vars[$name] = $value;
	}

	/**
	* Add a object variable to a template
	*
	* @access	public
	* @param	string	$template	name of the template
	* @param	string	$name		name of the variable
	* @param	mixed	$value		value of the variable
	* @return	void
	* @see		addVar(), addGlobalVar()
	*/
	function addObject( $template, $name, $value )
	{
		$this->_templates[$template]->_vars[$name] = $value;
	}

	/**
	* Fetches and returns a given variable from template.
	*
	* @access	public
	* @param	string	$template	name of the template
	* @param	string	$name		name of the variable
	* @return	mixed
	*/
	function getVar( $template, $name )
	{
		if (!$this->exists($template))
		{
			$this->riseError( 'Unknown template: ' . $template );
			return null;
		}

		ob_start();
		$result = $this->_templates[$template]->getVar($name);
		ob_end_clean();

		return $result;
	}

	/**
	* Renders template and return result as string
	*
	* @access	public
	* @param	string	$template	name of the template
	* @return 	string
	* @see		displayTemplate()
	*/
	function renderTemplate( $template )
	{
		if (!$this->exists($template)) {
			$this->riseError( 'Unknown template: ' . $template );
			return null;
		}

		ob_start();
		$this->_templates[$template]->render();
		$result = ob_get_contents();
		ob_end_clean();

		return $result;
	}

	/**
	* Renders template and displays output
	*
	* @access	public
	* @param	string	$template	name of the template
	* @return 	void
	* @see		renderTemplate()
	*/
	function displayTemplate( $template )
	{
		echo $this->renderTemplate($template);
	}

	/**
	* Frees a template
	*
	* All memory consumed by the template will be freed.
	*
	* @access	public
	* @param	string	$template	name of the template
	* @return	void
	* @see		freeAllTemplates()
	*/
	function freeTemplate( $template )
	{
		unset($this->_templates[$template]);
	}

	/**
	* Frees all templates
	*
	* All memory consumed by the templates will be freed.
	*
	* @access	public
	* @return	void
	* @see		freeTemplate()
	*/
	function freeAllTemplates()
	{
		$this->_templates = array();
		$this->_globals	= array();
		$this->_vars = array();
	}

	/**
	* Checks wether a template exists
	*
	* @access	public
	* @param	string	$name	name of the template
	* @return	boolean		true, if the template exists (loaded), false otherwise
	* @see		load()
	*/
	function exists( $name )
	{
		return isset($this->_templates[$name]);
	}

	/**
	* Displays error-message and die
	*
	* @access	private
	* @param	string	$message error message
	* @param	string	$type type of error (die or warning)
	* @return	void
	*/
	function riseError( $message, $type = 'die' )
	{
		switch($type)
		{
			case 'warning':
				echo( 'JoomlaTuneTemplateWarning: ' . $message );
				break;
			case 'die':
			default:
				die( 'JoomlaTuneTemplateError: ' . $message );
				break;
		}
	}
}
?>