<?php
/**
 * YANA library
 *
 * @package yana
 * @licence http://creativecommons.org/licenses/by-nc-sa/2.5/
 */

/**
 * SmartTemplate
 *
 * @access      public
 * @package     yana
 * @subpackage  core
 */
class SmartTemplate extends SerializeableObject
{

    /**#@+
     * @ignore
     * @access  private
     */
     
    /** @var string */  var $filename = "";
    /** @var bool */    var $exists   = false;
    /** @var smarty */  var $smarty   = null;

    /**#@-*/

    /**
     * create an instance
     *
     * You may enter a filename of a template you want to use.
     *
     * @param  string  $filename  (optional)
     */ 
    function SmartTemplate($filename = "")
    {
        settype($filename, "string");
        global $YANA;

        /* Config Smarty */
        $this->smarty                  = new Smarty();
        $this->smarty->left_delimiter  = YANA_LEFT_DELIMITER;
        $this->smarty->right_delimiter = YANA_RIGHT_DELIMITER;
        if (isset($YANA)) {
            DisplayUtility::loadSmilies($YANA->getVar("PROFILE.SMILEYDIR"));
            $this->smarty->template_dir    = './';
            $this->smarty->config_dir      = $YANA->getVar('CONFIGDIR');
            $this->smarty->compile_dir     = $YANA->getVar('TEMPDIR');
        } else {
            $this->smarty->template_dir    = './';
            $this->smarty->config_dir      = 'config/';
            $this->smarty->compile_dir     = 'cache/';
        }
        $this->smarty->php_handling        = SMARTY_PHP_REMOVE;
        $this->smarty->security            = true;
        $this->smarty->register_modifier('scanForAt',        array('DisplayUtility', 'scanForAt'));
        $this->smarty->register_modifier('smilies',          array('DisplayUtility', 'smilies'));
        $this->smarty->register_modifier('embeddedTags',     array('DisplayUtility', 'embeddedTags'));
        $this->smarty->register_modifier('replaceToken',     array('Layout',         'replaceToken'));
        $this->smarty->register_modifier('date',             array('DisplayUtility', 'date'));
        $this->smarty->register_modifier('css',              array('DisplayUtility', 'css'));
        $this->smarty->register_modifier('url',              array('DisplayUtility', 'url'));
        $this->smarty->register_modifier('href',             array('DisplayUtility', 'href'));
        $this->smarty->register_modifier('entities',         array('DisplayUtility', 'entities'));
        $this->smarty->register_function('import',           array('DisplayUtility', 'guiImport'));
        $this->smarty->register_function('smilies' ,         array('DisplayUtility', 'guiSmilies'));
        $this->smarty->register_function('create' ,          array('DisplayUtility', 'guiCreate'));
        $this->smarty->default_modifiers = array('replaceToken','scanForAt');
        $this->smarty->cache             = false;
        $this->smarty->assign('REMOTE_ADDR', $_SERVER['REMOTE_ADDR']);
        $this->smarty->register_prefilter(array('DisplayUtility', 'processLanguageInstructions'));
        $this->smarty->register_prefilter(array('DisplayUtility', 'htmlPreProcessor'));
        $this->smarty->register_postfilter(array('DisplayUtility', 'htmlPostProcessor'));
        $this->smarty->register_outputfilter(array('DisplayUtility', 'outputFilter'));
        $this->setFilename($filename);
    }

    /**
     * toString
     *
     * @access public
     * @return string
     *
     * @ignore
     */
    function toString()
    {
        if (!$this->exists()) {
            return "The template file '".$this->filename."' does not exist\n";
        } else {
            return "Template class '".get_class($this)."' using template file '".$this->filename."'.\n";
        }
    }

    /**
     * fetch a template or template var
     *
     * There are three ways to call this function:
     *
     * If you call $smartTemplate->get($varName)
     * it will get the template var $varName
     * and return it.
     *
     * If you call $smartTemplate->get("*")
     * with the wildcard '*' or an empty string ''
     * it will return an associative array
     * containing all template vars.
     *
     * If you call $smartTemplate->get()
     * without a parameter it will fetch
     * the current template and return it
     * as a string.
     *
     * @access  public
     * @param   string  $key  (optional)
     * @return  mixed
     */ 
    function get($key = null)
    {
        global $YANA;

        if (is_null($key)) {
            if (isset($YANA)) {
                $this->smarty->assign($YANA->getVar('*'));
            }
            return $this->smarty->fetch($this->filename);
        } else if (empty($key) || $key === '*') {
            return $this->smarty->get_template_vars();
        } else {
            $resource = $this->smarty->get_template_vars();
            return Hashtable::get($resource, $key);
        }

    }

    /**
     * output the template
     *
     * This function will fetch and print
     * the current template to the screen
     *
     * @access public
     */
    function write()
    {
       echo $this->get();
    }

