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

#include <time.h>
#include "DynamicArray.h"
#include "PeriodicTask.h"
#include "TaskInterface.h"


/*
CLASS 
Supervisor

DESCRIPTION

Supervisor has the following responsibilities:

* Create Task processes, based on current vehicle configuration
* Monitor Tasks, restart aborted Tasks
* Periodically reset watchdog timer

AUTHOR
Tom O'Reilly
*/
class Supervisor {

public:

  ///////////////////////////////////////////////////////////////////
  // Constructor
  Supervisor(int argc, char **argv);

  ~Supervisor();

  void run();

protected:

  ///////////////////////////////////////////////////////////////////
  // Create "core" vehicle tasks
  void createCoreTasks();

  ///////////////////////////////////////////////////////////////////
  // Create simulation tasks
  void createSimTasks();

  ///////////////////////////////////////////////////////////////////
  // Create "real" vehicle tasks (drivers, etc), as specified in 
  // config file
  void createRealTasks();

  ///////////////////////////////////////////////////////////////////
  // Create tasks as specified in config file
  void createTasks(const char *configFileName);

  ///////////////////////////////////////////////////////////////////
  // Check status of all tasks. Re-start any that have died.
  // Return number of tasks that have died.
  int checkTasks(Boolean restart);

  ///////////////////////////////////////////////////////////////////
  // Let hardware watchdog know that we're still alive
  void keepAlive();

  ///////////////////////////////////////////////////////////////////
  // Shutdown all tasks
  void shutdown(int exitCode);

  ///////////////////////////////////////////////////////////////////
  // Fork and execute task; add to task table
  // [input] taskName: name of task
  // [input] args: pointer to argument string (concatenation of argv[1] 
  //               through argv[argc-1]
  // [input] restarted: False on first time task is started, else True
  int createTask(const char *taskName, const char *args, 
		 Boolean restarted);

  ///////////////////////////////////////////////////////////////////
  // Add task entry to table
  void addTaskEntry(const char *taskName, pid_t pid, const char *argv);


  ///////////////////////////////////////////////////////////////////
  // Shutdown and exit()
  void exit(int exitCode);

  ///////////////////////////////////////////////////////////////////
  // Create subdirectory for log files. Redirect stderr to 'tee',
  // so that syslog stderr output is logged to a file in the log 
  // directory.
  void createLogDir();

  struct TaskEntry {

    TaskEntry(pid_t pid, TaskInterface *interface, const char *args) {
      _pid = pid;
      _interface = interface;
      _args = strdup(args);
    }

    pid_t _pid;
    TaskInterface *_interface;
    const char *_args;
  };

  DynamicArray<TaskEntry *>_tasks;

  Boolean _simulated;
  Boolean _realTailCone;

  // Configuration file names
  char *_planFileName;
  char *_abortFileName;
  char *_deviceFileName;
  char *_terminateFileName;

  Boolean _running;

  // Time at which supervisor was started
  time_t _startTime;

  // Termination programs are run at shutdown only if run time has
  // exceeded _minRunTime
  int _minRunTime;

  int parseOptions(int argc, char **argv);

private:

  ////////////////////////////////////////////////////////////////////
  // Signal handler
  static void signalHandler(int signalNo);

  ////////////////////////////////////////////////////////////////////
  // Destroy latest TaskServer object
  static void cleanup();

  // Points to most recently created Supervisor object. There should only
  // be one of these per process. We use this approach instead of
  // Singleton, since Singleton requires more code fiddling as new
  // subclasses are added.
  static Supervisor *_theSupervisor;
};


#endif
