/*!
  \file
  \brief 通信データの記録

  \author Satofumi KAMIMURA

  $Id: ConnectionRecorder.cpp 1372 2009-10-06 12:59:28Z satofumi $
*/

#include <fstream>
#include <string>
#include "ConnectionRecorder.h"

using namespace qrk;
using namespace std;


struct ConnectionRecorder::pImpl
{
  enum {
    Recv = 0,
    Send,
  };

  Connection* con_;
  size_t unget_count_;
  ofstream fout_[2];


  pImpl(Connection* con) : con_(con), unget_count_(0)
  {
    setBaseName("recorder");
  }


  void setBaseName(const char* basename)
  {
    const char* suffix[] = {
      "_receive.txt",
      "_send.txt",
    };

    for (size_t i = 0; i < 2; ++i) {
      // 現状の接続を閉じる
      if (fout_[i].is_open()) {
        fout_[i].close();
      }

      // 新しい名前で接続を開く
      string fname = string(basename) + suffix[i];
      fout_[i].open(fname.c_str(), ios::binary);
    }
  }
};


ConnectionRecorder::ConnectionRecorder(Connection* con)
  : pimpl(new pImpl(con))
{
}


ConnectionRecorder::~ConnectionRecorder(void)
{
}


const char* ConnectionRecorder::what(void) const
{
  return pimpl->con_->what();
}


bool ConnectionRecorder::connect(const char* device, long baudrate)
{
  return pimpl->con_->connect(device, baudrate);
}


void ConnectionRecorder::disconnect(void)
{
  pimpl->con_->disconnect();
}


bool ConnectionRecorder::setBaudrate(long baudrate)
{
  return pimpl->con_->setBaudrate(baudrate);
}


long ConnectionRecorder::baudrate(void) const
{
  return pimpl->con_->baudrate();
}


bool ConnectionRecorder::isConnected(void) const
{
    return pimpl->con_->isConnected();
}


int ConnectionRecorder::send(const char* data, size_t count)
{
  int n = pimpl->con_->send(data, count);

  if (n > 0) {
    pimpl->fout_[pImpl::Send].write(data, n);
    pimpl->fout_[pImpl::Send].flush();
  }
  return n;
}


int ConnectionRecorder::receive(char* data, size_t count, int timeout)
{
  int n = pimpl->con_->receive(data, count, timeout);

  // 過去に書き戻した分は、ファイルに書き出さない
  int skip_length = pimpl->unget_count_;
  if ((n > 0) && (skip_length > n)) {
    skip_length = n;
  }
  pimpl->unget_count_ -= skip_length;

  // ファイルへの受信データ書き出し
  if (n > 0) {
    pimpl->fout_[pImpl::Recv].write(&data[skip_length], n - skip_length);
    pimpl->fout_[pImpl::Recv].flush();
  }
  return n;
}


size_t ConnectionRecorder::size(void) const
{
  return pimpl->con_->size();
}


void ConnectionRecorder::flush(void)
{
  pimpl->con_->flush();
}


void ConnectionRecorder::clear(void)
{
  pimpl->con_->clear();
}


void ConnectionRecorder::ungetc(const char ch)
{
  ++pimpl->unget_count_;
  pimpl->con_->ungetc(ch);
}


void ConnectionRecorder::setBasename(const char* basename)
{
  pimpl->setBaseName(basename);
}
