<?php
/**
 * The Turba_AbstractObject:: class provides an interface for Turba objects -
 * people, groups, restaurants, etc.
 *
 * $Horde: turba/lib/AbstractObject.php,v 1.33.2.3 2005/06/23 00:47:16 selsky Exp $
 *
 * @author  Chuck Hagenbuch <chuck@horde.org>
 * @author  Jon Parise <jon@csh.rit.edu>
 * @since   Turba 0.0.1
 * @package Turba
 */
class Turba_AbstractObject {

    /**
     * Underlying driver.
     *
     * @var Turba_Driver
     */
    var $driver;

    /**
     * Hash of attributes for this contact.
     *
     * @var array
     */
    var $attributes;

    /**
     * Constructs a new Turba_AbstractObject object.
     *
     * @param Turba_Driver $driver  The source that this object came from.
     * @param array $attributes     Hash of attributes for this object.
     */
    function Turba_AbstractObject(&$driver, $attributes = array())
    {
        $this->driver = &$driver;
        $this->attributes = $attributes;
    }

    /**
     * Returns a key-value hash containing all properties of this object.
     *
     * @return array  All properties of this object.
     */
    function getAttributes()
    {
        return $this->attributes;
    }

    /**
     * Returns the name of the address book that this object is from.
     */
    function getSource()
    {
        return $this->driver->name;
    }

    /**
     * Returns the value of the specified attribute.
     *
     * @param string $attribute  The attribute to retrieve.
     *
     * @return string  The value of $attribute, or the empty string.
     */
    function getValue($attribute)
    {
        /* Cache hooks to avoid file_exists() calls. */
        static $hooks;

        if (!isset($hooks)) {
            $hooks = array();
            if (file_exists(HORDE_BASE . '/config/hooks.php')) {
                require_once HORDE_BASE . '/config/hooks.php';
            }
        }
        if (!isset($hooks[$attribute])) {
            $function = '_turba_hook_decode_' . $attribute;
            if (function_exists($function)) {
                $hooks[$attribute] = $function;
            } else {
                $hooks[$attribute] = false;
            }
        }

        if (isset($this->attributes[$attribute]) && !empty($hooks[$attribute])) {
            return call_user_func($hooks[$attribute], $this->attributes[$attribute]);
        }

        if (isset($this->driver->map[$attribute]) &&
            is_array($this->driver->map[$attribute])) {
            $args = array($this->driver->map[$attribute]['format']);
            foreach ($this->driver->map[$attribute]['fields'] as $field) {
                $args[] = $this->getValue($field);
            }
            return call_user_func_array('sprintf', $args);
        } else {
            return (isset($this->attributes[$attribute]) ? $this->attributes[$attribute] : null);
        }
    }

    /**
     * Sets the value of the specified attribute.
     *
     * @param string $attribute  The attribute to set.
     * @param string $value      The value of $attribute.
     */
    function setValue($attribute, $value)
    {
        if (file_exists(HORDE_BASE . '/config/hooks.php')) {
            require_once HORDE_BASE . '/config/hooks.php';
            $function = '_turba_hook_encode_' . $attribute;
            if (function_exists($function)) {
                $value = call_user_func($function, $value,
                                        $this->attributes[$attribute]);
            }
        }

        if (isset($this->driver->map[$attribute]) &&
            is_array($this->driver->map[$attribute])) {
            return false;
        }

        $this->attributes[$attribute] = $value;
        return true;
    }

    /**
     * Determines whether or not the object has a value for the specified
     * attribute.
     *
     * @param string $attribute  The attribute to check.
     *
     * @return boolean  Whether or not there is a value for $attribute.
     */
    function hasValue($attribute)
    {
        if (isset($this->driver->map[$attribute]) &&
            is_array($this->driver->map[$attribute])) {
            foreach ($this->driver->map[$attribute]['fields'] as $field) {
                if ($this->hasValue($field)) {
                    return true;
                }
            }
            return false;
        } else {
            return !is_null($this->getValue($attribute));
        }
    }

    /**
     * Returns true if this object is a group of multiple contacts.
     *
     * @return boolean  True if this object is a group of multiple contacts.
     */
    function isGroup()
    {
        return false;
    }

    /**
     * Returns true if this object is editable by the current user.
     *
     * @return boolean  Whether or not the current user can edit this object
     */
    function isEditable()
    {
        if (!$this->driver->readonly) {
            return true;
        } elseif (is_array($this->driver->admin) &&
                  in_array(Auth::getAuth(), $this->driver->admin)) {
            return true;
        } elseif ($this->hasValue('__owner') &&
                  $this->getValue('__owner') == Auth::getAuth()) {
            return true;
        }

        return false;
    }

    /**
     * Saves the current state of the object to the storage backend.
     */
    function store()
    {
        $object_id = $this->driver->save($this);
        if (is_a($object_id, 'PEAR_Error')) {
            return $object_id;
        }

        return $this->setValue('__key', $object_id);
    }

}
