<?php
/**
 * PHPTAL templating engine
 *
 * PHP Version 5
 *
 * @category HTML
 * @package  PHPTAL
 * @author   Laurent Bedubourg <lbedubourg@motion-twin.com>
 * @author   Kornel Lesiński <kornel@aardvarkmedia.co.uk>
 * @author   Iván Montes <drslump@pollinimini.net>
 * @license  http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
 * @version  SVN: $Id: RepeatControllerGroups.php 657 2009-06-30 16:48:20Z kornel $
 * @link     http://phptal.org/
 */

/**
 * Keeps track of variable contents when using grouping in a path (first/ and last/)
 *
 * @package PHPTAL
 * @subpackage Php
 */
class PHPTAL_RepeatControllerGroups
{
    protected $dict = array();
    protected $cache = array();
    protected $data = null;
    protected $vars = array();
    protected $branch;


    public function __construct()
    {
        $this->dict = array();
        $this->reset();
    }

    /**
     * Resets the result caches. Use it to signal an iteration in the loop
     *
     */
    public function reset()
    {
        $this->cache = array();
    }

    /**
     * Checks if the data passed is the first one in a group
     *
     * @param mixed $data   The data to evaluate
     * @return Mixed    True if the first item in the group, false if not and
     *                  this same object if the path is not finished
     */
    public function first($data)
    {
        if ( !is_array($data) && !is_object($data) && !is_null($data) ) {

            if ( !isset($this->cache['F']) ) {

                $hash = md5($data);

                if ( !isset($this->dict['F']) || $this->dict['F'] !== $hash ) {
                    $this->dict['F'] = $hash;
                    $res = true;
                } else {
                    $res = false;
                }

                $this->cache['F'] = $res;
            }

            return $this->cache['F'];
        }

        $this->data = $data;
        $this->branch = 'F';
        $this->vars = array();
        return $this;
    }

    /**
     * Checks if the data passed is the last one in a group
     *
     * @param mixed $data   The data to evaluate
     * @return Mixed    True if the last item in the group, false if not and
     *                  this same object if the path is not finished
     */
    public function last($data)
    {
        if ( !is_array($data) && !is_object($data) && !is_null($data) ) {

            if ( !isset($this->cache['L']) ) {

                $hash = md5($data);

                if (empty($this->dict['L'])) {
                    $this->dict['L'] = $hash;
                    $res = false;
                } elseif ($this->dict['L'] !== $hash) {
                    $this->dict['L'] = $hash;
                    $res = true;
                } else {
                    $res = false;
                }

                $this->cache['L'] = $res;
            }

            return $this->cache['L'];
        }

        $this->data = $data;
        $this->branch = 'L';
        $this->vars = array();
        return $this;
    }

    /**
     * Handles variable accesses for the tal path resolver
     *
     * @param string $var   The variable name to check
     * @return Mixed    An object/array if the path is not over or a boolean
     *
     * @todo    replace the PHPTAL_Context::path() with custom code
     */
    public function __get($var)
    {
        // When the iterator item is empty we just let the tal
        // expression consume by continuously returning this
        // same object which should evaluate to true for 'last'
        if ( is_null($this->data) ) {
            return $this;
        }

        // Find the requested variable
        $value = PHPTAL_Context::path($this->data, $var, true);

        // Check if it's an object or an array
        if ( is_array($value) || is_object($value) ) {
            // Move the context to the requested variable and return
            $this->data = $value;
            $this->addVarName($var);
            return $this;
        }

        // get a hash of the variable contents
        $hash = md5($value);

        // compute a path for the variable to use as dictionary key
        $path = $this->branch . $this->getVarPath() . $var;

        // If we don't know about this var store in the dictionary
        if ( !isset($this->cache[$path]) ) {

            if ( !isset($this->dict[$path]) ) {
                $this->dict[$path] = $hash;
                $res = $this->branch === 'F';
            } else {
                // Check if the value has changed
                if ($this->dict[$path] !== $hash) {
                    $this->dict[$path] = $hash;
                    $res = true;
                } else {
                    $res = false;
                }
            }

            $this->cache[$path] = $res;
        }

        return $this->cache[$path];

    }

    /**
     * Adds a variable name to the current path of variables
     *
     * @param string $varname  The variable name to store as a path part
     * @access protected
     */
    protected function addVarName($varname)
    {
        $this->vars[] = $varname;
    }

    /**
     * Returns the current variable path separated by a slash
     *
     * @return String  The current variable path
     * @access protected
     */
    protected function getVarPath()
    {
        return implode('/', $this->vars) . '/';
    }
}
?>
