/*!
  \file
  \brief モニタ対応の UrgDevice クラス

  \author Satofumi KAMIMURA

  $Id: mUrgDevice.cpp 1524 2009-11-16 16:40:22Z satofumi $
*/

#include "mUrgDevice.h"
#include "DeviceManager.h"
#include "mConnection.h"
#include "MonitorDataHandler.h"
#include "LogNameHolder.h"
#include "SerialDevice.h"
#include "TcpipSocket.h"

using namespace qrk;
using namespace std;


struct mUrgDevice::pImpl
{
  UrgDevice urg_;
  ExecutionType::Type type_;
  SerialDevice* serial_;
  Connection* created_connection_;
  MonitorDataHandler* handler_;


  pImpl(void)
    : type_(ExecutionType::object()->type()),
      serial_(NULL), created_connection_(NULL), handler_(NULL)
  {
    if (type_ == ExecutionType::Simulation) {
      created_connection_ = new TcpipSocket;
      urg_.setConnection(created_connection_);

    } else {
      serial_= new SerialDevice;

      if ((type_ == ExecutionType::Recording) ||
          (type_ == ExecutionType::Playback)) {
        string log_name = LogNameHolder::object()->name("mUrgDevice");
        handler_ = new MonitorDataHandler(log_name, type_);
        created_connection_ = new mConnection(serial_);
        urg_.setConnection(created_connection_);

      } else {
        urg_.setConnection(serial_);
      }
    }
  }


  ~pImpl(void)
  {
    delete handler_;
    delete created_connection_;
    delete serial_;
  }
};


mUrgDevice::mUrgDevice(void) : pimpl(new pImpl)
{
}


mUrgDevice::~mUrgDevice(void)
{
}


const char* mUrgDevice::what(void) const
{
  return pimpl->urg_.what();
}


long mUrgDevice::timestamp(void) const
{
  if (pimpl->type_ == ExecutionType::Simulation) {
    return pimpl->urg_.timestamp();

  } else {
    long ret = pimpl->urg_.timestamp();
    if ((pimpl->type_ == ExecutionType::Recording) ||
        (pimpl->type_ == ExecutionType::Playback)) {
      pimpl->handler_->fetch(ret);
    }
    return ret;
  }
}


bool mUrgDevice::connect(const char* device, long baudrate)
{
  if (pimpl->type_ == ExecutionType::Simulation) {
    // ポート番号を取得し、TCP/IP として接続する
    DeviceManager device_manager;
    long port = device_manager.port(device);
    return pimpl->urg_.connect("localhost", port);

  } else {
    bool ret = pimpl->urg_.connect(device, baudrate);
    if ((pimpl->type_ == ExecutionType::Recording) ||
        (pimpl->type_ == ExecutionType::Playback)) {
      if (pimpl->handler_->fetch(ret) < 0) {
        disconnect();
        return false;
      }
    }
    return ret;
  }
}


void mUrgDevice::disconnect(void)
{
  pimpl->urg_.disconnect();
}


bool mUrgDevice::isConnected(void) const
{
  // 戻り値のみを記録する
  bool ret = false;
  if (pimpl->type_ != ExecutionType::Playback) {
    ret = pimpl->urg_.isConnected();
  }

  if ((pimpl->type_ == ExecutionType::Recording) ||
      (pimpl->type_ == ExecutionType::Playback)) {
    pimpl->handler_->fetch(ret);
  }
  return ret;
}


void mUrgDevice::setConnection(Connection* connection)
{
  pimpl->urg_.setConnection(connection);
}


Connection* mUrgDevice::connection(void)
{
  return pimpl->urg_.connection();
}


size_t mUrgDevice::scanMsec(void) const
{
  return pimpl->urg_.scanMsec();
}


size_t mUrgDevice::minDistance(void) const
{
  return pimpl->urg_.minDistance();
}


size_t mUrgDevice::maxDistance(void) const
{
  return pimpl->urg_.maxDistance();
}


size_t mUrgDevice::maxRange(void) const
{
  return pimpl->urg_.maxRange();
}


#if 0
void mUrgDevice::setTimestamp(long timestamp)
{
  pimpl->urg_.setTimestamp(timestamp);
}
#endif


void mUrgDevice::setCaptureTimes(size_t times)
{
  pimpl->urg_.setCaptureTimes(times);
}


void mUrgDevice::setCaptureRange(size_t begin_index, size_t end_index)
{
  pimpl->urg_.setCaptureRange(begin_index, end_index);
}


void mUrgDevice::setSkipLines(size_t skip_lines)
{
  pimpl->urg_.setSkipLines(skip_lines);
}


void mUrgDevice::setRequestMode(UrgDevice::CaptureMode mode)
{
  pimpl->urg_.setRequestMode(mode);
}


void mUrgDevice::requestData(void)
{
  pimpl->urg_.requestData();
}


bool mUrgDevice::receiveData(std::vector<long>& data, long* timestamp)
{
  return pimpl->urg_.receiveData(data, timestamp);
}


size_t mUrgDevice::rad2index(double radian) const
{
  return pimpl->urg_.rad2index(radian);
}


double mUrgDevice::index2rad(size_t index) const
{
  return pimpl->urg_.index2rad(index);
}


void mUrgDevice::laserOn(void)
{
  pimpl->urg_.laserOn();
}


void mUrgDevice::laserOff(void)
{
  pimpl->urg_.laserOff();
}
