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

  \author Satofumi KAMIMURA

  $Id: ConnectionRecorder.cpp 1811 2010-04-30 16:12:05Z 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);
}
