<?php
/**
 * Base class for HTML_QuickForm2 groups
 *
 * PHP version 5
 *
 * LICENSE:
 *
 * Copyright (c) 2006-2010, Alexey Borzov <avb@php.net>,
 *                          Bertrand Mansion <golgote@mamasam.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *    * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *    * Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *    * The names of the authors may not be used to endorse or promote products
 *      derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @category   HTML
 * @package    HTML_QuickForm2
 * @author     Alexey Borzov <avb@php.net>
 * @author     Bertrand Mansion <golgote@mamasam.com>
 * @license    http://opensource.org/licenses/bsd-license.php New BSD License
 * @version    SVN: $Id: Group.php 294057 2010-01-26 21:10:28Z avb $
 * @link       http://pear.php.net/package/HTML_QuickForm2
 */

/**
 * Base class for all HTML_QuickForm2 containers
 */
// require_once 'HTML/QuickForm2/Container.php';

/**
 * Base class for QuickForm2 groups of elements
 *
 * @category   HTML
 * @package    HTML_QuickForm2
 * @author     Alexey Borzov <avb@php.net>
 * @author     Bertrand Mansion <golgote@mamasam.com>
 * @version    Release: @package_version@
 */
class HTML_QuickForm2_Container_Group extends HTML_QuickForm2_Container
{
   /**
    * Group name
    * If set, group name will be used as prefix for contained
    * element names, like groupname[elementname].
    * @var string
    */
    protected $name;

   /**
    * Previous group name
    * Stores the previous group name when the group name is changed.
    * Used to restore children names if necessary.
    * @var string
    */
    protected $previousName;

    public function getType()
    {
        return 'group';
    }

    protected function prependsName()
    {
        return strlen($this->name) > 0;
    }

    public function getValue()
    {
        $value = parent::getValue();
        if (!$this->prependsName()) {
            return $value;

        } elseif (!strpos($this->getName(), '[')) {
            return isset($value[$this->getName()])? $value[$this->getName()]: null;

        } else {
            $tokens   =  explode('[', str_replace(']', '', $this->getName()));
            $valueAry =& $value;
            do {
                $token = array_shift($tokens);
                if (!isset($valueAry[$token])) {
                    return null;
                }
                $valueAry =& $valueAry[$token];
            } while ($tokens);
            return $valueAry;
        }
    }

    public function setValue($value)
    {
        // Prepare a mapper for element names as array

        if ($this->prependsName()) {
            $prefix = explode('[', str_replace(']', '', $this->getName()));
        }

        $elements = array();
        foreach ($this as $child) {
            $tokens = explode('[', str_replace(']', '', $child->getName()));
            if (!empty($prefix)) {
                $tokens = array_slice($tokens, count($prefix));
            }
            $elements[] = $tokens;
        }

        // Iterate over values to find corresponding element

        $index = 0;

        foreach ($value as $k => $v) {
            $val = array($k => $v);
            $found = null;
            foreach ($elements as $i => $tokens) {
                do {
                    $token = array_shift($tokens);
                    $numeric = false;
                    if ($token == "") {
                        // Deal with numeric indexes in values
                        $token = $index;
                        $numeric = true;
                    }
                    if (isset($val[$token])) {
                        // Found a value
                        $val = $val[$token];
                        $found = $val;
                        if ($numeric) {
                            $index += 1;
                        }
                    } else {
                        // Not found, skip next iterations
                        $found = null;
                        break;
                    }

                } while (!empty($tokens));

                if (!is_null($found)) {
                    // Found a value corresponding to element name
                    $child = $this->elements[$i];
                    $child->setValue($val);
                    unset($val);
                    if (!($child instanceof HTML_QuickForm2_Container_Group)) {
                        // Speed up next iterations
                        unset($elements[$i]);
                    }
                    break;
                }
            }
        }
    }


    public function getName()
    {
        return $this->name;
    }

    public function setName($name)
    {
        $this->previousName = $this->name;
        $this->name = $name;
        foreach ($this as $child) {
            $this->renameChild($child);
        }
        return $this;
    }

