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

#ifndef MISSIONITEM_H_
#define MISSIONITEM_H_

#include "component/ComponentRegistry.h"
#include "component/Behavior.h"
#include "data/Double.h"
#include "data/Location.h"
#include "logger/Logger.h"

class Aggregate;
class Component;
class DefineBehavior;
class MissionNode;
class Trigger;
class ValueClause;

/** \ingroup missionScript
 *
 *  Wraps a Behavior or Aggregate
 *  with mission-specific settings pertaining to that item
 */
class MissionItem
{
public:

    /// Destructor
    virtual ~MissionItem();

    /// Returns an instance, or NULL if an instance can't be returned
    static MissionItem* Instance( MissionItem* parent, MissionNode* node,
                                  unsigned int tablePos, Logger& logger );

    /// Returns the component as a Aggregate
    Aggregate* getAggregate() const
    {
        return aggregate_ ? ( Aggregate* )component_ : NULL;
    }

    /// Returns the mission component
    Behavior* getComponent() const
    {
        return component_;
    }

    /// Sets the mission component
    void setComponent( Behavior* component )
    {
        component_ = component;
    }

    /// Indicates if the item runs in parallel
    bool isParallel()
    {
        return parallel_;
    }

    /// Tell the item to run in parallel
    void setParallel( bool parallel )
    {
        parallel_ = parallel;
    }

    /// Indicates if the item runs in sequence
    bool isSequence()
    {
        return sequence_;
    }

    /// Tell the item to run in sequence
    void setSequence( bool sequence )
    {
        sequence_ = sequence;
    }

    /// Indicates if the mission component is an aggreate behavior
    bool isAggregate() const
    {
        return aggregate_;
    }

    /// Indicates if the mission component is a command
    bool isCompletable()
    {
        return ( isSequence() || ( isAggregate() && !isParallel() ) );
    }

    /// Returns the position within the Aggregate
    unsigned int getTablePosition()
    {
        return tablePos_;
    }

    // returns Boolean BREAK clause
    ValueClause* getBreakClause()
    {
        return breakClause_;
    }

    // returns Boolean WHEN clause
    ValueClause* getWhenClause()
    {
        return whenClause_;
    }

    // returns Boolean WHEN clause
    ValueClause* getWhileClause()
    {
        return whileClause_;
    }

    // returns Boolean PREEMPTIVE clause
    ValueClause* getPreemptiveClause()
    {
        return preemptiveClause_;
    }

    // indicates if the clause is preemptive
    bool isPreemptive();

    /// resets the repeat index
    void setRepeatIndex( int repeatIndex );

    /// returns the repeat index
    int getRepeatIndex()
    {
        return repeatIndex_;
    }

    /// returns the repeat limit
    int getRepeatLimit()
    {
        return repeatLimit_;
    }

    unsigned int getTablePos()
    {
        return tablePos_;
    }

    // Returns true if the item's missionState is BEHAVIOR_ACTIVE,
    // Or is equal to the indicated activeItem,
    // Or has a whenClause or whileClause true,
    // But not an breakClause true!
    bool isActive( MissionItem* activeItem );

    void initialize();

    void run();

    bool runIfUnsatisfied();

    bool satisfied();

    /// Called when the mission component becomes preempted.
    void preempted();

    void uninitialize( /*PCaller& pCaller*/ );

    /// True if this is timed out.
    bool isTimedOut()
    {
        return timedOut_;
    }

    bool isInitialized()
    {
        return initialized_;
    }

    const Timestamp& getStartTime() const
    {
        return startTime_;
    }

    /// Parent MissionItem
    MissionItem* getParent() const
    {
        return parentItem_;
    }

    void addCall();

    void removeCall();

    DataReader* findArgReader( const Str& argName ) const;

protected:
    /// Protected Constructor
    MissionItem( MissionItem* parent, unsigned int tablePos );

    // Initializer
    void initializeFromScript( MissionNode* node, Logger& logger );

    // Interpret Repeat attribute
    void interpretRepeat( MissionNode* node, const Str& name, Logger& logger );

    // Interpret RunIn elements
    void interpretRunIn( MissionNode* node, const Str& name, Logger& logger );

    MissionItem* findItemByRefId( const Str& refId ) const;

    void putDefineBehavior( const Str& name, DefineBehavior* defineBehavior );

    DefineBehavior* findDefineBehavior( const Str& name ) const;

    /// Parent MissionItem
    MissionItem* parentItem_;

    /// Position within the Aggregate
    unsigned int tablePos_;

    /// Single item
    Behavior* component_;

    /// Indicates if missionComponent should be run sequentially
    bool sequence_;

    /// Indicates if missionComponent should be run all the time
    bool parallel_;

    /// Aggregate item?
    bool aggregate_;

    /// Boolean BREAK clause
    ValueClause* breakClause_;

    /// Boolean WHEN clauses
    ValueClause* whenClause_;

    /// Boolean WHILE clause
    ValueClause* whileClause_;

    /// Indicates that the clause is preemptive
    ValueClause* preemptiveClause_;

    /// Number of calls to this item.
    int callCount_;

    /// Number of Times repeated so far
    int repeatIndex_;

    /// Number of Times to repeat this item
    int repeatLimit_;

    /// Reads timeout argument at timeout init time
    DataReader* repeatArgReader_;

    /// Keeps track of how long we've been running
    Timestamp startTime_;

    /// True if time since startTime exceed timeout
    bool timedOut_;

    /// Reads timeout argument at timeout init time
    DataReader* timeoutArgReader_;

    /// Aggregate commands to execute in the case of a timeout.  Can be empty.
    MissionItem* timeoutItem_;

    /// Map of DefineBehavior instances
    FastMap<const Str, DefineBehavior*>* defineBehaviors_;

    /// True if the item is currently preempted.
    bool preempted_;

    /// Flag used by parent aggregates
    bool initialized_;

    /// Used only while reading mission from XML.  Do not use later!
    MissionNode* node_;

    /// If true, this is a called item, so the when clause is ignored.
    bool ignoreWhenWhile_;

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

    void setCompleted();

    void setTimedOut();

};



#endif /*MISSIONITEM_H_*/
