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

#ifndef BEHAVIOR_H_
#define BEHAVIOR_H_

#include "LcmMessagingComponent.h"
#include "utils/FastMap.h"
#include "missionScript/SettingReader.h"

class ValueClause;

/** \ingroup component
 *
 *  Behavior is the abstract base class for
 *  components that implement mission behaviors and
 *  commands.
 *
 *  Typically, such components will define at least one "setting" related
 *  InputReader (obtained via Slate::NewInputReader), will read in
 *  some measured quantities with a UniversalReader
 *  (obtained via Slate::NewUniversalReader), and will send outputs
 *  to one or more of the control components (VerticalControl,
 *  SpeedControl, HeadingControl) with a Writer
 *  (obtained via Slate::newWriter).
 */
class Behavior : public LcmMessagingComponent
{
public:

    enum BehaviorState
    {
        BEHAVIOR_INACTIVE,
        BEHAVIOR_CALLED,
        BEHAVIOR_ACTIVE,
        BEHAVIOR_TIMEOUT,
        BEHAVIOR_COMPLETED,
    };

    virtual ~Behavior();
    bool executeIfUnsatisfied();
    virtual bool runIfUnsatisfied();

    virtual void preempted()
    {}

    ;
    virtual bool isSatisfied()
    {
        return false;
    }

    virtual bool isRunnable()
    {
        return runnable_;
    }

    virtual bool isSatisfiable()
    {
        return satisfiable_;
    }

    virtual bool isCommand()
    {
        return runnable_ && satisfiable_;
    }

    BehaviorState getBehaviorState() const
    {
        return behaviorState_;
    }

    void setBehaviorState( BehaviorState behaviorState )
    {
        this->behaviorState_ = behaviorState;
    }

    /// Query if this component is completed
    virtual bool isCompleted( void )
    {
        return behaviorState_ == BEHAVIOR_COMPLETED;
    }

    SettingReader* findSettingReader( const Str& settingURI );

    SettingReader* addValueClause( const Str& uriPart, ValueClause* valueClause );

    void addArgWriter( const Str& uriPart, DataWriter* argWriter );

    const Timespan& getTimeout()
    {
        return timeout_;
    }

    void setTimeout( const Timespan& timeout )
    {
        timeout_ = timeout;
    }

protected:
    Behavior( const Str & name, const Module *module, const bool runnable, const bool satisfiable );

    Behavior( const Str& name, const Module* module, const bool runnable, const bool satisfiable, const DataURI& enableBroadcast );

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

    SettingReader* newSettingReader( const Str& uriPart, const DataValue* defaultValue, bool deleteDefaultValue = true ); // __attribute__( ( deprecated ) ); // ("Use Behavior::newSettingReader with SettingURI arg instead.") ));

    SettingReader* newSettingReader( const SettingURI& uriPart );

    bool runnable_;
    bool satisfiable_;
    BehaviorState behaviorState_;

    /// Time before this behavior must end -- defaults no timeout
    Timespan timeout_;

    DataWriter* findArgWriter( const OutputURI& uriPart );

    FastMap<const Str, SettingReader*>* settingReaderMap_;
    FastMap<const Str, DataWriter*>* argWriterMap_;

};

/// Behavor factory interfaces

/// create_behavor must be implemented, following the
/// class implementation:
/// static Behavior* CreateBehavor( const Str& prefix, const Module* module ) {
///     return new MyBehavor( prefix, module );
/// }
typedef Behavior*( *BehaviorCreator )( const Str&, const Module* module );


#endif /*BEHAVIOR_H_*/
