/****************************************************************************/
/* Copyright (c) 2000 MBARI                                                 */
/* MBARI Proprietary Information. All rights reserved.                      */
/****************************************************************************/
/* Summary  :                                                               */
/* Filename : FuelCellServer.cc                                             */
/* Author   :                                                               */
/* Project  :                                                               */
/* Version  : 1.0                                                           */
/* Created  : 02/07/2000                                                    */
/* Modified :                                                               */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/****************************************************************************/
#include <process.h>
#include "FuelCellServer.h"
#include "mvc_fcc_api.h"
#include "Syslog.h"
#include "SharedData.h"
#ifdef _SIM
#include "SimulatedFuelCellIF.h"
#endif



FuelCellServer::FuelCellServer()
  : FuelCellIF_SK()
{
#ifdef _SIM
  try{
    Syslog::write("FuelCellServer.cc -- creating simulated fuel cell IF\n");
    simulatedfuelcell = new SimulatedFuelCellIF("simulatedfuelcell");
  }
  catch(SharedObjectClient::MissingServer e) {
       Syslog::write("FuelCellServer.cc --simulated Fuel Cell is not running. \n");
  }
  catch(...) {
    Syslog::write("FuelCellServer.cc -- failed on instantiation of SimulatedFuelCellIF");
  }
#endif
  //  _cutoffVoltage = 30.;
  Syslog::write("FuelCellServer -- FuelCellServer() -- creating output\n");
  _output = new FuelCellOutput(SharedData::ReadWrite);
  Syslog::write("FuelCellServer -- FuelCellServer() -- created output\n");
}


FuelCellServer::~FuelCellServer()
{
  delete _output;
}

void FuelCellServer::name(DeviceIF::Name name)
{
  strcpy(name,"FuelCell");
}

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


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


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


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


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


DeviceIF::Status FuelCellServer::dataLoggingOn()
{
  // Dummy implementation for now
  return DeviceIF::Ok;
}


DeviceIF::Status FuelCellServer::dataLoggingOff()
{
  // Dummy implementation for now
  return DeviceIF::Ok;
}


// the below are action commands send directly to the FCC via the FCC_api functions

//start fuel cell
DeviceIF::Status FuelCellServer::start()
{
  // must check current control state so that we don't do something redundant
  // or inconsistent with the fcc API
  Syslog::write("FuelCellServer::start()\n");
#ifdef _SIM
  Syslog::write("FuelCellServer -- WARNING, SIM IS DEFINED!\n");
  SimulatedFuelCellIF::FCC_status _fcc_status;
#endif
#ifndef _SIM
  FuelCellIF::FCC_status _fcc_status;
#endif
  //#ifdef _SIM
  //  if (simulatedfuelcell->get_simFCC_status(&_fcc_status) != DeviceIF::Ok)
  //#endif
    //#ifndef _SIM
  if (get_status(&_fcc_status) != DeviceIF::Ok)
    //#endif
	{
		// uh-oh, better throw an exception or something
		Syslog::write("FuelCellServer::start() -- couldn't get status\n");
		return DeviceIF::Error;
	}
  else /* STATUS IS OKAY */ 
	{
  		if (_fcc_status.fc_control_state != FC_STATE_IDLE)
		{
			// we're in the wrong state!
			Syslog::write("FuelCellServer::start() -- can't execute command, FC is in incorrect control state\n");	
			return DeviceIF::Error;	
		}
		else /*CONTROL STATE IS OKAY */
		{ 
		  int reply_code;
#ifdef _SIM
		  reply_code = simulatedfuelcell->send_simFCC_command(SimulatedFuelCellIF::FCC_CMD_START);
#endif
#ifndef _SIM
		  Syslog::write("FuelCellServer::start() - sending start command\n");
		  reply_code = send_FCC_command(FCC_CMD_START);
#endif
			if (reply_code!=FCC_ERR_OK)
			  { //bad reply code 
			    switch(reply_code)
			      {
			      case FCC_ERR_INVALID_PARAM:
				
				Syslog::write("FuelCellServer.cc:start()-- invalid parameter sent");
				throw Exception("FuelCellServer.cc:get_start()-- invalid parameter sent");
				return DeviceIF::Error;
				
				break;
				
			      case FCC_ERR_COMM:
				Syslog::write("FuelCellServer.cc:start()-- comm error");
				throw Exception("FuelCellServer.cc:start()-- comm error");
				break;
			      } // end switch
			  } //end bad reply code
  			else // good reply code
			  {
			    Syslog::write("FuelCellServer.cc:start() -- Fuel Cell is ramping up, wait until status = RUNNING (4) before sending new commands (120 sec)\n");
			    return DeviceIF::Ok;
			  }
     		} //end control-state if
	} // end status-okay-else 
  return DeviceIF::Ok;
}


