/****************************************************************************/
/* Copyright (c) 2000 MBARI                                                 */
/* MBARI Proprietary Information. All rights reserved.                      */
/****************************************************************************/
/* Summary  :                                                               */
/* Filename : BuoyLauncherServer.cc                                         */
/* Author   :                                                               */
/* Project  :                                                               */
/* Version  : 1.0                                                           */
/* Created  : 02/07/2000                                                    */
/* Modified :                                                               */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/****************************************************************************/
#include <process.h>
#include <i86.h>
#include <Syslog.h>
#include "BuoyLauncherServer.h"
#include "BuoyLauncherMsgs.h"

BuoyLauncherServer::BuoyLauncherServer(SerialParameters *params)
  : BuoyLauncherIF_SK()
{
  _params = params;
  _input = new BuoyLauncherInput(SharedData::ReadWrite);
  _output = new BuoyLauncherOutput(SharedData::Read);
  _fatalLauncherError = False;
}


BuoyLauncherServer::~BuoyLauncherServer()
{
  delete _input;
  delete _output;
}

Boolean BuoyLauncherServer::ready()
{
  BuoyLauncherIF::LC_status lc;
  getLauncherStatus(&lc);

  _input->read();
  if (_input->data._command != CLEAR_CMD || _fatalLauncherError)
    return False;
  else
    return True;
}

DeviceIF::Status BuoyLauncherServer::nBuoys(short *total, short *launched)
{
  _output->read();

  *total = _output->data._totalNumBuoys;
  *launched = _output->data._numBuoysLaunched;
  return DeviceIF::Ok;
}

DeviceIF::Status BuoyLauncherServer::currentBuoy(short buoyNo)
{
  _input->read();
  if (ready() == False)
  {
    Syslog::write("BuoyLauncherServer::currentBuoy():Driver busy or dead");
    return DeviceIF::Offline; // device busy
  }

  _input->data._command = CURRENT_BUOY;
  _input->data._currentBuoy = buoyNo;
  _input->write();

  return DeviceIF::Ok;
}

DeviceIF::Status BuoyLauncherServer::uploadLog(short numMinutes)
{
  if (numMinutes < 0)
  {
    Syslog::write("BuoyLauncherServer::uploadLog() - Number of minutes "
                  "cannot be < 0 (%d)", numMinutes);
    return DeviceIF::Error;
  }

  _input->read();

  if (ready() == False)
  {
    Syslog::write("BuoyLauncherServer::uploadLog():Driver busy %c",
		  _input->data._command);
    return DeviceIF::Offline; // device busy
  }

  _input->data._command = UPLOAD_LC_LOG;
  _input->data._numMinutesToUpload = min(255, numMinutes);
  _input->write();

  return DeviceIF::Ok;
}

DeviceIF::Status BuoyLauncherServer::rotateBuoy()
{
  _input->read();

  if (ready() == False)
  {
    Syslog::write("BuoyLauncherServer::rotateBuoy():Driver busy %c",
		  _input->data._command);
    return DeviceIF::Offline; // device busy
  }

  _input->data._command = ROTATE_BUOY;
  _input->write();

  return DeviceIF::Ok;
}

DeviceIF::Status BuoyLauncherServer::rotateCarousel()
{
  _input->read();

  if (ready() == False)
  {
    Syslog::write("BuoyLauncherServer::rotate():Driver busy %c",
		  _input->data._command);
    return DeviceIF::Offline; // device busy
  }

 Syslog::write("BuoyLauncherServer::rotateCarousel sending B\n");
  _input->data._command = ROTATE_CARO;
  _input->write();

  return DeviceIF::Ok;
}

DeviceIF::Status BuoyLauncherServer::loadData(BuoyLauncherIF::Filename fname,
					      char type)
{
  _input->read();

  if (ready() == False)
  {
    Syslog::write("BuoyLauncherServer::loadData():Driver busy %c",
		  _input->data._command);
    return DeviceIF::Offline; // device busy
  }

  if (XFER_ARGOS == type)
    _input->data._command = XFER_ARGOS;
  else if (XFER_ARCHIVE == type)
    _input->data._command = XFER_ARCHIVE;
  else
    return DeviceIF::Error;

  strcpy(_input->data._dataFilename, fname);
  _input->write();

  return DeviceIF::Ok;
}

DeviceIF::Status BuoyLauncherServer::launch(char hot_or_cold)
{
  _input->read();

  if (ready() == False)
  {
    Syslog::write("BuoyLauncherServer::launch():Driver busy %c",
		  _input->data._command);
    return DeviceIF::Offline; // device busy
  }

  _output->data._armsRetracted = 
                  _output->data._lastLaunchDone = _output->data._inLaunchPosition = False;
  _output->write();

  Syslog::write("sending command to launcher\n");
  _input->data._command = hot_or_cold;
  _input->write();
  Syslog::write("BuoyLauncherServer::Sent %c launch command to driver",
                 hot_or_cold);
  return DeviceIF::Ok;
}

