#include <QPainter>
#include <QStyleOption>
#include <QApplication>
#include <QBoxLayout>
#include <QLayout>
#include <qmath.h>
#include "clock.h"


SHSClock::_NumericCircle::_NumericCircle(QObject * parent_): QWidget() {
	parent = parent_;
	ro_ = false;
	aprev = -1;
	//setMouseTracking(true);
}


void SHSClock::_NumericCircle::paintEvent(QPaintEvent * event) {
	QPainter p(this);
	float w = width(), h = height(), r = qMin(w, h) / 2.f, thick = qMax(1., r / 80.);
	r -= thick;
	p.translate(w / 2.f, h / 2.f);
	float offset = 0.f;
	offsets.clear();
	p.setRenderHint(QPainter::Antialiasing);
	p.setPen(QPen(Qt::black, thick));
	p.drawEllipse(QPointF(), r - 1, r - 1);
	QFont f;
	f.setPixelSize(r / 5.7);
	p.setFont(f);
	r /= 1.1;
	float sel_ang = 0.;
	foreach (const QVector<FSPair> & cml, marks) {
		int ms = 0;
		foreach (const FSPair & m, cml) {
			QRect br = p.fontMetrics().boundingRect(m.second);
			ms = qMax(ms, qMax(br.width(), br.height()));
		}
		float cr = r - offset + ms * 0.2;
		p.setOpacity(0.5);
		p.setPen(QPen(Qt::black, thick / 2.));
		p.drawEllipse(QPointF(), cr, cr);
		p.setOpacity(1);
		float hms = ms / 2.f + 1.f;
		QPointF hmsp(hms, hms);
		foreach (const FSPair & m, cml) {
			float cr = r - hms - offset;
			f.setBold(false);
			if (current.toInt() == m.second.toInt()) {
				sel_ang = m.first;
				f.setBold(true);
				p.save();
				p.setPen(Qt::NoPen);
				p.setBrush(QColor(128, 128, 255));
				p.setOpacity(0.5);
				p.drawEllipse(QPointF(cr * sin(sel_ang), -cr * cos(sel_ang)), r / 7., r / 7.);
				p.restore();
			}
			p.setFont(f);
			QPointF mp(cr * sin(m.first) + 1., -cr * cos(m.first) + 1.);
			p.drawText(QRectF(mp - hmsp, QSizeF(ms, ms)), Qt::AlignCenter, m.second);
		}
		offsets << ms * 1.4f;
		offset += ms * 1.4f;
	}
	QPen pen = p.pen();
	pen.setCapStyle(Qt::RoundCap);
	foreach (const Arrow & a, arrows) {
		pen.setWidthF(r * a.thickness);
		p.setPen(pen);
		p.setOpacity(a.alpha);
		p.drawLine(QPointF(), QPointF(r * sin(a.ap_), -r * cos(a.ap_)) * a.length);
	}
}


void SHSClock::_NumericCircle::mouseMoveEvent(QMouseEvent * e) {
	if (offsets.size() != marks.size() || ro_) return;
	float w = width(), h = height(), r = qMin(w, h) / 2.f;
	QPointF cp = QPointF(e->pos()) - QPointF(w, h) / 2.f;
	float l = qSqrt(cp.x() * cp.x() + cp.y() * cp.y());
	float a = atan2(-cp.x(), cp.y()) + M_PI;
	r /= 1.1;
	float rmin = r, rmax = r;
	//qDebug() << a;
	if (marks.size() == 1) {
		int ang = qRound((a / (2*M_PI)) * 60.), ca = ang;
		if (e->type() == QEvent::MouseButtonPress) {
			ca = qRound(ca / 5.) * 5;
			aprev = ang;
		}
		if (e->type() == QEvent::MouseMove) {
			if (ang == aprev)
				ca = qRound(ca / 5.) * 5;
			else
				aprev = -1;
		}
		QString c = QString::number(ca % 60);
		if (current != c) {
			current = c;
			QMetaObject::invokeMethod(parent, "numSelected");
		}
	} else {
		for (int i = 0; i < offsets.size(); ++i) {
			rmax = rmin;
			rmin -= offsets[i];
			if (l > rmax || l < rmin) continue;
			QVector<FSPair> & cml(marks[i]);
			float da = 2*M_PI / cml.size(), hda = da / 2.f;
			float ca = a + hda;
			foreach (const FSPair & m, cml) {
				if (m.first + da > 2*M_PI) {
					if ((ca + 2*M_PI < m.first || ca + 2*M_PI > m.first + da) &&
						(ca < m.first || ca > m.first + da)) continue;
				} else
					if (ca < m.first || ca > m.first + da) continue;
				//qDebug() << "catch" << m.second;
				if (current != m.second) {
					current = m.second;
					QMetaObject::invokeMethod(parent, "numSelected");
				}
				return;
			}
		}
	}
	//qDebug() << cp;
}




