/*!
  \file
  \brief 複数 URG のデータ閲覧ツール

  \author Satofumi KAMIMURA

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

#include "MultiUrgViewerWidget.h"
#include "UrgStateWidget.h"
#include "DrawWidget.h"
#include "UrgUsbCom.h"
#include "FindComPorts.h"
#include <QShortcut>
#include <QVBoxLayout>
#include <vector>
#include <algorithm>

using namespace qrk;
using namespace std;


struct MultiUrgViewerWidget::pImpl
{
  MultiUrgViewerWidget* widget_;
  QVBoxLayout layout_;
  vector<UrgStateWidget*> urg_state_;
  DrawWidget draw_widget_;


  pImpl(MultiUrgViewerWidget* widget)
    : widget_(widget), layout_(widget_)
  {
  }


  void initializeForm(void)
  {
    // フォームの初期化
    widget_->setWindowTitle(tr("Multi URG Viewer"));
    layout_.setAlignment(Qt::AlignTop);

    connect(&draw_widget_, SIGNAL(quit()), widget_, SLOT(close()));

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

    // 最初の UrgState を配置
    addUrgState();
    rescanDevices();
  }


  void addUrgState(void)
  {
    if (! urg_state_.empty()) {
      UrgStateWidget* last_urg_state = urg_state_.back();
      if (! last_urg_state->isConnected()) {
        // 最後の UrgState が未接続ならば、追加しない
        return;
      }
    }

    UrgStateWidget* widget = new UrgStateWidget(widget_);
    urg_state_.push_back(widget);
    layout_.addWidget(widget);
  }


  void deleteUrgState(UrgStateWidget* widget)
  {
    layout_.removeWidget(widget);

    draw_widget_.disconnected(widget);

    vector<UrgStateWidget*>::iterator p =
      std::find(urg_state_.begin(), urg_state_.end(), widget);
    if (p != urg_state_.end()) {
      urg_state_.erase(p);
    }
    delete widget;

    addUrgState();
    rescanDevices();
  }


  void rescanDevices(void)
  {
    // デバイス一覧の取得
    FindComPorts urg_finder;
    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");

    vector<string> urg_ports;
    urg_finder.find(urg_ports);

    // 接続済みのデバイスを除去する
    for (vector<UrgStateWidget*>::iterator it = urg_state_.begin();
         it != urg_state_.end(); ++it) {
      const string device = (*it)->device();
      vector<string>::iterator p =
        std::find(urg_ports.begin(), urg_ports.end(), device);
      if (p != urg_ports.end()) {
        urg_ports.erase(p);
      }
    }

    // 接続されてないデバイスに対してデバイスを登録
    UrgUsbCom urg_usb;
    UrgStateWidget* last_urg_state = urg_state_.back();
    for (vector<string>::iterator it = urg_ports.begin();
         it != urg_ports.end(); ++it) {
      if (urg_usb.isUsbCom(it->c_str())) {
        *it = *it + " [URG]";
      }
    }
    last_urg_state->setDevices(urg_ports);
  }
};


MultiUrgViewerWidget::MultiUrgViewerWidget(QWidget* parent)
  : QWidget(parent), pimpl(new pImpl(this))
{
  pimpl->initializeForm();
}


MultiUrgViewerWidget::~MultiUrgViewerWidget(void)
{
}


void MultiUrgViewerWidget::deleteUrgState(UrgStateWidget* widget)
{
  pimpl->deleteUrgState(widget);
}


void MultiUrgViewerWidget::closeEvent(QCloseEvent* event)
{
  static_cast<void>(event);

  for (vector<UrgStateWidget*>::iterator it = pimpl->urg_state_.begin();
       it != pimpl->urg_state_.end(); ++it) {
    (*it)->close();
    pimpl->deleteUrgState(*it);
  }
  pimpl->draw_widget_.close();
}


void MultiUrgViewerWidget::rescanDevices(void)
{
  pimpl->rescanDevices();
}


void MultiUrgViewerWidget::addUrgState(void)
{
  pimpl->addUrgState();
}


DrawWidget* MultiUrgViewerWidget::drawWidget(void)
{
  return &pimpl->draw_widget_;
}
