/**
 * @file
 * $Id$
 * $Revision$
 * $Author$
 * $Date$
 *
 * This file is part of The iWear Framework.
 * In particular this file is part of the Framework Core Library
 *
 * The iWear Framework is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by the
 * Free Software Foundation as in version 2 of the License.

 * 
 * The iWear Framework is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * The iWear Framework; if not, write to the Free Software Foundation, Inc., 59
 * Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifndef __IWEAR_MODULE_H
#define __IWEAR_MODULE_H

#ifndef __IWEAR_MODULE_ENUMS_H
#include <iwear/module_enums.h>
#endif

#ifndef __IWEAR_UID_H
#include <iwear/uid.h>
#endif

#ifndef __IWEAR_THREADLOCKED_H
#include <iwear/threadlocked.h>
#endif

namespace iwear {
// Forward declaration and forward declaration for it ;)
class PManBase;    
//template <class Types, class ObjBase, class MasterObj> class ModuleManager;

/**
 * This is a base class for all low-level Modules. 
 * Since all Modules should have the ability to present power information, and
 * react on power states, this is done in the base class.
 * @note Although this seems to be usefull, modules have by design no default
 * locking mecahnism available. Whenever a locking mechanism is needed, the
 * derived class needs to take care of it. This is also the reason why we do
 * this : the modules know best what and where to lock, and if interlocks need
 * to be used and so on.
 */
class Module: public virtual ThreadLocked
{
    friend class BaseModuleManager;
private:
   /**
    * We don't permit Modules without managers
    */
    Module( ) {}
protected:
   /**
    * This is the name of the module in a human readble form. Should always be
    * set from derived classes.
    */
    std::string my_name;

   /**
    * The Module Manager we should have registered to. Be aware that this might
    * be NULL
    */
    PManBase* ModMan;

   /**
    * A unique identifier for a Module
    */
    const uid ID;

   /**
    * The Actual active power_state
    */
    power_state PState : ENUM_MIN_BITS(power_state);

   /**
    * The Actual active energy_state
    */
    energy_state EState : ENUM_MIN_BITS(energy_state);

   /**
    * Any Module *MUST* use this flag for choosing activity states.
    */
    bool active : 1;

   /**
    * This flag is true, if the data has been flushed, false if the currently
    * waiting data has not yet been read. The exact meaning of this may differ
    * from module to module.
    * @note This is mutable, so can also be set when the object is const
    */
    mutable bool flushed : 1;

public:
   /**
    * We need a pointer to a generic module manager here. The Module will then
    * automatically register at the generic module manager. This Manager will
    * then check for the kind of the module and will register it at the
    * corresponding module managers for subsystem modules.
    * @param mm is the module Manager this Module should register to. It is
    * permitted that the Manager is NULL, but not recommended. The only case
    * where this should be done is, when a library creates an object that needs
    * to be internally created.
    */
    Module( PManBase* mm, const uid& id ) : my_name("unnamed module"),ModMan(mm), ID(id) { }

   /**
    * This is in case the caller does not want a specific uid, but only one for
    * every new object..
    */
    Module( PManBase* mm ) : my_name("unnamed module"),ModMan(mm) { }

   /**
    * Destroying the object will deregister at the ModuleManager. Therefore
    * derived Modules shall only deregister at their specialized managers.
    */
    virtual ~Module();
    
   /**
    * @return true if the Module is active and can be used.
    */
    bool is_active( void ) const { return active; }

   /**
    * Set this module active, or inactive. Without parameter the module will be
    * set active.
    */
    void set_active( bool n=true ) { active = n; } 
    
   /**
    * Sets the module inactive when parameter is ommitted.
    */
    void set_inactive( bool b=false ) { active = b; }

   /**
    * Get the uid of this module.
    * @return Reference of the modules uid
    */
    const uid& get_uid( void ) const { return ID; }

   /**
    * Ask the module if it has been flushed. For sensor like modules, a change
    * from the state of flushed to not flushed indicates that new data has
    * arrived.
    * @return true if the module has been flushed
    */
    bool is_flushed( void ) const { return flushed; }

   /**
    * Tell the object that it has been flushed. Usually this should always be
    * done whenever data is read from the object. Since this should be possible
    * even when the object is const, the flush flag is mutable.
    */
    void flush( void ) const { flushed = true; }

    virtual power_state actual_power_state( void ) const { return PState; }

    virtual energy_state actual_energy_state( void ) const { return EState; }

    virtual module_type get_module_type( void ) const = 0;

   /**
    * To set a module in a specific power state this function can be used.
    * @return 0 if success, another value if otherwise, maybe a module dependent error number.
    */
    virtual uint32_t activate_power_state( power_state ) = 0;

    bool operator==( const Module& m ) const { return ID == m.ID; }
    bool operator!=( const Module& m ) const { return ID != m.ID; }

    /**
     * Should return a unique name for every module that is human readable...
     */
    const std::string& get_name( void ) const { return my_name; }
};

} // namespace iwear

#endif

