<?php
/**
 * Project: 
 * Contenido Content Management System
 * 
 * Description: 
 * Contenido Template Engine
 * 
 * Requirements: 
 * @con_php_req 5.0
 * 
 *
 * @package    Contenido Backend classes
 * @version    1.2.2
 * @author     Jan Lengowski
 * @copyright  four for business AG <www.4fb.de>
 * @license    http://www.contenido.org/license/LIZENZ.txt
 * @link       http://www.4fb.de
 * @link       http://www.contenido.org
 * @since      file available since contenido release <= 4.6
 * 
 * {@internal 
 *   created unknown
 *   modified 2008-06-30, Frederic Schneider, add security fix
 *   modified 2008-09-03  Timo Trautmann, DB Object is only created if necessary
 *
 *   $Id: class.template.php 790 2008-09-04 16:34:28Z timo.trautmann $: 
 * }}
 * 
 */

if(!defined('CON_FRAMEWORK')) {
	die('Illegal call');
}

/**
 * class Template
 *
 * Light template mechanism
 *
 * @author Jan Lengowski <Jan.Lengowski@4fb.de>
 * @copyright four for business <http://www.4fb.de>
 * @author Stefan Jelner (Optimizations)
 * @version 1.0
 */
class Template
{

	/**
	 * Needles (static)
	 * @var array
	 */
	var $needles = array ();

	/**
	 * Replacements (static)
	 * @var array
	 */
	var $replacements = array ();

	/**
	 * Dyn_Needles (dynamic)
	 * @var array
	 */
	var $Dyn_needles = array ();

	/**
	 * Dyn_Replacements (dynamic)
	 * @var array
	 */
	var $Dyn_replacements = array ();

	/**
	 * Database instance
	 * @var object
	 */
	var $db;

	/**
	 * Template cache
	 * @var array
	 */
	var $tplcache;

	/**
	 * Template name cache
	 * @var array
	 */
	var $tplnamecache;
	
	/**
	 * Dynamic counter
	 * @var int
	 */
	var $dyn_cnt = 0;

	/**
	 * Tags array (for dynamic blocks);
	 * @var array
	 */
	var $tags = array ('static' => '{%s}', 'start' => '<!-- BEGIN:BLOCK -->', 'end' => '<!-- END:BLOCK -->');

	/**
	 * Constructor function
	 * @return void
	 */
	function Template($tags = false)
	{
		$this->tplcache = Array ();
		$this->tplnamecache = Array ();

		if (is_array($tags))
		{
			$this->tags = $tags;
		}
		
		$this->setEncoding("");
        $this->setDomain("contenido");		
	} // end function

    /**
     * setDomain
     *
     * Sets the gettext domain to use for translations in a template
     *
	 * @param $sDomain	string	Sets the domain to use for template translations
     * @return none
     */    
    function setDomain ($sDomain)
    {
    	$this->_sDomain = $sDomain;
    }
    
	/**
	 * Set Templates placeholders and values
	 *
	 * With this method you can replace the placeholders
	 * in the static templates with dynamic data.
	 *
	 * @param $which String 's' for Static or else dynamic
	 * @param $needle String Placeholder
	 * @param $replacement String Replacement String
	 *
	 * @return void
	 */
	function set($which = 's', $needle, $replacement)
	{
		if ($which == 's')
		{ // static
			$this->needles[] = sprintf($this->tags['static'], $needle);
			$this->replacements[] = $replacement;

		} else
		{ // dynamic
			$this->Dyn_needles[$this->dyn_cnt][] = sprintf($this->tags['static'], $needle);
			$this->Dyn_replacements[$this->dyn_cnt][] = $replacement;

		}
	}

    /**
     * Sets an encoding for the template's head block.
     *
     * @param $encoding string Encoding to set
     */    
    function setEncoding ($encoding)
    {
    	$this->_encoding = $encoding;
    }
 	
	/**
	 * Iterate internal counter by one
	 *
	 * @return void
	 */
	function next()
	{
		$this->dyn_cnt++;
	}

	/**
	 * Reset template data
	 *
	 * @return void
	 */
	function reset()
	{
		$this->dyn_cnt = 0;
		$this->needles = array ();
		$this->replacements = array ();
		$this->Dyn_needles = array ();
		$this->Dyn_replacements = array ();
	}

