/*!
  \file
  \brief 範囲を 2D 表示するウィジット

  \author Satofumi KAMIMURA

  $Id: cRangeViewWidget.cpp 1299 2009-09-15 00:56:12Z satofumi $
*/

#include "cRangeViewWidget.h"
#include "cCaptureSettingWidget.h"
#include "RangeSensorParameter.h"
#include "MathUtils.h"
#include <QPainter>

using namespace qrk;
using namespace std;


struct cRangeViewWidget::pImpl
{
  cRangeViewWidget* widget_;
  cCaptureSettingWidget* widget_parent_;

  bool is_parameter_loaded_;
  RangeSensorParameter parameter_;

  int first_index_;
  int last_index_;


  pImpl(cRangeViewWidget* widget, cCaptureSettingWidget* widget_parent)
    : widget_(widget), widget_parent_(widget_parent),
      is_parameter_loaded_(false), first_index_(0), last_index_(0)
  {
  }


  void initializeForm(void)
  {
    widget_->setMinimumSize(200, 200);
    widget_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

    connect(widget_parent_, SIGNAL(rangeChanged(int, int)),
            widget_, SLOT(isRangeChanged(int, int)));
  }


  double index2rad(int index)
  {
    int index_from_front = index - parameter_.area_front;
    return index_from_front * (2.0 * M_PI) / parameter_.area_total;
  }


  QPoint calculatePoint(int radius, double radian)
  {
    int x = static_cast<int>(radius * cos(radian));
    int y = static_cast<int>(radius * sin(radian));

    return QPoint(x, y);
  }
};


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


cRangeViewWidget::~cRangeViewWidget(void)
{
}


void cRangeViewWidget::paintEvent(QPaintEvent* event)
{
  static_cast<void>(event);

  QPainter painter;
  painter.begin(this);
  QRect this_rect = rect();
  painter.fillRect(this_rect, QBrush(QColor(Qt::white)));
  painter.drawRect(0, 0, this_rect.width() - 1, this_rect.height() - 1);

  // !!! 最初にオブジェクトを作って使いまわすように変更すべき
  enum { FontSize = 12 };
  QFont font("times", FontSize);
  QFontMetrics fm(font);
  size_t text_height = fm.height();
  size_t text_width = fm.width("-XXX[deg]");

  const int offset = 2;
  int width_radius = (this_rect.width() / 2) - text_width - offset;
  int height_radius = (this_rect.height() / 2) - (text_height * 2) - offset;

  // 円の描画
  painter.setPen(QColor(Qt::gray));
  size_t radius = min(width_radius, height_radius);
  QPoint center(this_rect.width() / 2, this_rect.height() / 2);
  int cx = center.x() - radius;
  int cy = center.y() - radius;
  painter.drawEllipse(cx, cy,
                      static_cast<int>(radius * 2.02),
                      static_cast<int>(radius * 2.02));

  // X 軸, Y 軸の描画
  painter.drawLine(offset, center.y(), this_rect.width() - offset, center.y());
  painter.drawLine(center.x(), offset, center.x(), this_rect.height() - offset);

  if (! pimpl->is_parameter_loaded_) {
    painter.setPen(QColor(Qt::black));
    painter.drawText(0, 0, this_rect.width(), this_rect.height() / 2,
                     Qt::AlignVCenter | Qt::AlignHCenter,
                     tr("no range parameters."));
    return;
  }

  // 選択範囲の描画
  // !!! first, last の共通部分をまとめる
  painter.setPen(Qt::black);
  double first_radian = pimpl->index2rad(pimpl->first_index_) + (M_PI / 2.0);
  double last_radian = pimpl->index2rad(pimpl->last_index_) + (M_PI / 2.0);
  QPoint first_point =
    pimpl->calculatePoint(radius + (offset * 2), first_radian);
  QPoint last_point =
    pimpl->calculatePoint(radius + (text_height / 2) + offset, last_radian);
  first_point.setY(-first_point.y());
  first_point += center;
  last_point.setY(-last_point.y());
  last_point += center;

  // !!! 表示用と描画用の角度計算まわりは実装し直すこと
  int first_deg = static_cast<int>(round(first_radian * 180.0 / M_PI)) - 90;
  int last_deg = static_cast<int>(round(last_radian * 180.0 / M_PI)) - 90;

  // 楕円の描画
  painter.setBrush(QColor(0x33, 0x77, 0xff));
  painter.drawPie(cx, cy, radius * 2, radius * 2,
                  (first_deg + 90) * 16, (last_deg - first_deg) * 16);

  painter.drawText(first_point.x() + (offset * 3),
                   first_point.y() - (text_height / 2),
                   text_width, text_height,
                   Qt::AlignLeft | Qt::AlignBottom,
                   tr("%1[deg]").arg(first_deg));

  painter.drawText(last_point.x() - text_width,
                   last_point.y() - (text_height / 2),
                   text_width, text_height,
                   Qt::AlignRight | Qt::AlignBottom,
                   tr("%1[deg]").arg(last_deg));

  painter.end();
}


void cRangeViewWidget::isRangeChanged(int first_index, int last_index)
{
  pimpl->first_index_ = first_index;
  pimpl->last_index_ = last_index;

  repaint();
}


void cRangeViewWidget::setParameter(const qrk::RangeSensorParameter& parameter)
{
  pimpl->parameter_ = parameter;
  pimpl->is_parameter_loaded_ = true;

  repaint();
}

