<?php
/**
* Copyright (c) 2003 Brian E. Lozier (brian@massassi.net)
*
* set_vars() method contributed by Ricardo Garcia (Thanks!)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/

class Template {
   var $vars; /// Holds all the template variables
   var $path; /// Path to the templates

   /**
    * Constructor
    *
    * @param string $path the path to the templates
    *
    * @return void
    */
   function Template($path = null) {
       $this->path = $path;
       $this->vars = array();
   }

   /**
    * Set the path to the template files.
    *
    * @param string $path path to template files
    *
    * @return void
    */
   function set_path($path) {
       $this->path = $path;
   }

   /**
    * Set a template variable.
    *
    * @param string $name name of the variable to set
    * @param mixed $value the value of the variable
    *
    * @return void
    */
   function set($name, $value) {
       $this->vars[$name] = $value;
   }

   /**
    * Set a bunch of variables at once using an associative array.
    *
    * @param array $vars array of vars to set
    * @param bool $clear whether to completely overwrite the existing vars
    *
    * @return void
    */
   function set_vars($vars, $clear = false) {
       if($clear) {
           $this->vars = $vars;
       }
       else {
           if(is_array($vars)) $this->vars = array_merge($this->vars, $vars);
       }
   }

   /**
    * Open, parse, and return the template file.
    *
    * @param string string the template file name
    *
    * @return string
    */
   function fetch($file) {
       extract($this->vars);          // Extract the vars to local namespace
       ob_start();                    // Start output buffering
       include($this->path . $file);  // Include the file
       $contents = ob_get_contents(); // Get the contents of the buffer
       ob_end_clean();                // End buffering and discard
       return $contents;              // Return the contents
   }
}

/**
* An extension to Template that provides automatic caching of
* template contents.
*/
class CachedTemplate extends Template {
   var $cache_id;
   var $expire;
   var $cached;

   /**
    * Constructor.
    *
    * @param string $path path to template files
    * @param string $cache_id unique cache identifier
    * @param int $expire number of seconds the cache will live
    *
    * @return void
    */
   function CachedTemplate($path, $cache_id = null, $expire = 900) {
       $this->Template($path);
       $this->cache_id = $cache_id ? 'cache/' . md5($cache_id) : $cache_id;
       $this->expire   = $expire;
   }

   /**
    * Test to see whether the currently loaded cache_id has a valid
    * corrosponding cache file.
    *
    * @return bool
    */
   function is_cached() {
       if($this->cached) return true;

       // Passed a cache_id?
       if(!$this->cache_id) return false;

       // Cache file exists?
       if(!file_exists($this->cache_id)) return false;

       // Can get the time of the file?
       if(!($mtime = filemtime($this->cache_id))) return false;

       // Cache expired?
       if(($mtime + $this->expire) < time()) {
           @unlink($this->cache_id);
           return false;
       }
       else {
           /**
            * Cache the results of this is_cached() call.  Why?  So
            * we don't have to double the overhead for each template.
            * If we didn't cache, it would be hitting the file system
            * twice as much (file_exists() & filemtime() [twice each]).
            */
           $this->cached = true;
           return true;
       }
   }

   /**
    * This function returns a cached copy of a template (if it exists),
    * otherwise, it parses it as normal and caches the content.
    *
    * @param $file string the template file
    *
    * @return string
    */
   function fetch_cache($file) {
       if($this->is_cached()) {
           $fp = @fopen($this->cache_id, 'r');
           $contents = fread($fp, filesize($this->cache_id));
           fclose($fp);
           return $contents;
       }
       else {
           $contents = $this->fetch($file);

           // Write the cache
           if($fp = @fopen($this->cache_id, 'w')) {
               fwrite($fp, $contents);
               fclose($fp);
           }
           else {
               die('Unable to write cache.');
           }

           return $contents;
       }
   }
}
?>