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


SHSThermometer::SHSThermometer(QWidget * parent): QWidget(parent) {
	min_ = -30;
	max_ = 30;
	gmin_ = -50;
	gmax_ = 50;
	val_ = ap_ = 0.;
	ro_ = track_ = false;
	setValue(0.);
	calcColor();
	anim.setTargetObject(this);
	anim.setPropertyName("h__anim");
	anim.setDuration(200);
	anim.setEasingCurve(QEasingCurve::OutQuad);
}


SHSThermometer::~SHSThermometer() {
}


void SHSThermometer::resizeEvent(QResizeEvent * ) {
	float w = width(), h = height(), r = qMin(w, h);
	r /= qMax<double>(qMin<double>(7.f, 7.f - h / w), 2.f);
	float hr = r / 2.;
	//float sqrt3_2 = qSqrt(3.) / 2.;
	QPainterPath pt;
	ppath = QPainterPath();
	pt.addEllipse(QPointF(), r - 3., r - 3.);
	ppath |= pt; pt = QPainterPath();
	pt.addEllipse(QPointF(0, -h + r * 1.5 + 3.), hr, hr);
	ppath |= pt; pt = QPainterPath();
	pt.addRect(QRectF(QPointF(-hr, -hr + 3), QPointF(hr, -h + r * 1.5)));
	ppath |= pt;
}


void SHSThermometer::paintEvent(QPaintEvent * ) {
	float w = width(), h = height(), r = qMin<float>(w, h);
	r /= qMax<double>(qMin<double>(7.f, 7.f - h / w), 2.f);
	float hr = r / 2.;
	double thick = qMax(1., hr / 25.);
	QPen pen(Qt::black, thick);
	QPainter p(this);
	p.setRenderHint(QPainter::Antialiasing);
	p.translate(w / 2., h - r);

	double mh = h - r - r - hr;
	if (mh > 5) {

		p.setClipping(true);
		float v = qMax<double>(qMin<double>((ap_ - gmin_) / (gmax_ - gmin_), 1.), 0.);
		QRect cr(-r, r, r+r, -r-r- v* mh);
		p.setClipRect(cr);
		QRadialGradient rgr;
		rgr.setFocalPoint(-hr / 1.5, hr / 1.5);
		rgr.setRadius(r);
		rgr.setColorAt(0., Qt::white);
		rgr.setColorAt(1., color);
		p.fillPath(ppath, QBrush(rgr));
		p.setClipRect(QRect(cr.left(), cr.bottom(), cr.width(), -h));
		QLinearGradient lgr;
		lgr.setStart(-hr, 0.);
		lgr.setFinalStop(hr, 0.);
		lgr.setColorAt(0., Qt::white);
		lgr.setColorAt(1., Qt::transparent);
		p.fillPath(ppath, QBrush(lgr));
		p.setClipping(false);

		p.translate(0., -r);
		QFont f;
		f.setPixelSize(qMin<double>(mh / 4., hr / 2.));
		p.setFont(f);
		double th = double(p.fontMetrics().boundingRect("0").height()) / 4;
		for (int i = int(gmin_); i <= int(gmax_); ++i) {
			double my = -(i - gmin_) / (gmax_ - gmin_) * mh;
			if (i % 10 == 0) {
				pen.setWidthF(thick); p.setPen(pen);
				p.drawLine(-hr, my, -hr / 4., my);
				p.drawText(0, my + th, QString::number(i));
			} else if (i % 5 == 0) {
				pen.setWidthF(thick / 1.5); p.setPen(pen);
				p.drawLine(-hr, my, -hr / 2., my);
			} else {
				pen.setWidthF(thick / 2); p.setPen(pen);
				p.drawLine(-hr, my, -hr / 1.25, my);
			}
		}
		p.translate(0., r);
	}

	p.setBrush(Qt::NoBrush);
	pen.setWidthF(thick); p.setPen(pen);
	p.drawPath(ppath);
}