DeviceIF::Status BuoyLauncherServer::launchDummyBuoy()
{
  _input->read();

  if (ready() == False)
  {
    Syslog::write("BuoyLauncherServer::launchDummyBuoy():Driver busy on %c",
		  _input->data._command);
    return DeviceIF::Offline; // device busy
  }

  _output->data._lastLaunchDone = _output->data._inLaunchPosition = 0;
  _output->write();

  _input->data._command = LAUNCH_FAKE;
  _input->write();

  return DeviceIF::Ok;
}

DeviceIF::Status BuoyLauncherServer::rotateToLaunchPosition(Boolean realBuoy)
{
  _input->read();

  if (ready() == False)
  {
    Syslog::write("BuoyLauncherServer::rotateToLaunchPosition():Driver busy on %c",
		  _input->data._command);
    return DeviceIF::Offline; // device busy
  }

  _output->data._inLaunchPosition = 0;
  _output->write();

  if (realBuoy)
    _input->data._command = 'M';
  else
    _input->data._command = 'Z';

  _input->write();

  return DeviceIF::Ok;
}

DeviceIF::Status BuoyLauncherServer::ejectBuoy()
{
  _input->read();

  if (ready() == False)
  {
    Syslog::write("BuoyLauncherServer::ejectBuoy():Driver busy on %c",
		  _input->data._command);
    return DeviceIF::Offline; // device busy
  }

  _output->read();
  if (_output->data._inLaunchPosition)
  {
    _output->data._lastLaunchDone = 0;
    _output->write();

    _input->data._command = 'E';
    _input->write();
  }
  else
  {
    Syslog::write("BuoyLauncherServer::ejectBuoy():Buoy not in position!");
  }
  return DeviceIF::Ok;
}

DeviceIF::Status BuoyLauncherServer::reinitLauncher()
{
  _input->read();

  if (ready() == False)
  {
    Syslog::write("BuoyLauncherServer::reinitLauncher():Driver busy on %c",
		  _input->data._command);
    return DeviceIF::Offline; // device busy
  }

  _input->data._command = REINITIALIZE;
  _input->write();

  return DeviceIF::Ok;
}

DeviceIF::Status BuoyLauncherServer::retractArms()
{
  _input->read();

  if (ready() == False)
  {
    Syslog::write("BuoyLauncherServer::retractArms():Driver busy on %c",
		  _input->data._command);
    return DeviceIF::Offline; // device busy
  }

  _input->data._command = RETRACT_LARMS;
  _input->write();

  return DeviceIF::Ok;
}

DeviceIF::Status BuoyLauncherServer::pushAndRetract()
{
  _input->read();

  if (ready() == False)
  {
    Syslog::write("BuoyLauncherServer::pushAndRetract():Driver busy on %c",
		  _input->data._command);
    return DeviceIF::Offline; // device busy
  }

  _input->data._command = PUSH_OUT_RETRACT;
  _input->write();

  return DeviceIF::Ok;
}

DeviceIF::Status BuoyLauncherServer::rotateAPosition(char launch_or_data)
{
  _input->read();

  if (ready() == False)
  {
    Syslog::write("BuoyLauncherServer::rotateAPosition():Driver busy on %c",
		  _input->data._command);
    return DeviceIF::Offline; // device busy
  }

  if (launch_or_data != ROTATE_LAUNCH_POS && launch_or_data != ROTATE_DATA_POS)
  {
    Syslog::write("BuoyLauncherServer::rotateAPosition():illegal option %c",
		  launch_or_data);
    return DeviceIF::Error; 
  }

  _input->data._command = launch_or_data;
  _input->write();

  return DeviceIF::Ok;
}

DeviceIF::Status BuoyLauncherServer::statusOn(Boolean on)
{
  return DeviceIF::Ok;

  _input->read();

  if (ready() == False)
  {
    Syslog::write("BuoyLauncherServer::statusOn():Driver busy %c",
		  _input->data._command);
    return DeviceIF::Offline; // device busy
  }

  if (on)
  {
    Syslog::write("BuoyLauncherServer::calling statusOn(TRUE)");
    _input->data._command = STATUS_ON;
  }
  else
  {
    Syslog::write("BuoyLauncherServer::calling statusOn(FALSE)");
    _input->data._command = STATUS_OFF;
  }

  _input->write();

  return DeviceIF::Ok;
}

DeviceIF::Status BuoyLauncherServer::launched(Boolean *launched)
{
  _output->read();
  *launched = (_output->data._armsRetracted != 0);

  return DeviceIF::Ok;
}