    protected function renameChild(HTML_QuickForm2_Node $element)
    {
        $tokens = explode('[', str_replace(']', '', $element->getName()));
        if ($this === $element->getContainer()) {
            // Child has already been renamed by its group before
            if (!is_null($this->previousName) &&
                $this->previousName !== '') {
                $gtokens = explode('[', str_replace(']', '', $this->previousName));
                $pos = array_search(end($gtokens), $tokens);
                if (!is_null($pos)) {
                    $tokens = array_slice($tokens, $pos+1);
                }
            }
        }
        if (is_null($this->name) || $this->name === '') {
            if (is_null($this->previousName) || $this->previousName === '') {
                return $element;
            } else {
                $elname = $tokens[0];
                unset($tokens[0]);
                foreach ($tokens as $v) {
                    $elname .= '['.$v.']';
                }
            }
        } else {
            $elname = $this->getName().'['.implode('][', $tokens).']';
        }
        $element->setName($elname);
        return $element;
    }

   /**
    * Appends an element to the container
    *
    * If the element was previously added to the container or to another
    * container, it is first removed there.
    *
    * @param    HTML_QuickForm2_Node     Element to add
    * @return   HTML_QuickForm2_Node     Added element
    * @throws   HTML_QuickForm2_InvalidArgumentException
    */
    public function appendChild(HTML_QuickForm2_Node $element)
    {
        if (null !== ($container = $element->getContainer())) {
            $container->removeChild($element);
        }
        // Element can be renamed only after being removed from container
        $this->renameChild($element);

        $element->setContainer($this);
        $this->elements[] = $element;
        return $element;
    }

   /**
    * Removes the element from this container
    *
    * If the reference object is not given, the element will be appended.
    *
    * @param    HTML_QuickForm2_Node     Element to remove
    * @return   HTML_QuickForm2_Node     Removed object
    */
    public function removeChild(HTML_QuickForm2_Node $element)
    {
        $element = parent::removeChild($element);
        if ($this->prependsName()) {
            $name = preg_replace('/^' . $this->getName() . '\[([^\]]*)\]/', '\1', $element->getName());
            $element->setName($name);
        }
        return $element;
    }

   /**
    * Inserts an element in the container
    *
    * If the reference object is not given, the element will be appended.
    *
    * @param    HTML_QuickForm2_Node     Element to insert
    * @param    HTML_QuickForm2_Node     Reference to insert before
    * @return   HTML_QuickForm2_Node     Inserted element
    */
    public function insertBefore(HTML_QuickForm2_Node $element, ?HTML_QuickForm2_Node $reference = null)
    {
        if (null === $reference) {
            return $this->appendChild($element);
        }
        return parent::insertBefore($this->renameChild($element), $reference);
    }

   /**
    * Sets string(s) to separate grouped elements
    *
    * @param    string|array    Use a string for one separator, array for
    *                           alternating separators
    * @return   HTML_QuickForm2_Container_Group
    */
    public function setSeparator($separator)
    {
        $this->data['separator'] = $separator;
        return $this;
    }

   /**
    * Returns string(s) to separate grouped elements
    *
    * @return   string|array    Separator, null if not set
    */
    public function getSeparator()
    {
        return isset($this->data['separator'])? $this->data['separator']: null;
    }

   /**
    * Renders the group using the given renderer
    *
    * @param    HTML_QuickForm2_Renderer    Renderer instance
    * @return   HTML_QuickForm2_Renderer
    */
    public function render(HTML_QuickForm2_Renderer $renderer)
    {
        $renderer->startGroup($this);
        foreach ($this as $element) {
            $element->render($renderer);
        }
        $renderer->finishGroup($this);
        return $renderer;
    }

    public function __toString()
    {
        // require_once 'HTML/QuickForm2/Renderer.php';

        return $this->render(
                   HTML_QuickForm2_Renderer::factory('default')
                       ->setTemplateForId($this->getId(), '{content}')
               )->__toString();
    }
}
?>
