//=========================================================================
// Summary  : */
// Filename : SharedObjectServer.cc
// Author   : */
// Project  : */
// Revision : 1
// Created  : 2000/08/19
// Modified : 2000/08/19
//=========================================================================
// Description :
//=========================================================================
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/name.h>
#include <sys/kernel.h>
#include <sys/psinfo.h>
#include "SharedObjectServer.h"
#include "Syslog.h"
#include "VehicleConfigurator.h"

//#include "remote/ModemMessage.h"

SharedObjectServer::SharedObjectServer(const char *name)
  : SharedObject(name)
{
  pid_t pid;

  // Attach server name to its pid so clients can find us
  if ((_processNameId = qnx_name_attach(0, name)) == -1) {
       throw ServerExists(name);
  }

  // Register the PID with VCS
  VehicleConfigurator::setPID();
  VehicleConfigurator::setIFName( name );

  _clientPid = 0;
  _requestPtr = 0;

  char errorBuf[256];

  // Identify this as a server to QNX
  if (qnx_pflags(~0, _PPF_SERVER | _PPF_PRIORITY_REC | _PPF_PRIORITY_FLOAT,
		 0, 0) == -1) {
    sprintf(errorBuf, 
	    "SharedObjectServer::SharedObjectServer() - qnx_pflags(): %s",
	    strerror(errno));

    throw Exception(errorBuf);
  }
}


SharedObjectServer::~SharedObjectServer()
{
  Boolean debug = False;
  
  dprintf("SharedObjectServer::~SharedObjectServer()");

  if (_processNameId != -1) {
    qnx_name_detach(0, _processNameId);
    dprintf("SharedObjectServer::~SharedObjectServer() - detached name");
  }

  dprintf("SharedObjectServer::~SharedObjectServer() - free()...");
  free((void *)_requestPtr);
  dprintf("SharedObjectServer::~SharedObjectServer() - done");
}


void SharedObjectServer::allocateBuffers()
{
  _maxReqBytes = maxRequestBytes();

  // Allocate request buffer
  if ((_requestPtr = (Request *)malloc(_maxReqBytes)) == 0) {

    fprintf(stderr, 
	    "SharedObjectServer::allocateBufffers() - "
	    "couldn't malloc %d bytes!\n",
	    _maxReqBytes);
    
    exit(1);
  }
}


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

  Boolean debug = False;

  int nReplyBytes;
  Reply *replyPtr;

  // Launch callbacks (note this is pure virtual, and should actually
  // call the most-inherited function
  init();

  while (True) {

    // Wait for client request
    _clientPid = Receive(AnyPid, (void *)_requestPtr, _maxReqBytes);

    dprintf("SharedObjectServer::run() - received message, code %d\n",
	    _requestPtr->code);

    // Call appropriate method
    if (processRequest(_requestPtr, _maxReqBytes, &replyPtr, &nReplyBytes)) {
      // Reply to client
      dprintf("SharedObjectServer::run() - Reply to client %d with %d bytes\n",
	      _clientPid, nReplyBytes);

      Reply(_clientPid, (void *)replyPtr, nReplyBytes);
      dprintf("SharedObjectServer::run() - done with Reply()\n");
    }
  }
}


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


Boolean SharedObjectServer::processRequest(Request *request, int nRequestBytes,
					   Reply **reply, int *nReplyBytes)
{
     Boolean debug = False;

  CallbackEntry *entry;

  // Search for method that matches request code
  for (int i = 0; i < _callbacks.size(); i++) {
    _callbacks.get(i, &entry);

    dprintf("SharedObjectServer::processRequest -- Checking for code %d = %d",
	    request->code, entry->_code );

    if (entry->_code == request->code) {
      // Found callback for this Request code
      return callMemberFunction(this, entry->_callback)(request, nRequestBytes,
							reply, nReplyBytes);
    }
  }

  // Couldn't find matching code (throw an exception here???)
  Syslog::write( "SharedObjectServer::processRequest() \'%s\' - "
		 "couldn't find callback for code %d\n", name(), request->code  );

  return False;
}


size_t SharedObjectServer::maxRequestBytes() 
{
  return 512;
}


pid_t SharedObjectServer::clientPid()
{
  return _clientPid;
}



const char *SharedObjectServer::clientName()
{
  qnx_psinfo(PROC_PID, _clientPid, &_psInfo, 0, 0);

  char *ptr;
  // Look only at last name in program path
  if ((ptr = strrchr(_psInfo.un.proc.name, '/')) == 0)
    ptr = _psInfo.un.proc.name;
  else
    // Skip past '/'
    ptr++;

  return ptr;
}

