/***************************************************************************
 *   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 GWECONTROLLERH
#define GWECONTROLLERH

#include <qobject.h>
#include <qvaluelist.h>

namespace GCS
{

class GElement;
class GElementID;
class GElementInfluence;
class GEnergy;

}

namespace GWE
{

//QPtrList<GElement> (this way we don't need to include <GElement.h>
//  - GweController is a public interface, should not have additional #include dependencies
class QPtrListGElement;

class GDataController;

/**
  \Interface GweController GweController.h
  \brief Base class for G World Engine (GWE) controller implementations
  @author Raphael Langerhorst
  
  GweController defines the interface for the GWE controller implementation.
  The GWEs single purpose is persistent element management and thus
  has a very slim and effective interface definition. Whether this
  implementation is a dynamic network distributed hierarchical
  server structure with database backend or a simple local implementation
  does not matter.
  
  @note Some documentation given here on this class (or interface)
  depends on the actual implementation that is used; the implementation
  is "supposed" to do what the documentation of the method says.
  
  @todo use exceptions as they provide a better way for failure description.(??)
        talk about this on the mailing list first!!
  
*/

class GweController : public QObject
{
  Q_OBJECT
  
  protected:
  
    /**
     * Every GWE Controller needs to have a data controller anyway,
     * so it is already present in this base class and can be used
     * be derived controllers.
     * @note the data controller is passed in the constructor
     */
    GDataController* Data;
  
  public:
  
    /**
     * Constructor.
     * @param data the GDataController used
     */
    GweController(GDataController* data, QObject *parent = 0, const char *name = 0);
  
    /**
     * Virtual destructor to allow clean memory management
     * with derived classes.
     */
    virtual ~GweController();
    
    // HELPER OBJECTS //
 
    /**
     * @Returns The data controller used.
     */   
    virtual GDataController* getDataController();
    
    /**
     * @Returns The data controller used, read-only.
     */   
    virtual const GDataController* getDataController() const;
    
  protected:
  
    // USEFUL MANAGEMENT ROUTINES //
    
  protected slots:
  
    /**
     * Connects the following element signals in a standard way,
     * data is the GDataController that is used.
     * - connect(element,SIGNAL(childElementCreated(GCS::GElement*)),
     *           Data,SLOT(add(GCS::GElement*)));
     * - connect(element,SIGNAL(radiateInfluence(const GCS::GElementInfluence&)),
     *           this,SLOT(radiateInfluence(const GCS::GElementInfluence& )));
     * - connect(element,SIGNAL(sendInfluence(const GCS::GElementID&, const GCS::GElementInfluence& )),
     *           this,SLOT(routeInfluence(const GCS::GElementID&, const GCS::GElementInfluence& )));
     * - connect(element,SIGNAL(formChanged(const GCS::GForm& )),
     *           this,SLOT(handleReparenting()));
     * - connect(element,SIGNAL(energyChanged(const GCS::GEnergy& )),
     *           this,SLOT(removeElementWithNoEnergyLeft(const GCS::GEnergy& )));
     */
    virtual void connectBasicElementSignals(const GCS::GElementID& id);
    
  protected:
    
    /**
     * Uses the data controller to find all elements that are
     * in the range of the given source element. Elements in
     * range are simply all elements that touch each other.
     * 
     * This method is usually used to find all elements that are
     * affected by an influence.
     * 
     * If the source element has no form, the form of the parent
     * element is used as boundary, until a element with a form
     * is found or traversal count reaches max_depth_parent.
     * 
     * Normally max_traverse_parents is not set to anything larger than
     * 1. If it is necessary it most likely because of a bad element design.
     * Still, it can be useful in some cases.
     * 
     * @param source The element that defines the range of affected elements.
     * @param max_traverse_children Sets the maximum element hierarchy traversal
     *        limit in the direction of children; 0 means no children at all,
     *        1 means all direct children, ...
     * @param max_traverse_parents Sets the maximum element hierarchy traversal limit
     *        in the direction of parents; 0 means no parents (not even the parent
     *        of the source element!), 1 means including the direct parent; a higher
     *        value than 1 only makes sense if neither the source nor the parent
     *        element have a form attribute. The real maximum of parent traverses is
     *        defined by the minimum of this parameter and the number of traversals to
     *        the first parent with a form and the number of traversals to the root
     *        element.
     * 
     * @returns List of elements that overlap with their form with the source element.
     */
    virtual QPtrListGElement findInRange(GCS::GElement* source, unsigned max_traverse_children = 0, unsigned max_traverse_parents = 1);
    
  public slots:
    
    virtual void executeOpenElement(const GCS::GElementID& id);
        
    // INFLUENCE MANAGEMENT //
  
    /**
     * Forwards given influence to all elements that are near to the
     * sender() of this signal.
     *
     * @see GElement::radiateInfluence()
     */
    virtual void radiateInfluence(const GCS::GElementInfluence& influence);
    
    /**
     * Routes an influence from an element to given destination.
     *
     * @see GElement::routeInfluence()
     */
    virtual void routeInfluence(const GCS::GElementID& destination, const GCS::GElementInfluence& influence);
    
    /**
     * Checks if given element (sender()) leaves it's current
     * parent or enters a sibling element.
     * In case any of this applies, reparenting is performed.
     * 
     * Usually this slot can be connected to the formChanged() signal of
     * an element.
     */
    virtual void handleReparenting();

    /**
     * Checks if given element (sender()) has an energy amount of 0
     * in which case it is deleted.
     *
     * Usually this slot can be connected to the energyChanged() signal of
     * an element.
     */
    virtual void removeElementWithNoEnergyLeft(const GCS::GEnergy& changedEnergy);

    /**
     * Shuts down the whole World Engine and does all required
     * cleanup beforehand. It is highly recommended to call
     * this slot before shutting down the application.
     *
     * At the end the quit signal is emitted. In this
     * state all cleanup and shutdown is down and the
     * application can safely quit.
     * @see quit()
     */
    virtual void shutdown();
    
  signals:
    
    /**
     * Emitted when the GWE Server should shutdown.
     * @see shutdown()
     */
    void quit();
  
};

}

#endif
