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

  \author Satofumi KAMIMURA

  $Id: UrgInformationWidget.cpp 1439 2009-10-22 02:09:34Z satofumi $
*/

#include "UrgInformationWidget.h"
#include "ConnectionWidget.h"
#include "Connection.h"
#include "ConnectionUtils.h"
#include "UrgUsbCom.h"
#include "UrgCtrl.h"
#include "FindComPorts.h"
#include <QMessageBox>
#include <QShortcut>
#include <string>

using namespace qrk;
using namespace std;


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

  UrgUsbCom urg_usb_;
  FindComPorts urg_finder_;
  UrgCtrl 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)
  {
    // 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&)));
  }


  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);
  }
};


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);
}


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

  if (! pimpl->urg_.connect(device.c_str())) {
    QMessageBox::warning(this, tr("Connection error"), pimpl->urg_.what());
    return;
  }

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