/****************************************************************************/
/* Copyright (c) 2000 MBARI                                                 */
/* MBARI Proprietary Information. All rights reserved.                      */
/****************************************************************************/
/* Summary  :                                                               */
/* Filename : Task.cc                                                       */
/* Author   :                                                               */
/* Project  :                                                               */
/* Version  : 1.0                                                           */
/* Created  : 02/07/2000                                                    */
/* Modified :                                                               */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/****************************************************************************/
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/kernel.h>
#include <malloc.h>
#include <process.h>
#include <signal.h>
#include "Task.h"
#include "Syslog.h"

#define ServerProgramName "taskServer"

Task *Task::_theTask = 0;

Task::Task(const char *name)
{
  Boolean debug = False;
  char errorBuf[100];

  if (_theTask != 0) {
    // Oops, we've already created a Task! Only 1 allowed per process
    sprintf(errorBuf, "Task::Task() - instance (\"%s\") already exists!",
	    _theTask->name());

    throw Exception(errorBuf);
  }

  // Keep track of the most recently created Task for cleanup on signal/exit
  _theTask = this;

  _name = strdup(name);

  _eventTriggers = 0;

  _mode = Nominal;
  _cmdPtr = 0;
  _maxCmdBytes = 0;

  dprintf("Task::Task() \"%s\" - _theTask=0x%x\n", name, _theTask);

  signal(SIGINT, Task::signalHandler);
  signal(SIGTERM, Task::signalHandler);
  signal(SIGQUIT, Task::signalHandler);
  signal(SIGHUP, SIG_IGN);
  atexit(Task::cleanup);

  // We don't wait for children to die, and we don't
  // want any zombies either...
  //  signal(SIGCHLD, SIG_IGN);

  _eventTriggers = new EventTriggers(serverPid());
}


Task::~Task()
{
  Boolean debug = False;
  dprintf("Task::~Task() - delete _eventTriggers");
  delete _eventTriggers;
  dprintf("Task::~Task() - free(_name)");
  free((void *)_name);
  _theTask = 0;
  dprintf("Task::~Task() - done");
}



void Task::processCommand(Command *command)
{
  return;
}


size_t Task::maxCommandBytes()
{
  return 512;
}



void Task::allocateBuffers()
{
  _maxCmdBytes = maxCommandBytes();

  // Allocate request buffer
  if ((_cmdPtr = (Command *)malloc(_maxCmdBytes)) == 0) {

    Syslog::write("Task::init() - couldn't malloc %d bytes!\n",
		  _maxCmdBytes);
    
    exit(1);
  }
}



void Task::run()
{
  allocateBuffers();

  while (True) {
    Receive(serverPid(), (void *)_cmdPtr, _maxCmdBytes);
    processCommand(_cmdPtr);
  }
}


void Task::triggerEvent(EventCode eventCode)
{
  Boolean debug = False;
  dprintf("Task::triggerEvent() - _eventTriggers ptr = x%x\n", _eventTriggers);
  _eventTriggers->notify(eventCode);
}


void Task::addCallback(SharedObject::RequestCode code, CallbackPtr callback)
{
  CallbackEntry *entry = new CallbackEntry(code, callback);
  _callbacks.add(&entry);
}


const pid_t Task::serverPid()
{
  // Assume parent is server
  return getppid();
}



void Task::signalHandler(int signalNo)
{
  Boolean debug = False;
  dprintf("Task::signalHandler() for task %s - call cleanup()\n", 
	  _theTask->name());

  // Call exit(), which will invoke Task::cleanup()
  exit(1);
}

void Task::nullSignalHandler(int signalNo)
{
  Boolean debug = True;
  dprintf("Task::nullSignalHandler() for task %s - someone got HUP'd\n", 
	  _theTask->name());
}


void Task::cleanup()
{
  Boolean debug = False;

  if (!_theTask) 
    // Doesn't exist
    return;

  dprintf("Task::cleanup() - delete _theTask=0x%x (named %s)\n", 
	  _theTask, _theTask->name());

  delete _theTask;

  dprintf("Task::cleanup() - done deleting _theTask=0x%x\n", 
	  _theTask);

  dprintf("Task::cleanup() - done\n");
  return;
}


void Task::publish(EventCode event)
{
  triggerEvent(event);
}