SHSClock::SHSClock(QWidget * parent): QWidget(parent), _hours(this), _minutes(this) {
	init();
}


SHSClock::~SHSClock() {
}


void SHSClock::init() {
	setLayout(new QBoxLayout(QBoxLayout::LeftToRight));
	_hours.marks.resize(2);
	for (int i = 1; i <= 12; ++i) {
		_hours.marks[0] << FSPair(i / 12. * 2*M_PI, QString::number((i + 12) % 24).rightJustified(2, '0'));
		_hours.marks[1] << FSPair(i / 12. * 2*M_PI, QString::number(i));
	}
	_hours.arrows << (Arrow){0.03, 0.35, 0.66, 0., 0.} << (Arrow){0.075, 0.275, 1., 0., 0.};
	_minutes.marks.resize(1);
	for (int i = 5; i <= 60; i += 5)
		_minutes.marks[0] << FSPair(i / 60. * 2*M_PI, QString::number(i % 60));
	_minutes.arrows << (Arrow){0.075, 0.275, 0.66, 0., 0.} << (Arrow){0.03, 0.35, 1., 0., 0.};
	QFont f(font());
	f.setBold(true);
	f.setPointSizeF(f.pointSizeF() * 1.5);
	_hours.setFont(f);
	_minutes.setFont(f);
	layout()->addWidget(&_hours);
	layout()->addWidget(&_minutes);
	anim[0].setTargetObject(this);
	anim[0].setPropertyName("h__anim0");
	anim[0].setDuration(200);
	anim[0].setEasingCurve(QEasingCurve::OutQuad);
	anim[1].setTargetObject(this);
	anim[1].setPropertyName("h__anim1");
	anim[1].setDuration(200);
	anim[1].setEasingCurve(QEasingCurve::OutQuad);
}


QTime SHSClock::time() const {
	return QTime(_hours.current.toInt(), _minutes.current.toInt(), 0);
}


int SHSClock::heightForWidth(int) const {
	return width();
}


bool SHSClock::hasHeightForWidth() const {
	return true;
}


void SHSClock::animate() {
	anim[0].stop();
	anim[0].setStartValue(g_anim0());
	anim[0].setEndValue(_hours.arrows[0].angle);
	anim[0].start();
	anim[1].stop();
	anim[1].setStartValue(g_anim1());
	anim[1].setEndValue(_hours.arrows[1].angle);
	anim[1].start();
}


void SHSClock::s_anim0(float v) {
	_hours.arrows[0].ap_ = _minutes.arrows[1].ap_ = v;
	update();
}


void SHSClock::s_anim1(float v) {
	_hours.arrows[1].ap_ = _minutes.arrows[0].ap_ = v;
	update();
}


void SHSClock::numSelected() {
	_hours.arrows[1].angle = (_hours.current.toInt() % 12) / 12. * 2*M_PI;
	_hours.arrows[0].angle = _minutes.current.toInt() / 60. * 2*M_PI;
	_minutes.arrows[0].angle = _hours.arrows[1].angle;
	_minutes.arrows[1].angle = _hours.arrows[0].angle;
	animate();
	emit timeChanged(time());
}


void SHSClock::setTime(QTime t) {
	if (t == time()) return;
	_hours.current.setNum(t.hour());
	_minutes.current.setNum(t.minute());
	numSelected();
}


void SHSClock::setReadOnly(bool y) {
	_hours.ro_ = _minutes.ro_ = y;
}