DeviceIF::Status FuelCellServer::stop()
{
  Syslog::write("FuelCellServer::stop()\n");
   
  int reply_code;
#ifdef _SIM
  SimulatedFuelCellIF::FCC_status _fcc_status;
#endif
#ifndef _SIM
  FuelCellIF::FCC_status _fcc_status;
#endif
  //#ifdef _SIM
  //  if (simulatedfuelcell->get_simFCC_status(&_fcc_status) != DeviceIF::Ok)
  //#endif
  //#ifndef _SIM
  //  if (get_status(&_fcc_status) != DeviceIF::Ok)
  //#endif
  
  if (get_status(&_fcc_status) != DeviceIF::Ok)
    {
      // uh-oh, better throw an exception or something
    }
  else
    {
      if (_fcc_status.fc_control_state != FC_STATE_OFFLINE)
	{
	  // we're in the wrong state!
	  Syslog::write("FuelCellServer::start() -- can't execute command, FC is in incorrect control state\n");	
	  return DeviceIF::Error;	
	}
      else
	{
#ifdef _SIM
	  reply_code = simulatedfuelcell->send_simFCC_command(SimulatedFuelCellIF::FCC_CMD_STOP);
#endif
#ifndef _SIM
	  Syslog::write("FuelCellServer::stop() - sending stop command\n");
	  reply_code = send_FCC_command(FCC_CMD_STOP);
#endif
	  if (reply_code!=FCC_ERR_OK)
	    {
	      switch(reply_code)
		{
		case FCC_ERR_INVALID_PARAM:
		  
		  Syslog::write("FuelCellServer.cc:stop()-- invalid parameter sent");
		  throw Exception("FuelCellServer.cc:get_stop()-- invalid parameter sent");
		  return DeviceIF::Error;
		  
		  break;
		  
		case FCC_ERR_COMM:
		  Syslog::write("FuelCellServer.cc:stop()-- comm error");
		  throw Exception("FuelCellServer.cc:stop()-- comm error");
		  return DeviceIF::Error;
		  break;
		}
	    }
	  else
	    {
	      return DeviceIF::Ok;
	    }
	  
	  
	  
	}
    }
  return DeviceIF::Ok;
}

DeviceIF::Status FuelCellServer::offline()
{
  Syslog::write("FuelCellServer::offline\n");
  int reply_code;
  
#ifdef _SIM
  SimulatedFuelCellIF::FCC_status _fcc_status;
#endif
#ifndef _SIM
  FuelCellIF::FCC_status _fcc_status;
#endif
  //#ifdef _SIM
  //if (simulatedfuelcell->get_simFCC_status(&_fcc_status) != DeviceIF::Ok)
  //#endif
  //#ifndef _SIM
  //  if (get_status(&_fcc_status) != DeviceIF::Ok)
  //#endif
      
  //  FuelCellIF::FCC_status _fcc_status;
  
  if (get_status(&_fcc_status) != DeviceIF::Ok)
    {
      // uh-oh, better throw an exception or something
      return DeviceIF::Error;
    }
  else
    {
      
      if (_fcc_status.fc_control_state != FC_STATE_ONLINE)
	{
	  // we're in the wrong state!
	  Syslog::write("FuelCellServer::offline() -- can't execute command, FC is in incorrect control state\n");	
	  return DeviceIF::Error;	
	}
      else
	{
#ifdef _SIM
	  reply_code = simulatedfuelcell->send_simFCC_command(SimulatedFuelCellIF::FCC_CMD_OFFLINE);
#endif
#ifndef _SIM
	  Syslog::write("FuelCellServer: offline command sending\n");
	  reply_code = send_FCC_command(FCC_CMD_OFFLINE);
#endif
	  
	  if (reply_code!=FCC_ERR_OK)
	    {
	      switch(reply_code)
		{
		case FCC_ERR_INVALID_PARAM:
		  
		  Syslog::write("FuelCellServer.cc:offline()-- invalid parameter sent");
		  throw Exception("FuelCellServer.cc:get_offline()-- invalid parameter sent");
		  return DeviceIF::Error;
		  
		  break;
		  
		case FCC_ERR_COMM:
		  Syslog::write("FuelCell.cc:offline()-- comm error");
		  throw Exception("FuelCell.cc:offline()-- comm error");
		  break;
		}
	    }
	  else
	    {
	      return DeviceIF::Ok;
	    }
	}
    }
  return DeviceIF::Ok;
}


