/*!
  \file
  \brief シミュレータ用のウィンドウ

  \author Satofumi KAMIMURA

  $Id: SimulationWindow.cpp 1444 2009-10-25 01:04:59Z satofumi $
*/

#include "SimulationWindow.h"
#include "SimulationMain.h"
#include "TicksControlWidget.h"
#include "DrawEnvironmentWidget.h"
#include "DeviceManager.h"
#include "fileExist.h"
#include <QTimer>
#include <QShortcut>
#include <QSettings>
#include <QMessageBox>
#include <iostream>

using namespace qrk;
using namespace std;


namespace
{
  enum {
    RedrawFps = 20,             // [msec]
  };

  const char* Organization = "Hyakuren soft.";
  const char* Application = "QRK Simulator";


  void printVersion(void)
  {
    cout << "version message: not implemented." << endl;
  }


  void printHelp(void)
  {
    cout << "help message: not implemented." << endl;
  }
}


struct SimulationWindow::pImpl
{
  SimulationWindow* window_;
  DrawEnvironmentWidget draw_environment_widget_;
  TicksControlWidget ticks_control_widget_;

  DeviceManager device_manager_;
  SimulationMain simulation_main_;

  QTimer redraw_timer_;


  pImpl(SimulationWindow* window,
        MainFunction* function, int argc, char *argv[])
    : window_(window), simulation_main_(function, argc, argv)
  {
    ArgsInformation args;

    // シミュレーション設定を読み出して反映させる
    if (! parseArgs(args, argc, argv)) {
      exit(0);
    }
    ExecutionType* execution_type = ExecutionType::object();
    if (args.simulation_) {
      execution_type->setType(ExecutionType::Simulation);

    } else {
      execution_type->setType(args.type_);
    }

    // メインプログラムの実行
    simulation_main_.start();
  }


  void initializeForm(void)
  {
    window_->dummy_label_->hide();
    window_->main_layout_->addWidget(&draw_environment_widget_);

    // TicksControlWidget
    connect(&ticks_control_widget_, SIGNAL(play()),
            window_, SLOT(playPressed()));
    connect(&ticks_control_widget_, SIGNAL(pause()),
            window_, SLOT(pausePressed()));
    connect(&ticks_control_widget_, SIGNAL(moreFaster()),
            window_, SLOT(moreFasterPressed()));
    connect(&ticks_control_widget_, SIGNAL(moreSlower()),
            window_, SLOT(moreSlowerPressed()));

    // 終了用のシグナルを接続
    connect(&ticks_control_widget_, SIGNAL(quit()),
            window_, SLOT(quitHandler()));
    connect(window_->action_quit_, SIGNAL(triggered()),
            window_, SLOT(quitHandler()));

    // About の表示
    connect(window_->action_about_, SIGNAL(triggered()),
            window_, SLOT(aboutApplication()));

    // サブウィンドウの表示/非表示
    connect(&ticks_control_widget_, SIGNAL(closed()),
            window_, SLOT(ticksControlClosed()));
    connect(window_->action_ticks_control_, SIGNAL(toggled(bool)),
            window_, SLOT(ticksControlChecked(bool)));

    // View
    connect(window_->action_wire_frame_, SIGNAL(toggled(bool)),
            window_, SLOT(wireframeChecked(bool)));

    // 描画タイマーの動作開始
    connect(&redraw_timer_, SIGNAL(timeout()), window_, SLOT(redraw()));
    redraw_timer_.setInterval(RedrawFps);
    redraw_timer_.start();
  }


  void loadSettings(void)
  {
    QSettings settings(Organization, Application);

    // ウィンドウ位置
    window_->restoreGeometry(settings.value("window_geometry").toByteArray());
    ticks_control_widget_.
      restoreGeometry(settings.value("ticks_geometry").toByteArray());

    // サブウィンドウの表示/非表示
    bool ticks_control_show =
      settings.value("ticks_control_show", false).toBool();
    ticks_control_widget_.setVisible(ticks_control_show);
    window_->action_ticks_control_->setChecked(ticks_control_show);

    // ワイヤーフレーム表示
    bool wire_frame = settings.value("wireframe_view", false).toBool();
    draw_environment_widget_.setWireframeMode(wire_frame);
    window_->action_wire_frame_->setChecked(wire_frame);
  }


