/*!
  \file
  \brief URG の出力ログ管理

  \author Satofumi KAMIMURA

  $Id: UrgLogHandler.cpp 1970 2011-11-09 06:53:29Z satofumi $
*/

#include "UrgLogHandler.h"
#include "split.h"
#include <fstream>
#include <cstdlib>

using namespace qrk;
using namespace std;


namespace {
  enum {
    InvalidTimestamp = -1,
  };
}

struct UrgLogHandler::pImpl
{
  ofstream fout_;
  ifstream* fin_;

  int last_timestamp_;
  int cached_timestamp_;
  vector<qrk::Point<long> > cached_points_;


  pImpl(void)
    : fin_(NULL), last_timestamp_(0), cached_timestamp_(InvalidTimestamp)
  {
  }


  void addData(size_t timestamp, const vector<qrk::Point<long> >& points)
  {
    last_timestamp_ = timestamp;

    fout_ << timestamp << ',' << points.size() << ',';

    for (vector<qrk::Point<long> >::const_iterator it = points.begin();
         it != points.end(); ++it) {
      fout_ << it->x << ',' << it->y << ',';
    }
    fout_ << endl;
  }


  bool load(const char* file_name)
  {
    fin_ = new ifstream(file_name);
    if (! fin_->is_open()) {
      delete fin_;
      fin_ = NULL;
      return false;
    }

    // 最後の行を読み出し、最大のタイムスタンプ値を取得する
    string line;
    while (getline(*fin_, line)) {
      last_timestamp_ = atoi(line.c_str());
    }
    if (last_timestamp_ == 0) {
      delete fin_;
      fin_ = NULL;
      return false;
    }

    cached_timestamp_ = InvalidTimestamp;

    // ifstream::seekg(0) が動作しなかったため、再 open() する
    delete fin_;
    fin_ = new ifstream(file_name);

    return true;
  }


  bool getData(size_t& timestamp, vector<qrk::Point<long> >& points,
               size_t current_timestamp)
  {
    if (cached_timestamp_ == InvalidTimestamp) {
      // データの読み出し
      string line;
      if (! getline(*fin_, line)) {
        return false;
      }

      vector<string> tokens;
      if (qrk::split(tokens, line, " \t,") <= 1) {
        // タイムスタンプ、データ数、だけのトークンがない
        return false;
      }

      cached_timestamp_ = atoi(tokens[0].c_str());
      int n = atoi(tokens[1].c_str());

      cached_points_.clear();
      for (int i = 0; i < n; ++i) {
        int x = atoi(tokens[2 + (2 * i)].c_str());
        int y = atoi(tokens[2 + (2 * i) + 1].c_str());

        cached_points_.push_back(Point<long>(x, y));
      }
    }

    // 保持しているデータが指定タイムスタンプよりも古ければ、データを返す
    if (static_cast<size_t>(cached_timestamp_) > current_timestamp) {
      return false;
    }
    timestamp = cached_timestamp_;
    points = cached_points_;

    cached_timestamp_ = InvalidTimestamp;

    return true;
  }
};


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


UrgLogHandler::~UrgLogHandler(void)
{
}


bool UrgLogHandler::create(const char* file_name) {

  pimpl->fout_.open(file_name);

  return (! pimpl->fout_.is_open()) ? false : true;
}


void UrgLogHandler::addData(size_t timestamp,
                            const vector<qrk::Point<long> >& points)
{
  pimpl->addData(timestamp, points);
}


void UrgLogHandler::close()
{
  pimpl->fout_.close();
}


bool UrgLogHandler::load(const char* file_name)
{
  return pimpl->load(file_name);
}


int UrgLogHandler::getLastTimestamp(void)
{
  return pimpl->last_timestamp_;
}


bool UrgLogHandler::getData(size_t& timestamp,
                            vector<qrk::Point<long> >& points,
                            size_t current_timestamp)
{
  return pimpl->getData(timestamp, points, current_timestamp);
}
