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

#include "SharedObjectServer.h"

#define MAXPROCS 4
#define PROCLEN 32
#define ARGLEN 16

class TaskInterface;

/*
CLASS
TaskServer

DESCRIPTION
Fills requests from TaskInterface objects, 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);
  TaskServer(const char *name, int priority = 0, int sched_policy = 0);

  virtual ~TaskServer();

  ////////////////////////////////////////////////////////////////////
  // call SharedObjectServer::run()
  virtual void run();

  ////////////////////////////////////////////////////////////////////
  // Returns a description of an IDL call, or zero if none exists.
  //  Only needed for the IDL servers which inherit from TaskServer.
  virtual const char* getSerializedInterfaceDescription(int iMethod);

protected:

  char _procs[MAXPROCS][PROCLEN];
  char _args[MAXPROCS][ARGLEN];
  int _numProcs;
  int _pids[MAXPROCS];

  ///////////////////////////////////////////////////////////////////
  // 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();

  struct Event : Request {
    int marker;
    int eventCode;
    pid_t serverPid;
    nid_t node;
    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;
    }
  };

  ////////////////////////////////////////////////////////////////////
  // 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;

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

private:

  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, Boolean otherNode = False);


  ////////////////////////////////////////////////////////////////////
  // Process event
  Boolean handleEvent(Request *request, int nRequestBytes,
		      Reply **reply, int *nReplyBytes);

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

  struct FwdEventTableSubscriber {
	  pid_t pid;
	  Boolean otherNode;
  };

  // Forwarded event and corresponding subscriber
  struct FwdEventTableEntry {
    EventCode eventCode;
    DynamicArray<FwdEventTableSubscriber> 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;
      _localProxyPid = -1;
      _remoteProxyPid = -1;
    }

    EventTableEntry(TaskInterface *client,
		    EventCode eventCode,
		    EventCallback callback,
		    pid_t localProxyPid,
		    pid_t remoteProxyPid) {
      _client = client;
      _eventCode = eventCode;
      _callback = callback;
      _localProxyPid = localProxyPid;
      _remoteProxyPid = remoteProxyPid;
    }

    TaskInterface *_client;
    EventCode _eventCode;
    EventCallback _callback;
    pid_t _localProxyPid, _remoteProxyPid;
  };

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


  SubscriptionReply _subscriptionReply;


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

  char * _theTaskServerName;


};


#endif
