/****************************************************************************/
/* Copyright (c) 2000 MBARI                                                 */
/* MBARI Proprietary Information. All rights reserved.                      */
/****************************************************************************/
/* Summary  :                                                               */
/* Filename : Behavior.h                                                    */
/* Author   :                                                               */
/* Project  :                                                               */
/* Version  : 1.0                                                           */
/* Created  : 02/07/2000                                                    */
/* Modified :                                                               */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/****************************************************************************/
#ifndef _BEHAVIOR_H
#define _BEHAVIOR_H

#include "DynamicArray.h"
#include "DynamicControlIF.h"
#include "MissionClock.h"
#include "Attributes.h"
#include "NavigationIF.h"

class LayeredControl;

/*
CLASS 
Behavior

DESCRIPTION
Defines a "behavior" for LayeredControl. Behavior contains
an Attributes object, and the constructor for a Behavior should
define individual attributes (as described in the Attributes header file).
Attributes::parse() and Attributes::verify() 
must be called after the constructor, before the first call to
Behavior::execute().

The static setEnvironment() method is called any Behavior objects have
been executed. setEnvironment() gets references
to LayeredControl objects such as NavigationIF and MissionClock. This
approach allows Behavior objects to be constructed (but not executed)
in the absence of the LayeredControl environment; this is useful for
simply checking mission script syntax.

Note: The destructor of a Behavior subclass should be declared 'virtual'.

Note: When implementing a new Behavior subclass, you must also modify 
BehaviorFactory::create().

Note: When implementing a new Behavior subclass, you must also modify 
bdoc.cc

AUTHOR
Tom O'Reilly
*/
class Behavior {

public:

  ///////////////////////////////////////////////////////////////////
  // Behavior State enumeration. Each Behavior object has 
  // an associated State.
  enum State {

    // Behavior object is ready to execute
    Active = 0, 

    // Wait, don't execute Behavior object yet 
    Suspended, 

    // All done; don't execute this Behavior object again
    Finished
  };


  ///////////////////////////////////////////////////////////////////
  // Constructor
  Behavior(const char *name, Boolean sequential);
     
  virtual ~Behavior();
     
  ///////////////////////////////////////////////////////////////////
  // Reset components of output command
  void resetOutput();
     
  ///////////////////////////////////////////////////////////////////
  // Get output command
  void output(DynamicControlIF::Command *cmd);

  ///////////////////////////////////////////////////////////////////
  // Initialize command parameters
  void input(DynamicControlIF::Command *cmd);    

  ///////////////////////////////////////////////////////////////////
  // Return True if all input attribute values are valid and 
  // self-consistent; else return False.
  virtual Boolean validInput() = 0;
     
  ///////////////////////////////////////////////////////////////////
  virtual void resolve();

  ///////////////////////////////////////////////////////////////////
  // Set state
  void setState(State state) {
    _state = state;
  }
     
  ///////////////////////////////////////////////////////////////////
  // Current state 
  State state() {
    return _state;
  }
	  
  ///////////////////////////////////////////////////////////////////
  // Print out mnemonic for current Behavior state
  static const char *stateMnem( State );
  const char *stateMnem();
     
  ///////////////////////////////////////////////////////////////////
  // Start time
  double startTime() {
    return _startTime;
  }
     
  ///////////////////////////////////////////////////////////////////
  // End time
  double endTime() {
    return _endTime;
  }
     
  ///////////////////////////////////////////////////////////////////
  // Duration
  double duration() {
    return _duration;
  }

  ///////////////////////////////////////////////////////////////////
  // Name
  const char *name() {
    return _name;
  }
     
  ///////////////////////////////////////////////////////////////////
  // Indicate if Behavior is "sequential". Only 1 sequential Behavior
  // can execute at a given time
  Boolean sequential() {
    return _sequential;
  }
     
  ///////////////////////////////////////////////////////////////////
  // Issued a mission-abort request?
  Boolean abortRequested() {
    return _abortMission;
  }