    /**
     * assign a variable by value
     *
     * This assigns the $var to the name $varName.
     *
     * Unlike Smarty's "assign()" this function takes an
     * additional value for $varName:
     *
     * You may use the wildcard '*' to:
     *
     * <ol>
     *     <li>    $smartTemplate('*', string $var)    assign a string to the global token %INSERT_CONTENT_HERE%    </li>
     *     <li>    $smartTemplate('*', array  $var)    merge an associative array with the template vars    </li>
     * </ol>
     *
     * @access  public
     * @param   string  $varName
     * @param   mixed   $var
     */
    function insert($varName, $var)
    {
        settype($varName, "string");

        if ($varName=='*' && is_string($var)) {
            $this->smarty->assign('INSERT_CONTENT_HERE', $var);
        } else if ($varName=='*') {
            $this->smarty->assign($var);
        } else {
            $this->smarty->assign($varName, $var);
        }

    }

    /**
     * assign a variable by reference
     *
     * This assigns the $var to the name $varName.
     *
     * Unlike Smarty's "assign()" this function takes an
     * additional value for $varName:
     *
     * You may use the wildcard '*' to:
     *
     * <ol>
     *     <li>    $smartTemplate('*', string $var)    assign a string to the global token %INSERT_CONTENT_HERE%    </li>
     *     <li>    $smartTemplate('*', array  $var)    merge an associative array with the template vars    </li>
     * </ol>
     *
     * @access public
     * @param string $varName
     * @param mixed $var
     */
    function insertByReference($varName, &$var)
    {
        settype($varName, "string");

        if ($varName=='*' && is_string($var)) {
            $this->smarty->assign_by_ref('INSERT_CONTENT_HERE', $var);
        } else if ($varName=='*') {
            foreach (array_keys($var) as $key)
            {
                $this->smarty->assign_by_ref($key, $var[$key]);
            }
        } else {
            $this->smarty->assign_by_ref($varName, $var);
        }

    }

    /**
     * insert a file
     *
     * Load a file and assign it's content as a string
     * to the provided template var.
     *
     * You may use the wildcard '*' to assign the file content
     * to the global token %INSERT_CONTENT_HERE%
     *
     * @access  public
     * @param   string  $varName
     * @param   string  $filename
     * @return  boolean
     */ 
    function insertFile($varName, $filename) 
    {
        settype($varName, "string");
        settype($filename, "string");

        if (empty($varName) || $varName == "*") {
            $varName = 'INSERT_CONTENT_HERE';
        }

        if (file_exists($filename) && is_readable($filename)) {
            $t = new smartTemplate($filename);
            $t->insert('FILE_IS_INCLUDE', "true");
            $include = $t->get();
            $this->smarty->assign($varName, $include);
            return true;
        } else {
            return false;
        }

    }

    /**
     * set filename of current template
     *
     * You may set another filename of a template to fetch.
     *
     * Template files may not have a reserved extension like "htaccess", "php", "config" or the like.
     * Files should be adressed from the root, where "index.php" is stored.
     * If you can't access a file, the file does not exist or is not readable, an error is thrown.
     *
     * @access  public
     * @param   string  $filename
     * @return  boolean
     */ 
    function setFilename($filename)
    {
        settype($filename, "string");

        /* Reset file binding */
        $this->smarty->clear_assign('MTIME');
        $this->smarty->clear_assign('ATIME');
        $this->smarty->clear_assign('CTIME');
        $this->exists    = false;
        $this->filename  = "";

        if (empty($filename)) {

            return false;

        } else if (preg_match("/.*\.(register|config|cfg|lock|dat|htaccess|php|inc|conf)/Ui", $filename)) {

            $this->smarty->trigger_error("ERROR 403: Access denied for file '$filename'.");
            return false;

        } elseif (!file_exists($filename) || !is_readable($filename)) {

            $this->smarty->trigger_error("ERROR 404: File '$filename' not found.");
            return false;

        } else {

            $this->filename = $filename;

            /* Append Template Data */
            $this->smarty->assign('MTIME', date("d.m.Y",filemtime($filename)));
            $this->smarty->assign('ATIME', date("d.m.Y H:i:s",fileatime($filename)));
            $this->smarty->assign('CTIME', date("d.m.Y",filectime($filename)));
            $this->smarty->assign_by_ref('FILENAME', $this->filename);
            preg_match("/^.*\//", $filename, $basedir);
            $this->smarty->assign('BASEDIR', $basedir[0]);
            clearstatcache();

            $this->exists = true;
            return true;

        }
    }

    /**
     * get filename of current template
     *
     * @access public
     * @return string
     */ 
    function getFilename()
    {
        assert('is_string($this->filename);');
        return $this->filename;
    }

    /**
     * exists
     *
     * @access public
     * @return boolean
     *
     * @ignore
     */ 
    function exists()
    {
        assert('is_bool($this->exists);');
        return $this->exists;
    }

    /**
     * clearCache
     *
     * @access  public
     * @static
     * @ignore
     */
    function clearCache()
    {
        global $YANA;

        $dir   = $YANA->getVar('TEMPDIR');
        $files = dirlist($dir, '.php|.cache|.tmp');
        for ($i=0; $i<count($files); $i++)
        {
            unlink($dir.$files[$i]);
        }
    }

}
?>