	/**
	 * Generate the template and
	 * print/return it. (do translations sequentially to save memory!!!)
	 *
	 * @param $template string/file Template
	 * @param $return bool Return or print template
	 * @param $note bool Echo "Generated by ... " Comment
	 *
	 * @return string complete Template string
	 */
	function generate($template, $return = 0, $note = 0)
	{
		global $cfg;

		//check if the template is a file or a string
		if (!@ is_file($template))
		{
			$content = & $template; //template is a string (it is a reference to save memory!!!)
		}
		else
		{
			$content = implode("", file($template)); //template is a file
		}

		$content = (($note) ? "<!-- Generated by Contenido ".$cfg['version']."-->\n" : "").$content;

		$pieces = array();
		
		//replace i18n strings before replacing other placeholders 
		$this->replacei18n($content, "i18n"); 
		$this->replacei18n($content, "trans"); 

		//if content has dynamic blocks 
		if (preg_match("/^.*".preg_quote($this->tags['start'], "/").".*?".preg_quote($this->tags['end'], "/").".*$/s", $content)) { 
			//split everything into an array 
			preg_match_all("/^(.*)".preg_quote($this->tags['start'], "/")."(.*?)".preg_quote($this->tags['end'], "/")."(.*)$/s", $content, $pieces); 
			//safe memory 
			array_shift($pieces); 
			$content = ""; 
			//now combine pieces together 

			//start block 
			$content .= str_replace($this->needles, $this->replacements, $pieces[0][0]); 
			unset ($pieces[0][0]); 

			//generate dynamic blocks 
			for ($a = 0; $a < $this->dyn_cnt; $a ++) { 
				$content .= str_replace($this->Dyn_needles[$a], $this->Dyn_replacements[$a], $pieces[1][0]); 
			} 
			unset ($pieces[1][0]); 

			//end block 
			$content .= str_replace($this->needles, $this->replacements, $pieces[2][0]); 
			unset ($pieces[2][0]);
		} else { 
			$content = str_replace($this->needles, $this->replacements, $content); 
		}
		
		if ($this->_encoding != "")
		{
			$content = str_replace("</head>", '<meta http-equiv="Content-Type" content="text/html; charset='.$this->_encoding.'">'."\n".'</head>', $content);
		}
		  
		if ($return)
			return $content;
		else
			echo $content;
	} # end function

	/** 
    * replacei18n() 
    * 
    * Replaces a named function with the translated variant 
    * 
    * @param $template string Contents of the template to translate (it is reference to save memory!!!) 
    * @param $functionName string Name of the translation function (e.g. i18n) 
    */ 
	function replacei18n(& $template, $functionName) { 

		// Be sure that php code stays unchanged 
		$php_matches = array();
		if (preg_match_all('/<\?(php)?((.)|(\s))*?\?>/i', $template, $php_matches)) { 
			$x = 0; 
			foreach ($php_matches[0] as $php_match) { 
				$x++; 
				$template = str_replace ($php_match , "{PHP#".$x."#PHP}", $template); 
				$container[$x] = $php_match; 
			}
		}

		// If template contains functionName + parameter store all matches 
		$matches = array();
		preg_match_all("/".preg_quote($functionName, "/")."\\(([\\\"\\'])(.*?)\\1\\)/s", $template, $matches); 

		$matches = array_values(array_unique($matches[2])); 
		for ($a = 0; $a < count($matches); $a ++) { 
			$template = preg_replace("/".preg_quote($functionName, "/")."\\([\\\"\\']".preg_quote($matches[$a], "/")."[\\\"\\']\\)/s", i18n($matches[$a]), $template); 
		} 

		// Change back php placeholder 
		if (is_array($container)) { 
			foreach ($container as $x => $php_match) { 
				$template = str_replace ("{PHP#".$x."#PHP}" , $php_match, $template); 
			} 
		}
	}

	/**
	 * getTemplateName()
	 * Returns the name for the given template
	 * @deprecated This function is in the wrong place
	 * @return string  Returns the name of the given template
	 */
	function getTemplateName($tplid)
	{
		global $cfg;
        
        if (!is_object($this->db)) {
            $this->db = new DB_Contenido();
        }

		if (array_key_exists((int) $tplid, $this->tplnamecache))
		{
			return $this->tplnamecache[$tplid];
		}

		$sql = "SELECT
		                    name
		                FROM
		                ".$cfg["tab"]["tpl"]."
		                WHERE
		                    idtpl = '".$tplid."'";

		$this->db->query($sql);
		$this->db->next_record();

		$this->tplnamecache[$tplid] = $this->db->f("name");
		return ($this->db->f("name"));

	} // end function
	
	function getTemplateDescription($tplid)
	{
		global $cfg;
        
        if (!is_object($this->db)) {
            $this->db = new DB_Contenido();
        }

		$sql = "SELECT
		                    idtpl
		                FROM
		                ".$cfg["tab"]["tpl_conf"]."
		                WHERE
		                    idtplcfg = '".Contenido_Security::toInteger($tplid)."'";

		$this->db->query($sql);
		$this->db->next_record();
		$idTpl = $this->db->f("idtpl");
		
		$sql = "SELECT
		                	description
		                FROM
		                ".$cfg["tab"]["tpl"]."
		                WHERE
		                    idtpl = '".Contenido_Security::toInteger($idTpl)."'";
		
		$this->db->query($sql);
		$this->db->next_record();

		return ($this->db->f("description"));
	}

	/**
	 * getTemplateNameFromTPLCFG()
	 * Returns the name for the given template using the template configuration ID
	 * 
	 * @deprecated this function is in the wrong place
	 * @return string  Returns the name of the given template
	 */
	function getTemplateNameFromTPLCFG($tplcfg)
	{
		global $cfg;
        
        if (!is_object($this->db)) {
            $this->db = new DB_Contenido();
        }

		if (array_key_exists($tplcfg, $this->tplcache))
		{
			return $this->tplcache[$tplcfg];
		}

		$sql = "SELECT
		                    idtpl
		                FROM
		                ".$cfg["tab"]["tpl_conf"]."
		                WHERE
		                    idtplcfg = '".Contenido_Security::toInteger($tplcfg)."'";
		$this->db->query($sql);
		$this->db->next_record();

		$this->tplcache[$tplcfg] = $this->getTemplateName($this->db->f("idtpl"));
		return ($this->tplcache[$tplcfg]);

	} // end function

	
} # end class
?>