/** \file
 *
 *  Contains the Handler class declaration
 *
 *  Copyright (c) 2007,2008,2009 MBARI
 *  MBARI Proprietary Information.  All Rights Reserved
 */

#ifndef BLOCKHANDLER_H_
#define BLOCKHANDLER_H_

#include "component/Component.h"
#include "logger/Logger.h"

#ifdef __GAZEBO
#include "data/WorldStatHandler.h"

#include <gz/msgs/world_stats.pb.h>
#include <gz/transport/Node.hh>
#endif

class PCaller;

/**
 *  Base class for "handlers" of Components
 *
 *  Trying to make equivalence between Components which run within another
 *  thread (control, supervisor) and those that run in their own thread.
 *  ThreadHandler derives from this class.  Decided that ThreadHandler
 *  would "have a" Component rather than "be a" Component.
 *
 *  Basic non-threaded component handler.
 *
 *  Essentially a glorified while(1) loop.  Relies on the component to indicate
 *  when it's going to yield through Component::completed flag.
 *
 *  Should be moderately extensible through its virtual functions.  Run()
 *  does the following:
 *
 *  -# component.initialize()
 *  -# runOnce()
 *  -# component.run()
 *  -# check continueLoop(), if true continue, if false jump to end
 *  -# runBetween()
 *  -# component.run()
 *  -# check continueLoop()
 *  -# ...
 *  -# At end, component.uninitialize()
 *
 *  So runonce() can be used to initialize the Handler itself
 *  And runBetween() can be used to update the Handler, sleep, wait for
 *  a signal or condition variable, etc
 *
 *  \ingroup process
 */
class Handler
{
public:

    /// Constructor
    ///
    /// \param inComponent The component being handled.
    /// \param name Name of the component (fed to its logger_)
    /// \param idleThread If true, run thread at idle priority
    Handler( Component &inComponent, const Str& name, bool idleThread = false, bool controlThread = false );

    /// Destructor
    virtual ~Handler();

    /// Run the component itself
    virtual void run();

    /// Supplemental end conditions
    virtual bool continueLoop( void );

    /// Virtual function run only on first iteration of handler
    virtual void runOnce( void );

    /// Virtual function run after the first iteration of the handler
    virtual void runBetween( void );

    /// Stop the handler (and uninit the component)
    virtual void shutdown( void );

    /// True if handler is running
    virtual bool isRunning( void )
    {
        return running_;
    }

    const Str& getName()
    {
        return logger_.getFacility();
    }

    void setAsLogHandler( bool logHandler )
    {
        logHandler_ = logHandler;
    }

    void setAsControlLoopHandler( bool controlLoopHandler )
    {
        controlLoopHandler_ = controlLoopHandler;
    }

#ifdef __FASTSIM
    static void SetAllowFastSim( bool allowFastSim )
    {
        AllowFastSim_ = allowFastSim;
    }

    static bool IsFastSimAllowed()
    {
        return AllowFastSim_;
    }
#else
    static bool IsFastSimAllowed()
    {
        return false;
    }
#endif

protected:

    /// The "handled" Component
    Component &component_;

    /// Keep track of when the component is supposed to start next
    Timestamp componentStartTime_;

    /// Time of intialization. Real time. This will be a constant offset that sim
    /// time gets added to, because clock cannot be set to 0 to match sim time.
    Timestamp initTime_;

    Logger logger_;

    /// Used for making protected calls
    PCaller* pCaller_;

    bool running_;

    static const Timespan SMALL_INTERVAL;

private:

    // Note that the copy constructor below is private and not given a body.
    // Any attempt to call it will return a compiler error.
    Handler( const Handler& old ); // disallow copy constructor

    /// true at object initialization, false after the first iteration through the run() loop.
    bool firstLoop_;

    bool controlLoopHandler_;

    bool logHandler_;

#ifdef __FASTSIM
    static bool AllowFastSim_;

#ifdef __GAZEBO
    /// Transport node for message passing
    WorldStatHandler* worldStatHandler_;
#endif

#endif

    /// true is fast sim sleep case has been handeled, false otherwise
    bool fastSimSleepCase( void );

};

/// A type for a list of Handlers
typedef FlexArray<Handler *> ListOfHandlerPtrs;

#endif /*BLOCKHANDLER_H_*/