  void saveSettings(void)
  {
    QSettings settings(Organization, Application);

    // ウィンドウ位置
    settings.setValue("window_geometry", window_->saveGeometry());
    settings.setValue("ticks_geometry", ticks_control_widget_.saveGeometry());

    // サブウィンドウの表示/非表示
    settings.setValue("ticks_control_show", ticks_control_widget_.isVisible());

    // ワイヤーフレーム表示
    bool wire_frame = window_->action_wire_frame_->isChecked();
    settings.setValue("wireframe_view", wire_frame);
  }


  void closeAll(void)
  {
    ticks_control_widget_.close();
    // !!!
  }
};


SimulationWindow::SimulationWindow(MainFunction* function,
                                   int argc, char *argv[])
  : pimpl(new pImpl(this, function, argc, argv))
{
  setupUi(this);
  pimpl->initializeForm();
  pimpl->loadSettings();

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


SimulationWindow::~SimulationWindow(void)
{
}


bool SimulationWindow::parseArgs(ArgsInformation& args, int argc, char *argv[])
{
  for (int i = 1; i < argc; ++i) {
    char* token = argv[i];

    if ((! strcmp("-r", token)) || (! strcmp("--recording", token))) {
      if (args.type_ < ExecutionType::Recording) {
        args.type_ = ExecutionType::Recording;
      }

    } else if ((! strcmp("-m", token)) || (! strcmp("--monitoring", token))) {
      if (args.type_ < ExecutionType::Monitoring) {
        args.type_ = ExecutionType::Monitoring;
      }

    } else if ((! strcmp("-p", token)) || (! strcmp("--playback", token))) {
      if (args.type_ < ExecutionType::Playback) {
        args.type_ = ExecutionType::Playback;
      }

    } else if ((! strcmp("-s", token)) || (! strcmp("--simulation", token))) {
      args.simulation_ = true;

    } else if ((! strcmp("-v", token)) || (! strcmp("--version", token))) {
      printVersion();
      return false;

    } else if ((! strcmp("-h", token)) || (! strcmp("--help", token))) {
      printHelp();
      return false;
    }
  }

  // 引数がなかったときに "simulation_only.txt" ファイルが存在したら
  // シミュレーションとして動作させる
  if ((args.type_ == ExecutionType::RealDevice) &&
      fileExist("simulation_only.txt")) {
    args.simulation_ = true;
  }

  return true;
}


void SimulationWindow::quitHandler(void)
{
  close();
}


void SimulationWindow::closeEvent(QCloseEvent* event)
{
  static_cast<void>(event);
  pimpl->saveSettings();

  pimpl->simulation_main_.event_scheduler_.terminate();

  // スレッドが終了しないので、タイムアウト付きで強制終了させる
  pimpl->simulation_main_.terminate();
  pimpl->simulation_main_.wait(100);

  pimpl->device_manager_.terminate();

  pimpl->closeAll();
}


void SimulationWindow::playPressed(void)
{
  pimpl->simulation_main_.event_scheduler_.play();
}


void SimulationWindow::pausePressed(void)
{
  pimpl->simulation_main_.event_scheduler_.pause();
}


void SimulationWindow::moreFasterPressed(void)
{
  pimpl->simulation_main_.event_scheduler_.moreFaster();
}


void SimulationWindow::moreSlowerPressed(void)
{
  pimpl->simulation_main_.event_scheduler_.moreSlower();
}


void SimulationWindow::redraw(void)
{
  pimpl->draw_environment_widget_.redraw();
}


void SimulationWindow::aboutApplication(void)
{
  QMessageBox::about(this, tr("About QRK Simulator"),
                     tr("<h2>QRK Simulator</h2>"
                        "<p>QRK Robot & Sensor simulator</p>"
                        "<p>Report bugs to "
                        "&lt;satofumi@users.sourceforge.jp&gt;</p>"));
}


void SimulationWindow::ticksControlClosed(void)
{
  action_ticks_control_->setChecked(false);
}


void SimulationWindow::ticksControlChecked(bool checked)
{
  pimpl->ticks_control_widget_.setVisible(checked);
}


void SimulationWindow::wireframeChecked(bool checked)
{
  pimpl->draw_environment_widget_.setWireframeMode(checked);
}
