//=========================================================================
// Summary  : */
// Filename : Task.h
// Author   : */
// Project  : */
// Revision : 1
// Created  : 2000/08/19
// Modified : 2000/08/19
//=========================================================================
// Description :
//=========================================================================
#ifndef _TASK_H
#define _TASK_H

#include <stdio.h>
#include "EventTriggers.h"
#include "SharedObject.h"
#include "DynamicArray.h"
#include "Exception.h"

#define RestartMnem "-restart"


/*
CLASS 
Task

DESCRIPTION
System component functionality is implemented as a Task. Other processes
can interact with a Task through the TaskInterface and TaskServer
classes. A Task can define "events", and triggers them when they occur; 
the associated TaskServer then distributes the event to subscribers.

AUTHOR
Tom O'Reilly
*/
class Task {

  friend class PeriodicTask;

public:

  typedef int CommandCode;

  class Error : public Exception {
  public:
    Error(char *errorMsg) : Exception(errorMsg) {
    }
  };

  ///////////////////////////////////////////////////////////////////
  // Constructor
  // [input] name: Task name
  Task(const char *name);
  Task(const char *name, int  priority, int sched_policy);

  ///////////////////////////////////////////////////////////////////
  // Destructor
  virtual ~Task();


  ///////////////////////////////////////////////////////////////////
  // Base class for Command structures passed to Task from TaskServer
  struct Command {
    CommandCode code;
  };

  enum TaskCommandCode {
    Shutdown = 1000 
  };


  enum Mode {
    Initializing, Nominal
  };

  ///////////////////////////////////////////////////////////////////
  // Task name
  const char *name() {
    return _name;
  }

  ///////////////////////////////////////////////////////////////////
  // Return current mode
  Mode mode() {
    return _mode;
  }


  ///////////////////////////////////////////////////////////////////
  // Run main processing loop
  virtual void run();



protected:


  ///////////////////////////////////////////////////////////////////
  // Process received command
  virtual void processCommand(Command *command);

  ///////////////////////////////////////////////////////////////////
  // Maximum bytes in a Command buffer
  virtual size_t maxCommandBytes();

  ///////////////////////////////////////////////////////////////////
  // Allocate command buffer; called by run() method
  void allocateBuffers();

  const char *_name;

  size_t _maxCmdBytes;
  Command *_cmdPtr;

  ///////////////////////////////////////////////////////////////////
  // PID of server process
  const pid_t serverPid();

  ///////////////////////////////////////////////////////////////////
  // Dispatch event to TaskServer, for distribution to clients
  void triggerEvent(EventCode event);

  typedef 
  void (Task::*CallbackPtr)(SharedObject::Request *request, int nRequestBytes,
			    SharedObject::Reply **reply, int *nReplyBytes);


  ////////////////////////////////////////////////////////////////////
  // Register a callback function for specified SharedObject::RequestCode.
  void addCallback(SharedObject::RequestCode code, CallbackPtr callback);

  EventTriggers *_eventTriggers;

private:

  pid_t _serverPid;

  Mode _mode;

  ////////////////////////////////////////////////////////////////////
  // We keep a list of CallbackEntry objects. Each CallbackEntry 
  // specifies the callback function associated with a given RequestCode.
  struct CallbackEntry
  {
    CallbackEntry(SharedObject::RequestCode code, CallbackPtr callback) {
      _code = code;
      _callback = callback;
    }
    
    SharedObject::RequestCode _code;
    CallbackPtr _callback;
  };

  ////////////////////////////////////////////////////////////////////
  // List of CallbackEntry objects
  DynamicArray <CallbackEntry *> _callbacks;

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

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


  ////////////////////////////////////////////////////////////////////
  // Points to most recently created Task 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 Task *_theTask;
};

#endif
