/**
 *
 * @file src/statistics/ChartView.cpp
 *
 * @copyright 2008-2024 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria,
 *                      Univ. Bordeaux. All rights reserved.
 *
 * @author Luca Bourroux
 * @author Camille Ordronneau
 * @author Johnny Jazeix
 *
 * @date 2024-07-17
 */
#include "ChartView.hpp"

Chart_View::Chart_View(
    QScrollBar &x_scroll,
    QScrollBar &y_scroll,
    QChart *chart,
    QWidget *parent) :
    QChartView(chart, parent),
    _x_scroll(x_scroll), _y_scroll(y_scroll) {
    setFocusPolicy(Qt::FocusPolicy::StrongFocus);

    connect(&x_scroll, &QAbstractSlider::valueChanged, this, &Chart_View::on_x_scroll_changed);
    connect(&y_scroll, &QAbstractSlider::valueChanged, this, &Chart_View::on_y_scroll_changed);
}

void Chart_View::reset_scroll_zoom() {
    _scroll_value = { 0, 0 };
    _factor = 1;
}

void Chart_View::restrict_scroll(bool x, bool y) {
    _restrict_scroll_x = x;
    _restrict_scroll_y = y;
}

void Chart_View::wheelEvent(QWheelEvent *event) {
    _ignore_scrollbar = true;
    chart()->zoomReset();
    auto rect_chart = chart()->mapFromScene(chart()->plotArea()).boundingRect();

    _factor *= event->angleDelta().y() > 0 ? 0.5 : 2;
    _factor = _factor > 1 ? 1 : _factor;

    QRectF rect = chart()->plotArea();
    QPointF c = chart()->plotArea().center();
    if (_restrict_scroll_x) {
        rect.setWidth(_factor * rect.width());
        _scroll_value.setX(rect_chart.width() * (1 - _factor) / 2);
        _x_scroll.setValue(50);
    }
    if (_restrict_scroll_y) {
        rect.setHeight(_factor * rect.height());
        _scroll_value.setY(rect_chart.height() * (1 - _factor) / 2);
        _y_scroll.setValue(50);
    }
    rect.moveCenter(c);
    chart()->zoomIn(rect);
    QChartView::wheelEvent(event);
    _ignore_scrollbar = false;
}

void Chart_View::mousePressEvent(QMouseEvent *event) {
    if (event->button() == Qt::MiddleButton) {
        QApplication::setOverrideCursor(QCursor(Qt::SizeAllCursor));
        _last_mouse_pos = event->pos();
        event->accept();
    }

    QChartView::mousePressEvent(event);
}

void Chart_View::mouseMoveEvent(QMouseEvent *event) {
    // pan the chart with a middle mouse drag
    if (event->buttons() & Qt::MiddleButton) {
        _ignore_scrollbar = true;
        auto dPos = event->pos() - _last_mouse_pos;

        auto s_x = _restrict_scroll_x ? -dPos.x() : 0;
        auto s_y = _restrict_scroll_y ? +dPos.y() : 0;

        auto new_scroll = _scroll_value + QPointF { s_x * _factor, s_y * _factor };
        auto rect = chart()->plotArea();
        auto rect_chart = chart()->mapFromScene(rect).boundingRect();

        if (
            new_scroll.x() >= -1 && new_scroll.y() >= -1 && new_scroll.x() + rect_chart.width() * _factor <= rect_chart.width() + 1 && new_scroll.y() + rect_chart.height() * _factor <= rect_chart.height() + 1) {
            _scroll_value += QPointF { _factor * s_x, _factor * s_y };

            auto v = ((_scroll_value.x() - rect_chart.width() * _factor) / rect_chart.width());
            v += _factor;
            v /= (1 - _factor);

            _x_scroll.setValue(v * 100);

            v = ((_scroll_value.y() - rect_chart.height() * _factor) / rect_chart.height());
            v += _factor;
            v /= (1 - _factor);
            _y_scroll.setValue((1 - v) * 100);
            chart()->scroll(s_x, s_y);
        }

        _last_mouse_pos = event->pos();
        event->accept();

        QApplication::restoreOverrideCursor();
        _ignore_scrollbar = false;
    }

    QChartView::mouseMoveEvent(event);
}

void Chart_View::on_x_scroll_changed(int x) {
    if (_ignore_scrollbar)
        return;
    if (!_restrict_scroll_x)
        return;

    auto rect = chart()->plotArea();
    auto rect_chart = chart()->mapFromScene(rect).boundingRect();

    auto min = rect_chart.left() - 1;
    auto max = rect_chart.right() - rect_chart.width() * _factor + 1;

    auto v = min + (max - min) * (99 - x) * (1.f / 99.f);

    auto new_scroll = max - v;

    chart()->scroll((new_scroll - _scroll_value.x()) / _factor, 0);
    _scroll_value.setX(new_scroll);
}
void Chart_View::on_y_scroll_changed(int x) {
    if (_ignore_scrollbar)
        return;
    if (!_restrict_scroll_y)
        return;

    auto rect = chart()->plotArea();
    auto rect_chart = chart()->mapFromScene(rect).boundingRect();

    auto min = rect_chart.top() + rect_chart.height() * _factor - 1;
    auto max = rect_chart.bottom() + 1;

    auto v = min + (max - min) * x * (1.f / 99.f);

    auto new_scroll = max - v;

    chart()->scroll(0, (new_scroll - _scroll_value.y()) / _factor);
    _scroll_value.setY(new_scroll);
}

void Chart_View::focusInEvent(QFocusEvent *event) {
    Q_EMIT chart_focused();
}

#include "moc_ChartView.cpp"
