/***************************************************************************
 *   Copyright (C) 2004 - 2005 by Raphael Langerhorst                      *
 *   raphael-langerhorst@gmx.at                                            *
 *                                                                         *
 *   Permission is hereby granted, free of charge, to any person obtaining *
 *   a copy of this software and associated documentation files (the       *
 *   "Software"), to deal in the Software without restriction, including   *
 *   without limitation the rights to use, copy, modify, merge, publish,   *
 *   distribute, sublicense, and/or sell copies of the Software, and to    *
 *   permit persons to whom the Software is furnished to do so, subject to *
 *   the following conditions:                                             *
 *                                                                         *
 *   The above copyright notice and this permission notice shall be        *
 *   included in all copies or substantial portions of the Software.       *
 *                                                                         *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       *
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    *
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR     *
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
 *   OTHER DEALINGS IN THE SOFTWARE.                                       *
 ***************************************************************************/

#ifndef GOBJECTH
#define GOBJECTH

#include "GElementID.h"

#include <qvaluelist.h>
#include <qmutex.h>

class QDomDocument;

namespace GCS
{

class GEnergy;
class GForm;

class GWorldData;

/**
  \class GObject GObject.h
  \brief Holds all data of an element including energy and form
  @author Raphael Langerhorst
  
  The GObject is very fundamental. Together with GAgent it forms
  GElement. The whole world is ONLY built up with elements.
  The object's role is to represent matter (GForm),
  the matter's attribute is solely energy (GEnergy).
  
  See the detailed description of GObject::Connection for another
  central idea of the G system.


  Parent-child-relation (an advice for agent design):

  Since the world is built in a hierarchical structure every object can
  contain sub-elements so there should be only one element that is its
  own parent - the universe itself.

  The energy difference between children and their parents also affect the
  energy distribution of the parent among its children. This means that if
  a child's energy is like the parent's energy the child is receiving (= is
  able to receive) more energy from the parent than children which have
  completely different kinds of energy because they are not responsive to
  the kind of energy given.

  In other words: the parent distributes its own energy flow among its
  children according to the children's energy levels; the more the child's
  energy is like the parent's, the more energy the child can receive.
  
  @todo Much of this can be handled by GEnergy::put(), it should be implemented there.
  @todo Move all inline methods into implementation files.

  Also there is always some amount of energy that is cast into
  the object's sorroundings, which means: the energy is handed back to the
  object's parent. This probably should be implemented by agents that
  "radiate" influences.
  
  
  @note Considering the use of QObject's object tree for GObject:
  This is not a good idea since it is by no means guranteed that all elements
  are on _one_ machine running on _one_ world engine.
*/

class GObject : public QMutex
{
  private:
    /**
     * The object's energy.
     */
    GEnergy* Energy;
    
    /**
     * The object's form.
     */
    GForm* Form;
        
    /**
     * The element's parent's ID.
     */
    GElementID Parent;
    
    /**
     * The element's ID.
     */
    const GElementID ID;
    
    /**
     * The element ID of the connected element.
     * Connections also represent a central idea of the G system,
     * since any thing can only "exist" if it is concerned with
     * something. This idea can be applied to every setting.
     * Also multiple elements are needed to represent a complex
     * element that is concerned with multiple things.
     * ... think about it ...
     */
    const GElementID Connection;

//   this is left as a comment for idea gathering
//     /**
//      * consider the following situation:
//      * you hava a certain characteristic, for example you
//      * tend to be very happy; if something happens and you
//      * are quite unhappy for a few hours it does not mean
//      * that you are unhappy in general; likely you will
//      * recover and be (almost!!) happy as ever a few days
//      * later;
//      * (and maybe if you have learned something from the
//      * unexpected event so that afterwards you are even
//      * more happy - but this requires influence from your
//      * spirit...)
//      *
//      * so, if the energy changes for what reason ever
//      * this attribute could tell the "ordinary" state of
//      * the element;
//      *
//      * removed, because:
//      * the above comment actually is true, but we have to
//      * consider the way how we get unhappy when we are
//      * normally happy: if we get influenced by different
//      * circumstances than normal then it is likely that
//      * we also feel different; but this will go away as
//      * soon as the different influence also goes away!!
//      */
//    GEnergy LongTermEnergy;

//     The children are not stored anymore, GObject uses GWorldData for this
//     /**
//      * This value list stores all IDs of the element's children.
//      */
//     QValueList<GElementID> Children;
    
    /**
     * Can hold arbitrary additional element data.
     * This can be seen as an element wide storage facility that
     * is shared among all agents.
     */
    QDomDocument* ElementData;
    
    /**
     * This is an interface that can be used by agents to access data
     * from other elements (read only). The implementation also depends
     * on the GWE!
     * It is not the GObject's responsibility to delete the WorldData object.
     */
    const GWorldData* WorldData;

  public:

    /**
     * Constructor
     */
    GObject(GEnergy* energy,
            GForm* form,
            const GElementID& parent,
            const GElementID& ID,
            const GElementID& connection,
            QDomDocument* element_data,
            const GWorldData* WorldData);

    /**
     * A virtual destructor allows cleaner subclassing.
     */
    virtual ~GObject();

    // read methods:
    
    /**
     * @return true when energy is available.
     */
    bool hasEnergy() const;
    
    /**
     * @return pointer to the energy.
     */
    GEnergy* getEnergy();
    
    /**
     * @return const pointer to the energy.
     */
    const GEnergy* getEnergy() const;
    
    /**
     * @return true if a form is available.
     */
    bool hasForm() const;
    
    /**
     * @return pointer to the form.
     */
    GForm* getForm();
    
    /**
     * @return const pointer to the form (const reference).
     */
    const GForm* getForm() const;
    
    /**
     * @return const reference of the parent ID.
     */
    const GElementID& getParent() const;
    
    /**
     * @return const reference of the own element ID.
     */
    const GElementID& getID() const;
    
    /**
     * @return const reference of the ID of the connection element.
     */
    const GElementID& getConnection() const;
    
    /**
     * @return true if this element has additional data.
     */
    bool hasElementData() const;
    
    /**
     * @return const pointer to the additional element data.
     */
    const QDomDocument* getElementData() const;
    
    /**
     * @return pointer to the additional element data.
     */
    QDomDocument* getElementData();
    
    /**
     * @return true if this world data is available.
     */
    bool hasWorldData() const;
    
    /**
     * @return const pointer to the world data.
     */
    const GWorldData* getWorldData() const;
    
    // methods for hierarchy management:
    
    /**
     * Sets given element ID as new parent of this element.
     */
    void reparent(const GElementID& new_parent);

    /**
     * Checks if given element is registered as a child.
     * @note: Only one level is checked and no recursions are
     * done, so if the element with given ID is a child of a
     * child, this method returns false.
     * @return true when element with given ID is a direct child.
     */
    bool isChild(const GElementID&) const;
    
    /**
     * @return list of children IDs.
     */
    QValueList<GElementID> getChildren() const;
};

}

#endif
