<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0                                                      |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group                                |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.0 of the PHP license,       |
// | that is bundled with this package in the file LICENSE, and is        |
// | available at through the world-wide-web at                           |
// | http://www.php.net/license/2_02.txt.                                 |
// | If you did not receive a copy of the PHP license and are unable to   |
// | obtain it through the world-wide-web, please send a note to          |
// | license@php.net so we can mail you a copy immediately.               |
// +----------------------------------------------------------------------+
// | Authors: Alexey Borzov <borz_off@cs.msu.su>                          |
// |          Bertrand Mansion <bmansion@mamasam.com>                     |
// |          Thomas Schulz <ths@4bconsult.de>                            |
// +----------------------------------------------------------------------+
//
// $Id: SmartyDynamic.php,v 1.2 2005/01/13 12:22:09 ths Exp $

require_once 'HTML/QuickForm/Renderer.php';

/**
 * A concrete renderer for HTML_QuickForm, makes an array of form contents
 *
 * Based on old toArray() code.
 *
 * The form array structure is the following:
 * array(
 *   'frozen'           => 'whether the form is frozen',
 *   'javascript'       => 'javascript for client-side validation',
 *   'attributes'       => 'attributes for <form> tag',
 *   'requirednote      => 'note about the required elements',
 *   // if we set the option to collect hidden elements
 *   'hidden'           => 'collected html of all hidden elements',
 *   // if there were some validation errors:
 *   'errors' => array(
 *     '1st element name' => 'Error for the 1st element',
 *     ...
 *     'nth element name' => 'Error for the nth element'
 *   ),
 *   // if there are no headers in the form:
 *   'elements' => array(
 *     element_1,
 *     ...
 *     element_N
 *   )
 *   // if there are headers in the form:
 *   'sections' => array(
 *     array(
 *       'header'   => 'Header text for the first header',
 *       'elements' => array(
 *          element_1,
 *          ...
 *          element_K1
 *       )
 *     ),
 *     ...
 *     array(
 *       'header'   => 'Header text for the Mth header',
 *       'elements' => array(
 *          element_1,
 *          ...
 *          element_KM
 *       )
 *     )
 *   )
 * );
 *
 * where element_i is an array of the form:
 * array(
 *   'name'      => 'element name',
 *   'value'     => 'element value',
 *   'type'      => 'type of the element',
 *   'frozen'    => 'whether element is frozen',
 *   'label'     => 'label for the element',
 *   'required'  => 'whether element is required',
 *   'error'     => 'error associated with the element',
 *   'style'     => 'some information about element style (e.g. for Smarty)',
 *   // if element is not a group
 *   'html'      => 'HTML for the element'
 *   // if element is a group
 *   'separator' => 'separator for group elements',
 *   'elements'  => array(
 *     element_1,
 *     ...
 *     element_N
 *   )
 * );
 *
 * @access public
 */
class HTML_QuickForm_Renderer_SmartyDynamic extends HTML_QuickForm_Renderer
{
   /**
    * An array being generated
    * @var array
    */
    var $_ary;

   /**
    * Number of sections in the form (i.e. number of headers in it)
    * @var integer
    */
    var $_sectionCount;

   /**
    * Current section number
    * @var integer
    */
    var $_currentSection;

   /**
    * Array representing current group
    * @var array
    */
    var $_currentGroup = null;

   /**
    * true: collect all hidden elements into string; false: process them as usual form elements
    * @var bool
    */
    var $_collectHidden = false;


   /**
    * The Form object instance - used for callback rendering of generic elements
    * @var object
    */
    var $_form = null;

   /**
    * The Smarty template engine instance
    * @var object
    */
    var $_tpl = null;

   /**
    * a directory relatated to the current template dir for the
    * @var object
    */
    var $_tplSubdir = null;

   /**
    * Constructor
    *
    * @access public
    */
    function HTML_QuickForm_Renderer_SmartyDynamic(&$tpl, $tplSubdir='', $collectHidden=false)
    {
        $this->HTML_QuickForm_Renderer();
        $this->_collectHidden = $collectHidden;
        $this->_tpl =& $tpl;
        $this->_tplSubdir = $tplSubdir . '/';

        // register the smarty Modifier for element rendering
        $tpl->register_function('qfe', array(&$this, 'smarty_function_qfe'));

    }


   /**
    * Returns the resultant array
    *
    * @access public
    * @return array
    */
    function toArray()
    {
        return $this->_ary;
    }


    function startForm(&$form)
    {
        $this->_form =& $form;
        $this->_ary = array(
            'frozen'            => $form->isFrozen(),
            'javascript'        => $form->getValidationScript(),
            'attributes'        => $form->getAttributes(true),
            'requirednote'      => $form->getRequiredNote(),
            'errors'            => array()
        );
        if ($this->_collectHidden) {
            $this->_ary['hidden'] = '';
        }
        $this->_elementIdx     = 1;
        $this->_currentSection = null;
        $this->_sectionCount   = 0;
    }


    function renderHeader(&$header)
    {
        $this->_ary['sections'][$this->_sectionCount] = array('header' => $header->toHtml());
        $this->_currentSection = $this->_sectionCount++;
    }