DeviceIF::Status FuelCellServer::resume()
{
  Syslog::write("FuelCellServer::resume()\n");
  int reply_code;
#ifdef _SIM
  SimulatedFuelCellIF::FCC_status _fcc_status;
#endif
#ifndef _SIM
  FuelCellIF::FCC_status _fcc_status;
#endif
  //#ifdef _SIM
  //  if (simulatedfuelcell->get_simFCC_status(&_fcc_status) != DeviceIF::Ok)
  //#endif
  //#ifndef _SIM
  //  if (get_status(&_fcc_status) != DeviceIF::Ok)
  //#endif
  
  if (get_status(&_fcc_status) != DeviceIF::Ok)
    {
      // uh-oh, better throw an exception or something
      return DeviceIF::Error;
    }
  else
    {
      if (_fcc_status.fc_control_state != FC_STATE_OFFLINE)
	{
	  // we're in the wrong state!
	  Syslog::write("FuelCellServer::offline() -- can't execute command, FC is in incorrect control state\n");	
	  return DeviceIF::Error;	
	}
      else
	{
	  
#ifdef _SIM
	  reply_code = simulatedfuelcell->send_simFCC_command(SimulatedFuelCellIF::FCC_CMD_RESUME);
#endif
#ifndef _SIM
	  reply_code = send_FCC_command(FCC_CMD_RESUME);
#endif
	  if (reply_code!=FCC_ERR_OK)
	    {
	      switch(reply_code)
		{
		case FCC_ERR_INVALID_PARAM:
		  
		  Syslog::write("FuelCellServer.cc:resume()-- invalid parameter sent");
		  throw Exception("FuelCell.cc:get_resume()-- invalid parameter sent");
		  return DeviceIF::Error;
		  
		  break;
		  
		case FCC_ERR_COMM:
		  Syslog::write("FuelCell.cc:resume()-- comm error");
		  throw Exception("FuelCell.cc:resume()-- comm error");
		  break;
		}
	    }
	  else
	    {
	      return DeviceIF::Ok;
	    }
	}
    }
  return DeviceIF::Ok;
}

//#ifndef _SIM
DeviceIF::Status FuelCellServer::get_status(FuelCellIF::FCC_status *fcc_status)
{
  _output->read();
  memcpy((void *)fcc_status, (void *)&_output->data.fcc_status, sizeof(FuelCellIF::FCC_status));
  
  return DeviceIF::Ok;
}
//#endif

//#ifdef _SIM
DeviceIF::Status FuelCellServer::get_status(SimulatedFuelCellIF::FCC_status *fcc_status)
{
  _output->read();
  memcpy((void *)fcc_status, (void *)&_output->data.fcc_status, sizeof(SimulatedFuelCellIF::FCC_status));
  return DeviceIF::Ok;
}
//#endif

DeviceIF::Status FuelCellServer::get_data(FuelCellIF::FCC_data *fcc_data)
{
  _output->read();
  memcpy((void *)fcc_data, (void *)&_output->data.fcc_data, sizeof(FuelCellIF::FCC_data));
  
  return DeviceIF::Ok;
}


int FuelCellServer::spawnAuxTasks()
{
  char *program = "fuelCellDriver";
  char errorBuf[256];
  
  pid_t pid;
  
  Syslog::write("FuelCellServer -- spawnAuxTasks() -- forking driver...\n");
  switch ((pid = fork())) {
  
  case 0:
    //     In child
    // Execute server program
    
    Syslog::write("FuelCellServer -- spawnAuxTasks() -- execlping driver..\n");
    execlp(program, program,0);
    
    sprintf(errorBuf, "Task::spawnServer() - execlp() of \"%s\" failed", program);

    perror(errorBuf);
 
    break;

  case -1:
    perror("Task::spawnServer() - fork() failed");
    Syslog::write("FuelCellServer -- spawnAuxTasks() -- fork() failed\n");
    return -1;
  }
    
  return 0;
}



