/*!
  \file
  \brief URG パラメータの表示ウィジット

  \author Satofumi KAMIMURA

  $Id: UrgInformationWidget.cpp 1850 2010-07-09 07:30:42Z satofumi $
*/

#include "UrgInformationWidget.h"
#include "SerialConnectionWidget.h"
#include "Connection.h"
#include "ConnectionUtils.h"
#include "UrgUsbCom.h"
#include "UrgDevice.h"
#include "FindComPorts.h"
#include "codedString.h"
#include <QMessageBox>
#include <QShortcut>
#include <QFileDialog>
#include <QTextStream>
#include <string>

using namespace qrk;
using namespace std;


namespace
{
  const char* Version = "1.0.2";
}


struct UrgInformationWidget::pImpl
{
  UrgInformationWidget* widget_;
  SerialConnectionWidget connection_widget_;
  QString message_;
  vector<QLabel*> result_labels_;

  UrgUsbCom urg_usb_;
  FindComPorts urg_finder_;
  UrgDevice urg_;


  pImpl(UrgInformationWidget* widget)
    : widget_(widget)
  {
    urg_finder_.addBaseName("/dev/ttyACM");
    urg_finder_.addBaseName("/dev/tty.usbmodem");
    urg_finder_.addDriverName("URG Series USB Device Driver");
    urg_finder_.addDriverName("URG-X002 USB Device Driver");
  }


  void initializeForm(void)
  {
    // タイトルにバージョン情報を付加
    const QString title =
      widget_->windowTitle() + " " + Version;
    widget_->setWindowTitle(title);

    // ConnectionWidget の配置
    widget_->connection_layout_->addWidget(&connection_widget_);
    widget_->connection_dummy_->hide();

    widget_->command_tab_->setCurrentIndex(0);

    message_ = tr("Select device, and press 'Connect'.");
    setEnabled(false);

    // 情報の出力先ポインタを確保
    result_labels_.push_back(widget_->vv_result_);
    result_labels_.push_back(widget_->pp_result_);
    result_labels_.push_back(widget_->ii_result_);

    // イベントの接続
    connect(&connection_widget_, SIGNAL(rescanRequest()),
            widget_, SLOT(rescanPressed()));
    connect(&connection_widget_,
            SIGNAL(connectRequest(bool, const std::string&)),
            widget_, SLOT(connectPressed(bool, const std::string&)));
    connect(widget_->save_button_, SIGNAL(clicked()),
            widget_, SLOT(saveLog()));
  }


  void setEnabled(bool enable)
  {
    widget_->message_label_->setText(message_);
    widget_->command_tab_->setEnabled(enable);

    if (! enable) {
      widget_->command_tab_->setCurrentIndex(0);
      for (vector<QLabel*>::iterator it = result_labels_.begin();
           it != result_labels_.end(); ++it) {
        (*it)->clear();
      }
    }
  }


  void updateInformatino(void)
  {
    Connection* con = urg_.connection();

    enum {
      BufferSize = 64,
      Timeout = 1000,
    };
    char buffer[BufferSize];

    // VV, PP, II の情報を取得して表示
    const char* commands[] = { "VV\n", "PP\n", "II\n" };
    size_t n = sizeof(commands) / sizeof(commands[0]);
    for (size_t i = 0; i < n; ++i) {
      con->send(commands[i], 3);

      QString lines;
      int n = 0;
      while (1) {
        n = readline(con, buffer, BufferSize, Timeout);
        if (n <= 0) {
          break;
        }
        buffer[n] = '\0';
        lines += QString(buffer) + "\n";
      }
      lines.remove(lines.size() - 1, 1);

      // 取得した情報を表示
      result_labels_[i]->setText(lines);
    }
    setEnabled(true);
  }


  void clearMessages(void)
  {
    widget_->vv_result_->clear();
    widget_->pp_result_->clear();
    widget_->ii_result_->clear();
  }
};


UrgInformationWidget::UrgInformationWidget(QWidget* parent)
  : QWidget(parent), pimpl(new pImpl(this))
{
  setupUi(this);

  // フォームを初期化し、最初の表示を行う
  pimpl->initializeForm();
  rescanPressed();

  // Ctrl-q, Alt-F4 で終了させる
  (void) new QShortcut(Qt::CTRL + Qt::Key_Q, this, SLOT(close()));
  (void) new QShortcut(Qt::ALT + Qt::Key_F4, this, SLOT(close()));
}


UrgInformationWidget::~UrgInformationWidget(void)
{
}


void UrgInformationWidget::rescanPressed(void)
{
  vector<string> devices;
  pimpl->urg_finder_.find(devices);
  for (vector<string>::iterator it = devices.begin();
       it != devices.end(); ++it) {
    if (pimpl->urg_usb_.isUsbCom(it->c_str())) {
      *it = *it + " [URG]";
    }
  }
  pimpl->connection_widget_.setDevices(devices);
  if (! devices.empty()) {
    pimpl->connection_widget_.setFocus();
  }
}


void UrgInformationWidget::connectPressed(bool connection, const string& device)
{
  // !!! 接続処理をスレッドで行うように調整する
  if (! connection) {
    return;
  }
  pimpl->clearMessages();
  save_button_->setEnabled(false);

  if (! pimpl->urg_.connect(device.c_str())) {
    QString error_message = localedToUnicode(pimpl->urg_.what());
    QMessageBox::warning(this, tr("Connection error"), error_message);
    pimpl->connection_widget_.setConnected(false);
    return;
  }

  save_button_->setEnabled(true);

  // 情報を更新後、切断する
  pimpl->updateInformatino();
  pimpl->connection_widget_.setConnected(false);
  pimpl->urg_.disconnect();
}


void UrgInformationWidget::saveLog(void)
{
  QString default_file_name = "UrgInformation_log.txt";
  QString file_name =
    QFileDialog::getSaveFileName(this, tr("Save information log."),
                                 default_file_name, tr("txt (*.txt)"));
  if (file_name.isEmpty()) {
    return;
  }

  // 保存
  QFile save_file(file_name);
  if (! save_file.open(QIODevice::WriteOnly | QIODevice::Text)) {
    return;
  }
  QTextStream fout(&save_file);
  fout << vv_result_->text() << endl
       << endl
       << pp_result_->text() << endl
       << endl
       << ii_result_->text() << endl;
}
