<?php

require_once 'common/IObject.php';

/**
 * Base class. It's the root to any other class, in a java-like manner.
 * 
 * This class is closely related to <em>ObjectInspector</em> and 
 * <em>BaseException</em>, which also depends on this class. So, this two
 * classes are included at the end of this file, to avoid recursive includings.
 * <br />
 * It's function is to provide a standard set of basic methods, and a 
 * centralized place to extend or adapt all your classes at once, for 
 * example, when a new PHP version is released.
 * There's some <em>magic</em> methods that are declared and empty
 * implemented, because the __call() would else throw an error that should
 * be silently ignored else.
 * <br />
 * The interface <em>IObject</em>, defined at <em>common/IObject.php</em>, is 
 * implemented by this class. This interface is also implemented by 
 * <em>BaseException</em>, because it must extend PHP's own <em>Exception</em> 
 * class, and then can't extends <em>Object</em> too.
 * 
 * @author  $Author: pruna $
 * @package common
 * @version $Revision: 1.3 $
 * @created 12-Dic-2003
 * @modified $Date: 2005/12/06 02:56:45 $
 */
class Object implements IObject {

    /**
     * Throws an Exception for unimplemented methods.
     * This method could be extended to log the error.
     *
     * @access    public
     * @param     string    $name         Method called in this object
     * @param     array     $arguments    Parameters passed
     */
    public function __call($name, $arguments) {
        throw new BaseException("Unimplemented method: '$name' in class " 
            . ObjectInspector::getClass($this) . " (called with " 
            . var_export($arguments, TRUE) . ")", 
            BaseException::CODE_UNIMPLEMENTED_METHOD, $this);
    }
    
    /**
     * Special method called when cloning an object.
     * An object's __clone() method cannot be called directly.
     * Usage example: $copy_of_object = clone $object;
     *
     * @access    public
     */
    public function __clone() {}
    
    /**
     * Empty constructor.
     * It facilitates parent constructor invocation, because if the object extends
     * from this class, it won't throw an error for not having a constructor.
     *
     * @access    public
     */
    public function __construct() {}
    
    /**
     * Empty destructor.
     * It facilitates parent destructor invocation, because if the object extends
     * from this class, it won't throw an error for not having a destructor.
     *
     * @access    public
     */
    public function __destruct() {}
    
    /**
     * Compares the specified object with this object for equality.
     *
     * @access    public
     * @param     mixed     $object    Object to be compared whit $this
     * @return    boolean
     */
    public function equals($object) {
        return ($this === $object);
    }
    
    /**
     * Returns string hash representation for this object.
     *
     * @access    public
     * @return    string
     */
    public function hashCode() {
        return md5($this->__toString());
    }
    
    /**
     * Magic method to <em>sleep</em> an object.
     * This method is called prior to serialization.
     *
     * @access    public
     * @return    array
     */
    public function __sleep() {
        return array_keys(ObjectInspector::getAttributes($this));
    }
    
    /**
     * Returns a string representation of this object.
     *
     * @access    public
     * @return    string
     */
    public function __toString() {
        return var_export($this, TRUE);
    }
    
    /**
     * Returns a SimpleXML representation of this object.
     * 
     * @access    public
     * @return    SimpleXML
     */
    public function toXML() {
        return simplexml_load_string($this->toXMLString());
    }
    
    /**
     * Returns a XML string representation of this object.
     * Implementation is based on ObjectInspector::getInfo() method.
     * Note: this method could be moved to ObjectInspector class. However, 
     * right now keeping the method here allows to an easier use.
     * 
     * @access    public
     * @return    string
     */
    public function toXMLString() {
        $sp = "\t";
        $attribs = '';
        $oI = new ObjectInspector();
        foreach ($oI->getAttributes($this) as $k => $v) {
            $attribs .= $sp . $sp . '<attrib name="' . $k . '" type="' 
                . gettype($v) . '">' . $v . '</attrib>' . PHP_EOL;
        }
        $methods = '';
        foreach ($oI->getMethods($this) as $v) {
            $methods .= $sp . $sp . '<method>' . $v . '</method>' . PHP_EOL;
        }
        $parents = '';
        foreach ($oI->getHierarchy($this) as $v) {
            $parents .= $sp . $sp . '<parent>' . $v . '</parent>' . PHP_EOL;
        }
        $interfaces = '';
        foreach ($oI->getInterfaces($this) as $v) {
            $interfaces .= $sp . $sp . '<interface>' . $v . '<interface>' 
                . PHP_EOL;
        }
        return '<class name="' . $oI->getClass($this) . '">' . PHP_EOL . 
            ($parents?$sp . '<parents>' . PHP_EOL . $parents . $sp . 
                '</parents>' . PHP_EOL:'') .
            ($interfaces?$sp . '<interfaces>' . PHP_EOL . $interfaces . 
                $sp . '</interfaces>' . PHP_EOL:'') . 
            ($attribs?$sp . '<attributes>' . PHP_EOL . $attribs . $sp . 
                '</attributes>' . PHP_EOL:'') .
            ($methods?$sp . '<methods>' . PHP_EOL . $methods . $sp . 
                '</methods>' . PHP_EOL:'') . 
            '</class>' . PHP_EOL;
    }
    
    /**
     * Magic method to "unsleep" an object.
     * This method is called prior to unserialization.
     *
     * @access    public
     */
    public function __wakeup() {}
    
}

/**
 * As this 2 classes are used by <em>Object</em>, but at same time both also 
 * depends on <em>Object</em>, they are required here to ensure that 
 * <em>Object</em> class has been properly defined.
 */
require_once 'common/BaseException.php';
require_once 'common/ObjectInspector.php';

?>