/*
 * Copyright (C) 2023, KylinSoft Co., Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 *
**/
#include "lockslider.h"
#include <QPainter>
#include <QToolTip>
#include <QEvent>
#include <QMouseEvent>
#include <QDebug>

static const int node_radius = 5;
static const int handle_radius = 8;
static const int spaceing = handle_radius+2;

LockSlider::LockSlider(QStringList list, QWidget *parent) :
    KSlider(parent),
    scaleList(list)
{
    this->setMinimumHeight(50);
    this->setMaximumHeight(100);
    this->installEventFilter(this);
    mouseLeftBtnIsPressed = false;
}

LockSlider::~LockSlider()
{

}

void LockSlider::paintEvent(QPaintEvent *e)
{
    KSlider::paintEvent(e);

    auto painter = new QPainter(this);
    painter->setBrush(QBrush(QColor(QPalette::Base)));
    auto rect = this->geometry();
    int numTicks = (maximum() - minimum()) / tickInterval();
    painter->setFont(this->font());
    int total = 0;
    QFontMetrics fontMetrics = QFontMetrics(painter->font());
    for (int i = 0; i <= numTicks; i++) {
        QRect fontRect = fontMetrics.boundingRect(scaleList.at(i));
        total += fontRect.width();
    }
    const float interval = (rect.width() - spaceing*2) / float(numTicks);

    if (this->orientation() == Qt::Horizontal) {
        int fontHeight = fontMetrics.height();
        float tickY = rect.height() / 2.0 + fontHeight;
        float preTickEndX = 0.0;
        bool drawText = true;
        for (int i = 0; i <= numTicks; i++) {
            if (!drawText) {
                drawText = true;
                continue;
            }
            drawText = false;
            float tickX = spaceing + i * interval;
            tickX = tickX - fontMetrics.boundingRect(scaleList.at(i)).width() / 2;
            if (i == numTicks) {
                while (tickX + fontMetrics.boundingRect(scaleList.at(i)).width() >= this->width()) {
                    tickX = tickX - 1;
                }
                if (tickX < preTickEndX + 4) {
                    QFont fontText;
                    int pointSize = painter->font().pointSize() - 1;
                    if (pointSize < 1) {
                        pointSize = 1;
                    }
                    fontText.setPointSize(pointSize);
                    painter->setFont(fontText);
                    fontMetrics = QFontMetrics(painter->font());
                    if (pointSize > 1) { //避免 == 1死循环
                        i--;
                        continue;
                    }
                }
            } else if (i == 0){
                if (tickX < 0) {
                    tickX = 0;
                }
            }
            preTickEndX = tickX + fontMetrics.boundingRect(scaleList.at(i)).width();
            painter->drawText(QPointF(tickX, tickY),
                              this->scaleList.at(i));
        }
    }
    painter->end();
}

void LockSlider::initNodePoint()
{
    nodePointList.clear();
    int numTicks = (maximum() - minimum()) / tickInterval();
    float interval = (this->rect().width() - spaceing*2) / float(numTicks);
    for (int i = 0; i < scaleList.size(); ++i) {
        QPoint nodePoint(spaceing + i * interval, this->height()/2);
        nodePointList.append(nodePoint);
    }
}

bool LockSlider::eventFilter(QObject *watched, QEvent *event)
{
    if (watched == this) {
        QMouseEvent *me = static_cast<QMouseEvent*>(event);
        if (event->type() == QEvent::HoverMove && !mouseLeftBtnIsPressed) {
            initNodePoint();
            QPoint mousePos = me->pos();
            for (int i = 0; i < nodePointList.size(); ++i) {
                QPoint point = nodePointList.at(i);
                int radius = node_radius;
                if (this->value() == i + 1) {
                    radius = handle_radius;
                }
                if (isContains(mousePos, point, radius)) {
                    showTooltip(i);
                    break;
                } else {
                    if (i == nodePointList.size() - 1) {
                        QToolTip::hideText();
                    }
                }
            }
        }
    }
    return KSlider::eventFilter(watched, event);
}

bool LockSlider::isContains(QPoint p1, QPoint p2, int radius)
{
    return (p2.x() - radius <= p1.x()
         && p2.x() + radius >= p1.x()
         && p2.y() - radius <= p1.y()
         && p2.y() + radius >= p1.y());
}

void LockSlider::mousePressEvent(QMouseEvent *e)
{
    KSlider::mousePressEvent(e);
    initNodePoint();
    if (e->button() == Qt::LeftButton) {
        mouseLeftBtnIsPressed = true;
        showTooltip(this->value() - 1);
    }
    return;
}

void LockSlider::mouseReleaseEvent(QMouseEvent *e)
{
    KSlider::mouseReleaseEvent(e);
    if (e->button() == Qt::LeftButton) {
        mouseLeftBtnIsPressed = false;
        showTooltip(this->value() - 1);
        QPoint mousePos = e->pos();
        for (int i = 0; i < nodePointList.size(); ++i) {
            QPoint point = nodePointList.at(i);
            int radius = node_radius;
            if (this->value() == i + 1) {
                radius = handle_radius;
            }
            if (isContains(mousePos, point, radius)) {
                break;
            } else {
                if (i == nodePointList.size() - 1) {
                    QToolTip::hideText();
                }
            }
        }
    }
    return;
}

void LockSlider::mouseMoveEvent(QMouseEvent *e)
{
    KSlider::mouseMoveEvent(e);
    if (e->buttons() & Qt::LeftButton) {
        showTooltip(this->value() - 1);
    }
    return;
}

void LockSlider::showTooltip(const int &num)
{
    initNodePoint();
    int textLeftMargin = 8;
    int textTopMargin = 12;
    QPoint m_point  = this->mapToGlobal(nodePointList.at(num));
    QFontMetrics fontMetrics = QFontMetrics(this->font());
    QRect fontRect = fontMetrics.boundingRect(scaleList.at(num));
    QToolTip::showText(m_point - QPoint(fontRect.width()/2 + textLeftMargin, 20 + textTopMargin*2 + fontRect.height()), scaleList.at(num));
    return;
}