  ///////////////////////////////////////////////////////////////////
  // Behavior Attributes
  Attributes attributes;

  int verifyBaseAttributes();
  virtual int verify();
     
  static const Boolean Sequential;
  static const Boolean NonSequential;
     
  ///////////////////////////////////////////////////////////////////
  // Get any needed object references from LayeredControl. 
  // Behavior::setEnvironment() gets references to LayeredControl's
  // NavigationIF and MissionClock objects.
  // This method is called by LayeredControl before any Behaviors are
  // executed. We use this approach so that Behavior objects may
  // be created (but not executed) without the presence of 
  // LayeredControl (e.g. for checking syntax of mission scripts).
  static void setEnvironment(LayeredControl *layeredControl);

protected:

  ///////////////////////////////////////////////////////////////////
  // Should the behavior start now?
  virtual Boolean shouldBehaviorStart( void );

  ///////////////////////////////////////////////////////////////////
  // Do the behavior, i.e. generate command for input to DynamicControl.
  // At the time execute() is called, all components of the
  // command have been reset. So execute() only needs to set the 
  // relevant output components.
  virtual void execute();

     
  void printError(const char *msg);
     
  // When behavior starts
  double _startTime;		
     
  // When behavior ends
  double _endTime;		

  // How long the behavior should run
  double _duration;
     
  ///////////////////////////////////////////////////////////////////
  // Request to abort mission
  void abortMission();

  ///////////////////////////////////////////////////////////////////
  // Set vertical command
  void setVertical(DynamicControlIF::VerticalMode mode, double vertical);
     
  ///////////////////////////////////////////////////////////////////
  // Set horizontal command
  void setHorizontal(DynamicControlIF::HorizontalMode mode, 
		     double horizontal);
     
  ///////////////////////////////////////////////////////////////////
  // Set horizontal command, Waypoint mode
  void setHorizontal(DynamicControlIF::HorizontalMode mode, 
		     double horizontal,
		     double north, 
		     double east);

  ///////////////////////////////////////////////////////////////////
  // Set speed command
  void setSpeed(DynamicControlIF::SpeedMode mode, double speed);

  ///////////////////////////////////////////////////////////////////
  //
  DynamicControlIF::VerticalMode getVerticalMode( void ) 
    { return _output.verticalMode; };

  double getVertical( void )
    { return _output.vertical; };
     
  ///////////////////////////////////////////////////////////////////
  // 
  static Boolean isOutputEmpty( DynamicControlIF::Command * );
  static Boolean isVerticalEmpty( DynamicControlIF::Command *cmd );
  static Boolean isHorizontalEmpty( DynamicControlIF::Command *cmd );
  static Boolean isSpeedEmpty( DynamicControlIF::Command *cmd );


  Boolean isOutputEmpty( void )
    { return isOutputEmpty( &_output ); };

  Boolean isVerticalEmpty( void )
    { return isVerticalEmpty( &_output ); };

  Boolean isHorizontalEmpty( void )
    { return isHorizontalEmpty( &_output ); };

  Boolean isSpeedEmpty( void )
    { return isSpeedEmpty( &_output ); };

  Boolean horizontalSequence()
    { return isHorizontalEmpty(); };

  Boolean verticalSequence()
    { return isVerticalEmpty(); };

  Boolean bothSequence()
    { return (isHorizontalEmpty() && isVerticalEmpty()); };

  // All Behaviors access the same mission clock
  static MissionClock *_missionClock;

  // All Behaviors reference the same NavigationIF
  static NavigationIF *_navigation;

private:
     
  char *_name;
     
  State _state;  
     
  // True if this behavior run sequentially with others
  Boolean _sequential;
     
  Boolean _abortMission;
     
  // Keep this Command object private; access methods force behaviors
  // to set mode and value simultaneously.
  DynamicControlIF::Command _output;
};


typedef DynamicArray<Behavior *> BehaviorStack;

#endif
