/**
 * $Id$
 * $Revision$
 * $Author$
 * $Date$
 *
 * This file is part of The iWear Framework.
 * In particular this file is part of the Framework Output
 *
 * 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 __OUTPUTDATA_H
#define __OUTPUTDATA_H

// Standard includes
#include <list>
#include <map>

// iWear includes
#ifndef __UID_H
#include <iwear/uid.h>
#endif

#ifndef __REFCOUNTEVENT_H
#include <iwear/refcountevent.h>
#endif

#ifndef __EVENTDISPATCHER_H
#include <iwear/eventdispatcher.h>
#endif

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

#ifndef __DEBUGSTREAM_H
#include <iwear/debugstream.h>
#endif

namespace iwear {
namespace output {

// forward declaration - real include in cpp
class OutputDataFunctor;
class OutputDataFunctorParameter;

/**
 * This class is the base class of all OutputData and implements all the
 * registering of functors and notify functionality so that the deriving
 * classes don't have to mess with dispatching events and stuff like that if
 * something happened in the OutputData - they just call notify with a
 * parameter that tells what happens.
 *
 * The register, deregister and notify methods of this class are threadsafe.
 *
 * @author Christian Ober-Bloebaum, Carsten Rachuy
 */
class OutputData : public virtual ThreadLocked {

public:

    /**
     * Constructor for OutputData objects.
     *
     * @param name The name of the output data.
     *
     * @param description A description of the output data.
     *
     * @param type The type of this OutputData that determines the template
     * parameters and the outputmodules that can handle this OutputData.
     */
    OutputData(const uid& application_id,
	       const std::string& name,
	       const std::string& description,
	       const std::string& type);

    /**
     * Destructor for OutputData.
     */
    virtual ~OutputData(void);
    
    /**
     * Get the name of the output data.
     * @return The name of the output data.
     */
    inline const std::string& get_name(void) const {
	return this->name;
    }

    /**
     * Get the description of the output data.
     * @return The description of the output data.
     */
    inline const std::string& get_description(void) const{
	return this->description;
    }

    /**
     * Get the uid of the output data.
     * @return The uid of the output data.
     */
    inline const uid& get_id(void) const {
	return this->id;
    }

    /**
     * Get the uid of the application which own the output data
     * @return The uid of the application 
     */
    inline const uid& get_application_id(void) const {
	return this->application_id;
    }

    /**
     * Register a functor that will be called when something changes in this
     * OutputData.
     *
     * @param functor the functor to be called when an event occurs.
     */
    void register_functor(OutputDataFunctor& functor);

    /**
     * Deregister a functor.
     *
     * @param functor the functor to be deregistred.
     */
    void deregister_functor(OutputDataFunctor& functor);

    /**
     * Get the type of the derived OutputData determining the OutputModules
     * that will display the OutputData.
     *
     * @return The type of the outputdata as a string.
     */
    inline const std::string& get_type(void) const{
	return type;
    }

    /**
     * The method to add event dispatchers to all contained event
     * sources. If the event_dispatcher of one of the files is already
     * set, an exception is thrown.
     * @param event_dispatcher The event_dispatcher.
     * @throws logic_error 
     */
    inline void set_event_dispatcher(EventDispatcher* event_dispatcher){
	this->event_dispatcher = event_dispatcher;
    }
    
    /**
     * Compares the uid's contained in the OutputData's.
     */
    inline bool operator<(const OutputData& od) const{
        return id < od.id;
    }

    /**
     * Compares the uid's contained in the OutputData's.
     */
    inline bool operator>(const OutputData& od) const{
        return id > od.id;
    }

    /**
     * Compares the uid's contained in the OutputData's.
     */
    inline bool operator==(const OutputData& od) const{
        return id == od.id;
    }

    /**
     * Compares the uid's contained in the OutputData's.
     */
    inline bool operator!=(const OutputData& od) const{
        return id != od.id;
    }
protected:
    /**
     * Notifies of an event specified by the given parameter - please note
     * that this parameter will be deleted soon after this call - so don't
     * hold a pointer to the odf_parameter after this call! The notification
     * is done by calling all registered functors.
     *
     * @param odf_parameter The parameter that will be given to the functor -
     * it will be deleted after the call!!!
     *
     * @todo: think about deleting odf_parameter (if odf just puts it in a
     * queue - segfault!)
     */
    void notify(OutputDataFunctorParameter* odf_parameter, event_priority priority = prio_normal);

    /**
     * The name of the output data.
     */
    const std::string name;

    /**
     * The description of the output data.
     */
    const std::string description;

    /**
     * The uid of the output data.
     */
    const uid id;

    /**
     * The type of the derived OutputData determining the OutputModules that
     * will display the OutputData.
     */
    const std::string type;    

    /**
     * The uid of the application to which the output data belongs
     */
    const uid& application_id;

private:

    /**
     * A pointer to the event_dispatcher which is needed for
     * delivering the events wrapping the functors.
     */
    EventDispatcher* event_dispatcher;
    
    /**
     * To count how many events are send to the dispatcher for each functor
     * and are not yet dispatched - needed to wait when deregistering the
     * functor.
     */
    std::map<OutputDataFunctor*, AtomicCounter<uint32_t> > functor_to_counter;
    
    /**
     * The list of all registered functors that will be called if notify is
     * invoked.
     */
    std::list<OutputDataFunctor*> registered_functors;
};

} // namespace output
} // namespace iwear

#endif // __OUTPUTDATA_H

