#include <stdio.h>
#include "MethaneSensor.h"
#include "Syslog.h"

#define MaxRecordBytes 56
#define RecordTerminator "\r"
#define ReadTimeout 500
#define MaxInitTries 2

MethaneLog::MethaneLog(DataLog::FileFormat fileFormat)
  : DataLogWriter(MethaneLogName, fileFormat, AutoTimeStamp),
    channel1("channel1"), channel2("channel2"), channel3("channel3")
{
  addField(&channel1);
  addField(&channel2);
  addField(&channel3);
}


MethaneLog::~MethaneLog()
{
}


void MethaneLog::setFields()
{
  // Don't worry about it here; MethaneSensor::processRecord() actually
  // sets the fields in this case.
}


MethaneSensor::MethaneSensor(SerialDevice *device, Boolean verbose)
  : SerialDeviceDriver("methaneSensor", 
		       device, 
		       MaxRecordBytes,
		       RecordTerminator,
		       ReadTimeout,
		       MaxInitTries)
{
  _log = new MethaneLog(DataLog::BinaryFormat);
  _verbose = verbose;
}


MethaneSensor::~MethaneSensor()
{
  delete _log;
}


DeviceIF::Status MethaneSensor::initialize()
{
  return DeviceIF::Ok;
}


DeviceIF::Status MethaneSensor::requestData()
{
  _device->clearPort();

  char cmd[100];
  sprintf(cmd, "#A0\r");
  if (_device->write(cmd, strlen(cmd)) == strlen(cmd)) {
    setState(DeviceIF::Ok);
  }
  else {
    setState(DeviceIF::Error);
  }

  return state();
}


virtual DeviceIF::Status MethaneSensor::processRecord(unsigned char *record, 
						      int nRecordBytes)
{
  Boolean debug = _verbose;

  enum {
    Channel1, Channel2, Channel3,

    // NOTE: This must be the last value in the enumeration
    NTokens
  };

  dprintf("MethaneSensor::processRecord() - record=%s", record);

  char *ptr = (char *)record;
  char *token;
  int nToken = 0;

  // Parse the data record
  while (True) {

    if ((token = strtok(ptr, " ")) == 0) 
      break;

    ptr = 0;

    // Skip past ':', point to ascii hex representation
    char *valueToken;
    if ((valueToken = strchr(token, ':')) == 0) {
      // Couldn't find ':' - parsing error
      Syslog::write("MethaneSensor::processRecord() - can't find ':' in %s",
		    token);

      return DeviceIF::Error;
    }
    valueToken++;

    int value;

    if (sscanf(valueToken, "%lx", &value) != 1) {

      Syslog::write("MethaneSensor::processRecord() - invalid value: %s",
		    valueToken);

      return DeviceIF::Error;
    }
    
    switch (nToken) {
    case Channel1:
      _log->channel1.setValue(value);
      break;

    case Channel2:
      _log->channel2.setValue(value);
      break;

    case Channel3:
      _log->channel3.setValue(value);
      break;
      
    default:
      Syslog::write("MethaneSensor::processRecord() - bad token #: %d", 
		    nToken);

      return DeviceIF::Error;
    }

    if (++nToken == NTokens)
      // Done
      break;
  }

  if (nToken != NTokens) {
    Syslog::write("MethaneSensor::processRecord() - too few tokens - %d?",
		  nToken);

    return DeviceIF::Error;
  }

  _log->write();
  return DeviceIF::Ok;
}


DeviceIF::Status MethaneSensor::readRecord(unsigned char *record,
					   int maxRecordBytes,
					   const char *recordTerminator,
					   unsigned readTimeout,
					   int *nBytesRead)
{
  Boolean debug = False;
  dprintf("MethaneSensor::readRecord()");

  Boolean readError = False;

  try {

    // Read data record from device
    *nBytesRead = _device->readNChars((char *)record, maxRecordBytes, 
				      readTimeout);
  }
  catch (SerialDevice::TimedOut) {
    readError = True;
    Syslog::write("%s::readRecord() - serial device timed out", name());
    Syslog::write("%s::readRecord() - record so far: %s", name(), record);
  }
  catch (SerialDevice::BufferFull) {
    readError = True;
    Syslog::write("%s::readRecord() - serial device buffer full", name());
  }
  catch (Exception e) {
    readError = True;
    Syslog::write("%s::readRecord() - caught exception:  abort", name());
    throw;
  }

  if (readError)
    return DeviceIF::Error;
  else
    return DeviceIF::Ok;
}
