/*!
  \file
  \brief F-ZTAT の処理

  \author Satofumi KAMIMURA

  $Id: FZtatHandler.cpp 1107 2009-07-02 21:31:47Z satofumi $
*/

#include "FZtatHandler.h"
#include "Connection.h"
#include <vector>
#include <string>

using namespace qrk;
using namespace std;


struct FZtatHandler::pImpl
{
  string error_message_;


  pImpl(void) : error_message_("no error.")
  {
  }


  bool receive_ch(Connection* connection, char expected_ch, int timeout)
  {
    char recv_ch;
    int n = connection->receive(&recv_ch, 1, timeout);
    return ((n != 1) || (recv_ch != expected_ch)) ? false : true;
  }
};


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


FZtatHandler::~FZtatHandler(void)
{
}


const char* FZtatHandler::what(void) const
{
  return pimpl->error_message_.c_str();
}


bool FZtatHandler::transfer(Connection* connection,
                            const char* writer_program, size_t send_size)
{
  enum {
    Timeout = 100,              // [msec]
  };

  // 0x00 を受信するまで、0x00 を連続送信する
  char send_ch = 0x00;
  enum { RetryTimes = 10 };
  size_t i = 0;
  for (i = 0; i < RetryTimes; ++i) {
    connection->send(&send_ch, 1);
    if (pimpl->receive_ch(connection, 0x00, 1)) {
      break;
    }
  }
  if (i >= RetryTimes) {
    pimpl->error_message_ = "transfer fail: coudn't adjust baudrate.";
    return false;
  }

  // 0x55 を送信する
  send_ch = 0x55;
  connection->send(&send_ch, 1);

  // 0xaa を受信する
  if (! pimpl->receive_ch(connection, 0xaa, Timeout)) {
    pimpl->error_message_ = "transfer fail: no receive 1st 0xaa.";
    return false;
  }

  // send_size を 2 byte に分けて送信する
  char size_bytes[2];
  size_bytes[0] = (send_size >> 8) & 0xff;
  size_bytes[1] = send_size & 0xff;
  connection->send(size_bytes, 2);

  // 送信した 2 文字のエコーバックを受け取る
  if ((! pimpl->receive_ch(connection, size_bytes[0], Timeout)) ||
      (! pimpl->receive_ch(connection, size_bytes[1], Timeout))) {
    pimpl->error_message_ = "transfer fail: size echoback mismatch.";
    return false;
  }

  // プログラムを送信し、エコーバックを受け取る
  vector<char> receive_buffer;
  receive_buffer.resize(send_size);
  connection->send(writer_program, send_size);
  int n = connection->receive(&receive_buffer[0], send_size, Timeout);
  if (n != static_cast<int>(send_size)) {
    pimpl->error_message_ = "transfer fail: program echoback mismatch.";
    return false;
  }

  // 0xaa を受信する
  if (! pimpl->receive_ch(connection, 0xaa, Timeout)) {
    pimpl->error_message_ = "transfer fail: no receive 2nd 0xaa.";
    return false;
  }

  return true;
}
