<?php

require_once 'common/Object.php';
require_once 'common/collection/ArrayList.php';

/**
 * Bean's util method's class.
 * 
 * This class holds different methods that are usefull when 
 * working with Bean objects.
 * 
 * @author  $Author: pruna $
 * @package common/bean
 * @version $Revision: 1.3 $
 * @created 02-Apr-2005
 * @modified $Date: 2005/12/06 02:56:45 $
 */
class BeanUtils extends Object {
    
    /**
     * @const   Method to copy beans: based on destination bean attributes
     */
    const COPY_METHOD_RIGHT = 'right';
    
    /**
     * @const   Method to copy beans: based on origin bean attributes
     */
    const COPY_METHOD_LEFT = 'left';
    
    /**
     * @const   Method to copy beans: based on common attributes on both beans
     */
    const COPY_METHOD_INNER = 'inner';
    
    /**
     * @const   Method to copy beans: based on attributes on any bean
     */
    const COPY_METHOD_OUTER = 'outer';
    
    /**
     * Returns adder method name for attrName.
     * Attribute is a <em>ICollection</em>, so this method returns an "add to".
     * 
     * @access   public
     * @param    string     $attrName    Attribute's name
     * @return   string
     */
    public function adderName($attrName) {
        return Bean::PREFIX_ADD_TO . ucfirst($attrName);
    }
    
    /**
     * Copy atributes from one bean to another.
     * Destination bean is modified, and also returned.
     * Supports four methods to determine how to copy, similar to sql 'join':
     * <ul>
     * <li>right: based on destination bean attributes (default)</li>
     * <li>left: based on origin bean attributes</li>
     * <li>inner: based on common attributes on both beans</li>
     * <li>outer: based on attributes on any bean</li>
     * </ul>
     *
     * @access   public
     * @param    object   $beanFrom   Source bean to get attributes
     * @param    object   $beanTo     Destination bean to store attributes
     * @param    string   $method     Method to determine which attribs copy
     * @return   object
     */
    public function copy($beanFrom, $beanTo, 
        $method = BeanUtils::COPY_METHOD_RIGHT) {
        
        $keys = new ArrayList();
        if ($method === BeanUtils::COPY_METHOD_LEFT 
            || $method === BeanUtils::COPY_METHOD_OUTER) {
            
            $keys->addAll($beanFrom->keys());
        }
        if ($method === BeanUtils::COPY_METHOD_RIGHT 
            || $method === BeanUtils::COPY_METHOD_OUTER) {
            
            $keys->addAll($beanTo->keys());
        }
        if ($method === BeanUtils::COPY_METHOD_INNER) {
            // array_intersect_key() is only in CVS by now
            foreach ($beanFrom->keys() as $key) {
                if ($beanTo->containsKey($key)) {
                    $keys->add($key);
                }
            }
        }
        $it = $keys->getIterator();
        while ($it->hasMore()) {
            $getter = BeanUtils::getterName($it->next());
            $setter = BeanUtils::setterName($it->current());
            $beanTo->$setter($beanFrom->$getter());
        }
        return $beanTo;
    }
    
    /**
     * Returns the value obtained from calling getter method for attrName
     * in bean.
     * 
     * @access   public
     * @param    Bean       $bean        Bean to read attribute from
     * @param    string     $attrName    Attribute's name
     * @return   mixed
     */
    public function getter($bean, $attrName) {
        $getter = BeanUtils::getterName($attrName);
        return $bean->$getter();
    }
    
    /**
     * Returns getter method name for attrName.
     * Method signature is based on <em>type</em> parameter.
     * 
     * @access   public
     * @param    string     $attrName    Attribute's name
     * @param    string     $type        Attribute type's name
     * @return   string
     */
    public function getterName($attrName, $type = null) {
        return ($type === 'boolean' ? Bean::PREFIX_IS : Bean::PREFIX_GET) . ucfirst($attrName);
    }
    
    /**
     * Returns getter method name for attrName.
     * Method signature is based on <em>value</em>'s parameter type.
     * 
     * @access   public
     * @param    string     $attrName    Attribute's name
     * @param    string     $type        Attribute's value
     * @return   string
     */
    public function getterNameByVal($attrName, $value = null) {
        return BeanUtils::getterName($attrName, gettype($value));
    }
    
    /**
     * Merge Collection atributes from one bean to another. It checks that 
     * destination Collection doesn't have this values, and then adds it.
     * Destination bean is modified, and also returned.
     *
     * @access   public
     * @param    object   $beanFrom   Source bean to get attributes
     * @param    object   $beanTo     Destination bean to store attributes
     * @return   object
     */
    public function mergeCollectionValues($beanFrom, $beanTo) {
        foreach ($beanFrom->keys() as $key) {
            $getter = BeanUtils::getterName($key);
            $adder = BeanUtils::adderName($key);
            if (ObjectInspector::isA($beanFrom->$getter(), 'ICollection')) {
                $it = $beanFrom->$getter()->getIterator();
                while ($it->hasMore()) {
                    if ($beanTo->$getter()->contains($it->next())) {
                        $beanTo->$adder($it->current());
                    }
                }
            } elseif (is_array($beanFrom->$getter())) {
                foreach ($beanFrom->$getter() as $val) {
                    if (!in_array($val, $beanTo->$getter())) {
                        $beanTo->$adder($val);
                    }
                }
            }
        }
        return $beanTo;
    }
    
    /**
     * Sets the value to bean attrName, using the proper setter method.
     * in bean.
     * 
     * @access   public
     * @param    Bean       $bean        Bean to read attribute from
     * @param    string     $attrName    Attribute's name
     * @param    mixed      $value       Value to set
     * @return   mixed
     */
    public function setter($bean, $attrName, $value) {
        $setter = BeanUtils::setterName($attrName);
        return $bean->$setter($value);
    }
    
    /**
     * Returns setter method name for attrName.
     * 
     * @access   public
     * @param    string     $attrName    Attribute's name
     * @return   string
     */
    public function setterName($attrName) {
        return Bean::PREFIX_SET . ucfirst($attrName);
    }
    
}

?>