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

#include "SharedObjectServer.h"

class TaskInterface;

/*
CLASS 
TaskServer

DESCRIPTION
Fills requests generated by TaskInterface object, including 
subscription requests. Provides event notification to subscribers.
Can spawn and cooperate with "auxillary" Task processes.
Forwards events triggered in auxillary Task to subscribers.

AUTHOR
Tom O'Reilly
*/
class TaskServer : public SharedObjectServer {

  friend class EventTriggers;
  friend class EventService;

public:

  TaskServer(const char *name);

  virtual ~TaskServer();

  ////////////////////////////////////////////////////////////////////
  // Spawn auxillary tasks, then call SharedObjectServer::run()
  virtual void run();

protected:

  ///////////////////////////////////////////////////////////////////
  // Prototype for event callback methods
  typedef void (TaskServer::*EventCallback)(TaskInterface *client, 
					    EventCode eventCode);

  ///////////////////////////////////////////////////////////////////
  // Subscribe to specified event on specified TaskInterface, and
  // "register" callback to be invoked when event occurs.
  void subscribe(TaskInterface *client, 
		 EventCode eventCode, 
		 EventCallback callback);


  ////////////////////////////////////////////////////////////////////
  // Create and trigger an event to subscribers
  void triggerEvent(EventCode eventCode);

  ////////////////////////////////////////////////////////////////////
  // Maximum bytes in any request
  virtual size_t maxRequestBytes();

  ////////////////////////////////////////////////////////////////////
  // Spawn any auxillary tasks. Return 0 on success, -1 on error
  virtual int spawnAuxTasks() = 0;


  ////////////////////////////////////////////////////////////////////
  // An Event is passed between processes.
  struct Event : Request {

    int marker;

    int eventCode;
    pid_t serverPid;
    Boolean forward;

    Event() {
      // Fill in this code, so clients know they are actually
      // receiving an Event, rather than some other message.
      code = NotifyCode;
      marker = EventMarkerCode;
    }
  };


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


  ////////////////////////////////////////////////////////////////////
  // Points to most recently created TaskServer 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 TaskServer *_theTaskServer;


private:

  ////////////////////////////////////////////////////////////////////
  // Event is one that this TaskServer subscribed to (through a contained
  // TaskInterface). Invoke the corresponding callback method.
  void invokeEventCallback(Event *event);

  ////////////////////////////////////////////////////////////////////
  // Process subscription request from client
  Boolean addSubscriber(Request *request, int nRequestBytes, 
			Reply **reply, int *nReplyBytes);


  ////////////////////////////////////////////////////////////////////
  // Add subscriber; return True if successful, else return False
  Boolean registerSubscriber(EventCode eventCode, pid_t subscriber);


  ////////////////////////////////////////////////////////////////////
  // This method handles "events" generated by another process. The
  // event might be generated from an "auxillary" task, and should be 
  // forwarded to subscribers, or could be an event from a TaskInterface
  // that this TaskServer has subscribed to.
  Boolean handleEvent(Request *request, int nRequestBytes, 
		      Reply **reply, int *nReplyBytes);

  ////////////////////////////////////////////////////////////////////
  // Forward event to subscribers
  void forwardEvent(Event *event);

  // Forwarded event and corresponding subscriber
  struct FwdEventTableEntry {
    EventCode eventCode;
    DynamicArray<pid_t>subscriber;
  };

  // Forwarded events and corresponding subscribers
  DynamicArray<FwdEventTableEntry *> _fwdEventTable;


  // Event to which server has subscribed, through contained
  // TaskInterface object
  struct EventTableEntry {

    EventTableEntry(TaskInterface *client, 
		    EventCode eventCode,
		    EventCallback callback) {
      _client = client;
      _eventCode = eventCode;
      _callback = callback;
    }

    TaskInterface *_client;
    EventCode _eventCode;
    EventCallback _callback;
  };

  // Events to which server has subscribed, through contained TaskInterface
  // objects
  DynamicArray<EventTableEntry *> _eventTable;


  SubscriptionReply _subscriptionReply;

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


};


#endif