void SHSThermometer::mouseMoveEvent(QMouseEvent * e) {
	if (e->buttons() == Qt::NoButton || !track_ || ro_) {
		QWidget::mouseMoveEvent(e);
		return;
	}
	float w = width(), h = height(), r = qMin<float>(w, h);
	r /= qMax<double>(qMin<double>(7.f, 7.f - h / w), 2.f);
	float hr = r / 2.;
	double mh = h - r - r - hr;
	if (mh <= 5) return;
	float v = 1. - (e->y() - hr) / mh;
	setValue(gmin_ + v * (gmax_ - gmin_));
}


void SHSThermometer::mousePressEvent(QMouseEvent * e) {
	if (ro_) {
		QWidget::mousePressEvent(e);
		return;
	}
	float w = width(), h = height(), r = qMin<float>(w, h);
	r /= qMax<double>(qMin<double>(7.f, 7.f - h / w), 2.f);
	if (!ppath.contains(e->pos() - QPointF(w / 2., h - r))) {
		QWidget::mousePressEvent(e);
		return;
	}
	track_ = true;
	mouseMoveEvent(e);
}


void SHSThermometer::mouseReleaseEvent(QMouseEvent * e) {
	if (!track_)
		QWidget::mouseReleaseEvent(e);
	track_ = false;
}


QColor mixColor(QColor c0, QColor c1, double a) {
	double h[2] = {c0.hueF(), c1.hueF()};
	double s[2] = {c0.saturationF(), c1.saturationF()};
	double v[2] = {c0.valueF(), c1.valueF()};
	a = qMin(qMax(a, 0.), 1.);
	double ia = 1. - a;
	return QColor::fromHsvF(h[1] * a + h[0] * ia, s[1] * a + s[0] * ia, v[1] * a + v[0] * ia);
}

void SHSThermometer::calcColor() {
	static QColor col_cold = QColor(110, 200, 255),
				  col_normal = QColor(Qt::green).lighter(120),
				  col_hot = QColor(Qt::red).lighter(130);
	if (ap_ <= m_coldValue) {
		color = col_cold;
		return;
	}
	if (ap_ >= m_hotValue) {
		color = col_hot;
		return;
	}
	if (ap_ >= m_normalValue) {
		color = mixColor(col_normal, col_hot, (ap_ - m_normalValue) / (m_hotValue - m_normalValue));
	} else {
		color = mixColor(col_normal, col_cold, (m_normalValue - ap_) / (m_normalValue - m_coldValue));
	}
	/*double v = qMax<double>(qMin<double>((ap_ - min_) / (max_ - min_), 1.), 0.);
	double hmin = 200, hmax = 20;
	v = (v - 0.5) * 2;
	double hcur = v < 0 ? hmin : hmax;
	if (v < 0) v = -qSqrt(qAbs(v));
	else qSqrt(v);
	v = -v / 2. + 0.5;
	double sinv = sin(v * M_PI);
	color.setHsv(hcur, 255 * (1. - sinv * sinv), 255 * (1. - sinv / 2.));*/
	update();
}


void SHSThermometer::setValue(double v) {
	v = qMax<double>(gmin_, qMin<double>(gmax_, v));
	if (v == value()) return;
	val_ = v;
	calcColor();
	emit valueChanged(v);
	animate();
}


void SHSThermometer::setMinimum(double v) {
	if (v == minimum()) return;
	min_ = v;
	calcColor();
}


void SHSThermometer::setMaximum(double v) {
	if (v == maximum()) return;
	max_ = v;
	calcColor();
}


void SHSThermometer::setGradMinimum(double v) {
	if (v == gradMinimum()) return;
	gmin_ = v;
	calcColor();
	setValue(val_);
}


void SHSThermometer::setGradMaximum(double v) {
	if (v == gradMaximum()) return;
	gmax_ = v;
	calcColor();
	setValue(val_);
}


void SHSThermometer::setReadOnly(bool y) {
	ro_ = y;
}


void SHSThermometer::s_anim(double v) {
	ap_ = v;
	calcColor();
	update();
}


void SHSThermometer::animate() {
	anim.stop();
	anim.setStartValue(g_anim());
	anim.setEndValue(val_);
	anim.start();
}


void SHSThermometer::setColdValue(double v) {
	m_coldValue = v;
	calcColor();
}


void SHSThermometer::setNormalValue(double v) {
	m_normalValue = v;
	calcColor();
}


void SHSThermometer::setHotValue(double v) {
	m_hotValue = v;
	calcColor();
}
