/*!
  \file
  \brief TCP/IP 通信

  \author Satofumi KAMIMURA

  $Id: TcpipSocket.cpp 1302 2009-09-15 21:51:30Z satofumi $

  \todo テストを実装して動作確認を行う
*/

#include "TcpipSocket.h"
#include <QTcpSocket>

using namespace qrk;


struct TcpipSocket::pImpl
{
  QTcpSocket* socket_;
  long baudrate_;


  pImpl(QTcpSocket* socket) : socket_(socket), baudrate_(0)
  {
  }


  ~pImpl(void)
  {
    delete socket_;
  }
};


TcpipSocket::TcpipSocket(void) : pimpl(new pImpl(new QTcpSocket))
{
}


TcpipSocket::TcpipSocket(void* socket)
  : pimpl(new pImpl(static_cast<QTcpSocket*>(socket)))
{
}



TcpipSocket::~TcpipSocket(void)
{
}


const char* TcpipSocket::what(void) const
{
  return pimpl->socket_->errorString().toStdString().c_str();
}


bool TcpipSocket::connect(const char* host, long port)
{
  pimpl->socket_->connectToHost(host, port);

  enum { ConnectionTimeout = 3000 };
  bool ret = pimpl->socket_->waitForConnected(ConnectionTimeout);

  return ret;
}


void TcpipSocket::disconnect(void)
{
  pimpl->socket_->disconnectFromHost();
}


bool TcpipSocket::setBaudrate(long baudrate)
{
  // 実装しない
  pimpl->baudrate_ = baudrate;
  return true;
}


long TcpipSocket::baudrate(void) const
{
  // 実装しない
  return pimpl->baudrate_;
}


bool TcpipSocket::isConnected(void) const
{
  return pimpl->socket_->isValid();
}


int TcpipSocket::send(const char* data, size_t count)
{
  return pimpl->socket_->write(data, count);
}


int TcpipSocket::receive(char* data, size_t count, int timeout)
{
  if (count == 0) {
    return 0;
  }

  size_t filled = 0;
  do {
    int n = pimpl->socket_->read(&data[filled], count - filled);
    if (n < 0) {
      return n;
    }
    if (n > 0) {
      filled += n;
    }

    if ((filled < count) && (! pimpl->socket_->waitForReadyRead(timeout))) {
      break;
    }
  } while (filled < count);

  return filled;
}


size_t TcpipSocket::size(void) const
{
  return pimpl->socket_->bytesAvailable();
}


void TcpipSocket::flush(void)
{
  pimpl->socket_->flush();
}


void TcpipSocket::clear(void)
{
  // 受信バッファの内容を読み捨てる
  enum { BufferSize = 256 };
  char buffer[BufferSize];

  while (receive(buffer, BufferSize, 0) == BufferSize) {
    ;
  }
}


void TcpipSocket::ungetc(const char ch)
{
  pimpl->socket_->ungetChar(ch);
}