    function renderElement(&$element, $required, $error)
    {
        $elAry = $this->_elementToArray($element, $required, $error);
        if (!empty($error)) {
            $this->_ary['errors'][$elAry['name']] = $error;
        }
        $this->_storeArray($elAry);
    }


    function renderHidden(&$element)
    {
        if ($this->_collectHidden) {
            $this->_ary['hidden'] .= $element->toHtml() . "\n";
        } else {
            $this->renderElement($element, false, null);
        }
    }


    function startGroup(&$group, $required, $error)
    {
        $this->_currentGroup = $this->_elementToArray($group, $required, $error);
        if (!empty($error)) {
            $this->_ary['errors'][$this->_currentGroup['name']] = $error;
        }
    }


    function finishGroup(&$group)
    {
        $this->_storeArray($this->_currentGroup);
        $this->_currentGroup = null;
    }


   /**
    * Creates an array representing an element
    *
    * @access private
    * @param  object    An HTML_QuickForm_element object
    * @param  bool      Whether an element is required
    * @param  string    Error associated with the element
    * @return array
    */
    function _elementToArray(&$element, $required, $error)
    {
        // prevent double calls on generic elements
        $ret['type'] = $element->getType();

        // indicate generic elements
        $ret['generic'] = false;
        if (isset($GLOBALS['_4BC_QUICKFORM_GENERIC_TYPES'][$ret['type']])) {
            $ret['generic'] = true;
            // prevent double rendering for generic elements
            if (!empty($element->_renderedArray)) {
                return $element->_renderedArray;
            }
        }
        
        $ret['name']        = $element->getName();
        $ret['value']       = $element->getValue();
        $ret['frozen']      = $element->isFrozen();
        $ret['required']    = $required;
        $ret['error']       = $error;

        // render label(s)
        $labels = $element->getLabel();
        if (is_array($labels)) {
            foreach($labels as $key => $label) {
                $key = is_int($key)? $key + 1: $key;
                if (1 === $key) {
                    $ret['label'] = $label;
                } else {
                    $ret['label_' . $key] = $label;
                }
            }
        } else {
            $ret['label'] = $labels;
        }

        if ('group' == $ret['type']) {
            $ret['separator'] = $element->_separator;
            $ret['elements']  = array();
        } elseif ($ret['generic']) {
            // store the rendered array for generic elements
            $element->_renderedArray = $ret;
        } else {
            // get html and html attributes as array
            $ret['html'] = $element->toHtml();
            $ret['html_attr'] = $element->getAttributes();
        }
        return $ret;
    }

 
   /**
    * Stores an array representation of an element in the form array
    *
    * @access private
    * @param array  Array representation of an element
    * @return void
    */
    function _storeArray($elAry)
    {
        // where should we put this element...
        if (is_array($this->_currentGroup) && ('group' != $elAry['type'])) {
            $this->_currentGroup['elements'][] = $elAry;
        } elseif (isset($this->_currentSection)) {
            $this->_ary['sections'][$this->_currentSection]['elements'][] = $elAry;
        } else {
            $this->_ary['elements'][] = $elAry;
        }
    }


   /**
    * smarty function for rendering an generic QuickForm Element
    *
    * @param    string      The element name
    * @param    string      The element style
    * @access   private
    * @return   void
    */
    function smarty_function_qfe($params)
    {
        // detect elemnst name
        if (isset($params['name'])) {
            $elementName = $params['name'];
            unset($params['name']);
        } else {
            $this->_tpl->trigger_error(
                'the name of the element is required: {qfe name=...}'
            );
        }

        // get the elemet and render the array
        $element    =& $this->_form->getElement($elementName);
        $required   = ($this->_form->isElementRequired($elementName) && $this->_form->_freezeAll == false);
        $error      = $this->_form->getElementError($elementName);
        $elementAry = $this->_elementToArray($element, $required, $error);

        // get element attributes and merge additional
        $attributes = $element->getAttributes();
        $params = array_merge($attributes, $params);
        // print_d($params, 'Params Merged');

        // the view param/attribute and type selects the template for rendering
        $view = 'default';
        if (isset($params['view'])) {
            $view = $params['view'];
            unset($params['view']);
        }
        // the template and cache_id for this element
        if ($type = $this->_form->getElementType($elementName)) {
            $template = $this->_tplSubdir . 'qfe_' . $type . '_' . $view . '.tpl';
        } else {
            $this->_tpl->trigger_error(
                'Unkown Type of QuickForm Element "' . $elementName . '" '
            );
        }

        // hand over additional attributes
        $this->_tpl->assign_by_ref('attribute', $params);

        // hand over the element array
        $this->_tpl->assign_by_ref('qfe', $elementAry);

        // set a individual cache id if caching is enabled
        $c_id = 1;
        if ($this->_tpl->caching) {
            $c_id = md5(serialize($elementAry));
        }

        // Render the element...
        // lower error level
        $this->_tpl->error_reporting = 2039;
        $output = $this->_tpl->fetch($template, $c_id);
        // error_reporting($error_reporting);

        // ... and clear the assigned vars
        $this->_tpl->clear_assign(array('qfe', 'attribute'));

        return $output;
    }
}
?>