DeviceIF::Status BuoyLauncherServer::getLauncherStatus(BuoyLauncherIF::LC_status *status)
{
/* For now, just use the status heartbeat on the Driver
  _input->read();

  if (_input->data._command != CLEAR_CMD)
  {
    Syslog::write("BuoyLauncherServer::getLauncherStatus():Driver busy %c",
		  _input->data._command);
    return DeviceIF::Offline; // device busy
  }

  _input->data._command = LC_STATUS;
  _input->write();

  while(1)
  {
    delay(100);
    _input->read();
    if (_input->data._command == CLEAR_CMD)
      break;
  }
*/
  _output->read();

  status->launcherError = _output->data._launcherError;
  status->lastLaunchOK  = _output->data._lastLaunchOK;
  status->lastLaunchDone = _output->data._lastLaunchDone;
  status->armsRetracted = _output->data._armsRetracted;
  status->buoyInLaunchPosition = _output->data._inLaunchPosition;
  //Syslog::write("BuoyLauncherServer::_inLaunchPosition is %d", _output->data._inLaunchPosition);

  status->buoyResponsive = _output->data._buoyResponsive;
  status->nextBuoyReady = _output->data._nextBuoyReady;
  status->currentBuoyNumber = _output->data._currentBuoyNumber;
  status->numTotalBuoys = _output->data._totalNumBuoys;
  status->numBuoysRemain = _output->data._numBuoysRemain;
  status->numBuoysLaunched = _output->data._numBuoysLaunched;
  status->timeSec = _output->data._timeSec;
  status->argosBytes = _output->data._argosBytesL;
  status->archiveBytes = _output->data._archiveBytesL;
  status->picoBytes = _output->data._picoBytesL;
  status->dataMemory = _output->data._dataMemoryL;

/*
  if (_output->data._launcherError > FATAL_ERROR)
  {
    Syslog::write("BuoyLauncherServer::getLauncherStatus(): LC reports fatal error");
    _fatalLauncherError = True;
  }
  else
  {
    _fatalLauncherError = False;
  }
*/

  return DeviceIF::Ok;
}

DeviceIF::Status BuoyLauncherServer::getBuoyStatus(BuoyLauncherIF::BC_status *status)
{
/* For now, just use the status heartbeat on the Driver
  _input->read();

  if (_input->data._command != CLEAR_CMD)
  {
    Syslog::write("BuoyLauncherServer::getBuoyStatus():Driver busy %c",
		  _input->data._command);
    return DeviceIF::Offline; // device busy
  }

  _input->data._command = LCBC_STATUS;
  _input->write();

  while(1)
  {
    delay(100);
    _input->read();
    if (_input->data._command == CLEAR_CMD)
      break;
  }
*/

  _output->read();

  status->buoyNumber = _output->data._buoyNumber;
  status->mainBattVolts = _output->data._mainBattVolts;
  status->auxBattVolts = _output->data._auxBattVolts;
  status->tempDegC = _output->data._tempDegC;
  status->timeSecBuoy = _output->data._timeSecB;
  status->argosBytes = _output->data._argosBytesB;
  status->archiveBytes = _output->data._archiveBytesB;
  status->picoBytes = _output->data._picoBytesB;
  status->dataMemory = _output->data._dataMemoryB;

  return DeviceIF::Ok;
}

int BuoyLauncherServer::spawnAuxTasks()
{
  char *program = "buoyLauncherDriver";
  char params[256];
  char errorBuf[256];
  int driverPid;

  switch ((driverPid = fork())) {
    
  case 0:
    // In child
    // Execute server program
    execlp(program, program, "-serial", _params->string(), 0);

    sprintf(errorBuf, 
	    "Task::spawnServer() - execlp() of \"%s\" failed", program);

    perror(errorBuf);

    break;

  case -1:
    perror("Task::spawnServer() - fork() failed");
    return -1;
  }

  return 0;
}

void BuoyLauncherServer::name(DeviceIF::Name name)
{
  strcpy(name,"BLS");
}

void BuoyLauncherServer::serialNumber(DeviceIF::Name number)
{
  strcpy(number, "XXX");
}

DeviceIF::Status BuoyLauncherServer::initialize()
{
  // Dummy implementation for now
  return DeviceIF::Ok;
}


DeviceIF::Status BuoyLauncherServer::powerOn()
{
  // Dummy implementation for now
  return DeviceIF::Ok;
}


DeviceIF::Status BuoyLauncherServer::powerOff()
{
  // Dummy implementation for now
  return DeviceIF::Ok;
}


DeviceIF::Status BuoyLauncherServer::status()
{
  // Dummy implementation for now
  return DeviceIF::Ok;
}
