#include "ChartView.hpp"

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

	connect(&x_scroll, SIGNAL(valueChanged(int)), this, SLOT(on_x_scroll_changed(int)));
	connect(&y_scroll, SIGNAL(valueChanged(int)), this, SLOT(on_y_scroll_changed(int)));
}

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) {
	emit chart_focused();
}
