/*
Copyright (c) 2006-2009, Tom Thielicke IT Solutions

SPDX-License-Identifier: GPL-2.0-only
*/

/****************************************************************
**
** Implementation of the FingerWidget class
** File name: fingerwidget.cpp
**
****************************************************************/

#include <QCoreApplication>
#include <QLineF>
#include <QPainter>
#include <QPen>
#include <QRectF>
#include <QSettings>
#include <QSqlQuery>
#include <QVariant>

#include "def/defines.h"
#include "fingerwidget.h"

FingerWidget::FingerWidget(QWidget* parent)
    : QWidget(parent)
    , fingerSelected(-1)
{
// Get language
#if APP_PORTABLE
    QSettings settings(
        QCoreApplication::applicationDirPath() + "/portable/settings.ini",
        QSettings::IniFormat);
#else
    QSettings settings;
#endif
    settings.beginGroup("main");
    languageLayout
        = settings.value("language_layout", t10::app_std_language_layout)
              .toString();
    settings.endGroup();

    getChartValues();

    setMouseTracking(true);
}

void FingerWidget::getChartValues()
{
    QSqlQuery query;
    fingerRates.clear();
    fingerOccurs.clear();
    fingerErrors.clear();
    fingerRanks.clear();
    fingerX1.clear();
    fingerY1.clear();
    fingerX2.clear();
    fingerY2.clear();
    for (int i = 0; i < 9; i++) {
        fingerRates.append(0);
        fingerOccurs.append(0);
        fingerErrors.append(0);
        fingerRanks.append(0);
        fingerX1.append(0);
        fingerY1.append(0);
        fingerX2.append(0);
        fingerY2.append(0);
    }
    // SQL: all lessons sorted by id and a left joint to the number of
    // lessons done by the user
    if (!query.exec(
            "SELECT keyboard_grids.finger,  "
            "SUM(user_chars.user_char_target_errornum), "
            "SUM(user_chars.user_char_occur_num), "
            "((SUM(user_chars.user_char_target_errornum) * 1.0) / "
            "(SUM(user_chars.user_char_occur_num) * 1.0)) * 100.0 "
            "FROM user_chars "
            "LEFT JOIN keyboard_layouts ON "
            "keyboard_layouts.unicode = user_chars.user_char_unicode AND "
            "keyboard_layouts.layout = '"
            + languageLayout
            + "' "
              "LEFT JOIN keyboard_grids ON "
              "keyboard_grids.key =  keyboard_layouts.grid AND "
              "keyboard_grids.layout_country = '"
            + languageLayout.left(2)
            + "' "
              "WHERE user_char_occur_num > 0 "
              "GROUP BY keyboard_grids.finger "
              "ORDER BY "
              "((SUM(user_chars.user_char_target_errornum) * 1.0) / "
              "(SUM(user_chars.user_char_occur_num) * 1.0)) * 100.0 DESC "
              ";")) {
        return;
    }
    // Read all datasets to list items
    double ratePrevious = -1;
    int currentRank = 9; // Real: 0-8
    while (query.next()) {

        if (query.value(0).toInt() < 0 || query.value(0).toInt() > 8) {
            break;
        }
        if (ratePrevious != query.value(3).toDouble()) {
            currentRank--;
        }
        if (query.value(3).toDouble() == 0) {
            fingerRanks[query.value(0).toInt()] = 0;
        } else {
            fingerRanks[query.value(0).toInt()] = currentRank;
        }
        ratePrevious = query.value(3).toDouble();

        fingerOccurs[query.value(0).toInt()] = query.value(2).toInt();
        fingerErrors[query.value(0).toInt()] = query.value(1).toInt();
        fingerRates[query.value(0).toInt()] = query.value(3).toInt();
    }

    fingerNames << QObject::tr("Left little finger")
                << QObject::tr("Left ring finger")
                << QObject::tr("Left middle finger")
                << QObject::tr("Left forefinger")
                << QObject::tr("Right forefinger")
                << QObject::tr("Right middle finger")
                << QObject::tr("Right ring finger")
                << QObject::tr("Right little finger") << QObject::tr("Thumb");

    update();
}

void FingerWidget::paintEvent([[maybe_unused]] QPaintEvent* event)
{
    double currentPos;
    double additionalWidth;
    double height = static_cast<double>(this->height());
    double modWidth = (static_cast<double>(this->width()) - 40.0) / 10.0;
    for (int i = 0; i < 9; i++) {
        if (i == 8) {
            currentPos = 4.0;
            additionalWidth = modWidth;
        } else {
            if (i > 3) {
                currentPos = i + 2.0;
            } else {
                currentPos = i;
            }
            additionalWidth = 0.0;
        }
        fingerX1[i] = 20.0 + currentPos * modWidth;
        fingerX2[i]
            = 20.0 + currentPos * modWidth + modWidth + additionalWidth - 4.0;
        fingerY1[i] = (height / 2.0) - 96.0;
        fingerY2[i] = height - 50.0;
    }
    drawHeadline();
    drawFingers();
}

void FingerWidget::mouseMoveEvent(QMouseEvent* event)
{
    fingerSelected = -1;

    double pos_x = static_cast<double>(event->pos().x());
    double pos_y = static_cast<double>(event->pos().y());
    for (int x = 0; x < 9; x++) {
        if (fingerX1[x] < pos_x && pos_x < fingerX2[x] && fingerY1[x] < pos_y
            && pos_y < fingerY2[x]) {
            fingerSelected = x;
        }
    }

    repaint();
}

void FingerWidget::drawFinger(int currentFinger, double currentPos,
    double widgetLeft, double widgetTop, double currentTop, double currentWidth,
    double widgetHeight, double xUnit)
{
    QPainter painter(this);

    painter.setRenderHint(QPainter::Antialiasing, true);

    painter.setFont(QFont(t10::font_standard, t10::font_size_finger));

    QPen pen((fingerSelected == currentFinger ? QColor(255, 255, 255)
                                              : QColor(249, 126, 50)),
        5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);

    painter.setPen(pen);

    int startAngle = 30 * 16;
    int spanAngle = 120 * 16;

    painter.drawArc(QRectF(widgetLeft + (xUnit * currentPos) + 10.0, currentTop,
                        currentWidth, 2.0 * currentWidth),
        startAngle, spanAngle);

    painter.drawLine(
        QLineF(widgetLeft + (xUnit * currentPos) + 10.0 + (currentWidth / 15.0),
            currentTop + (currentWidth / 2.0),
            widgetLeft + (xUnit * currentPos) + 10.0 + (currentWidth / 15.0),
            widgetTop + widgetHeight - 80.0));

    painter.drawLine(QLineF(widgetLeft + (xUnit * currentPos) + currentWidth
            + 10.0 - (currentWidth / 15.0),
        currentTop + (currentWidth / 2.0),
        widgetLeft + (xUnit * currentPos) + currentWidth + 10.0
            - (currentWidth / 15.0),
        widgetTop + widgetHeight - 80.0));

    painter.setPen(QColor(fingerRanks.at(currentFinger) * 27,
        fingerRanks.at(currentFinger) * 14, fingerRanks.at(currentFinger) * 5));

    painter.drawText(QRectF(widgetLeft + (xUnit * currentPos) + 10.0,
                         currentTop - 26.0, currentWidth, 20.0),
        Qt::AlignCenter | Qt::AlignBottom,
        QString::number(fingerRates.at(currentFinger)) + " %");
}

void FingerWidget::drawHeadline()
{
    QPainter painter(this);

    painter.setRenderHint(QPainter::Antialiasing, true);

    painter.setPen(QColor(0, 0, 0));

    painter.setFont(QFont(t10::font_standard, t10::font_size_finger, 75));

    double modWidth = static_cast<double>(this->width()) - 40.0;
    painter.drawText(QRectF(20.0, 30.0, modWidth, 20.0),
        Qt::AlignCenter | Qt::AlignBottom, tr("Error rates of your fingers"));

    painter.setFont(QFont(t10::font_standard, t10::font_size_progress));

    painter.drawText(QRectF(20.0, static_cast<double>(this->height()) - 34.0,
                         modWidth, 16.0),
        Qt::AlignCenter | Qt::AlignBottom,
        tr("The error rate is based on the recorded characters and the "
           "current selected keyboard layout."));

    if (fingerSelected == -1)
        return;

    drawTooltip(&painter,
        fingerX1[fingerSelected]
            + ((fingerX2[fingerSelected] - fingerX1[fingerSelected]) / 2.0)
            - 4.0,
        fingerY1[fingerSelected] - 74.0,
        fingerNames[fingerSelected] + "\n" + tr("Error Rate:") + " "
            + QString::number(fingerRates[fingerSelected]) + " %" + "\n"
            + tr("Frequency:") + " "
            + QString::number(fingerOccurs[fingerSelected]) + "\n"
            + tr("Errors:") + " "
            + QString::number(fingerErrors[fingerSelected]));
}

void FingerWidget::drawTooltip(
    QPainter* painter, double x, double y, QString message)
{

    double yOffset = -4.0;
    double newX = x;
    if (x < 72) {
        newX = 72;
    }
    if (x > (static_cast<double>(this->width()) - 74.0)) {
        newX = static_cast<double>(this->width()) - 74.0;
    }

    painter->setRenderHint(QPainter::Antialiasing, false);
    painter->setFont(QFont(t10::font_standard, t10::font_size_progress));
    painter->setPen(QColor(0, 0, 0));

    painter->setBrush(QColor(255, 255, 255));
    painter->drawRect(QRectF(newX - 70.0, y + yOffset, 140.0, 66.0));

    painter->drawText(QRectF(newX - 70.0, y + yOffset, 140.0, 66.0),
        Qt::AlignCenter | Qt::AlignVCenter, message);
}

void FingerWidget::drawFingers()
{
    double widgetLeft = 10.0;
    double widgetTop = 30.0;
    double widgetWidth = static_cast<double>(this->width()) - 40.0;
    double widgetHeight = static_cast<double>(this->height());
    double xUnit = widgetWidth / 10.0;

    int currentFinger = 0;
    double currentPos = 0.0;
    double currentTop = widgetTop + (widgetHeight / 2.0) - 20.0;
    double currentWidth = xUnit - 2.0;
    drawFinger(currentFinger, currentPos, widgetLeft, widgetTop, currentTop,
        currentWidth, widgetHeight, xUnit);

    currentFinger = 1;
    currentPos = 1.0;
    currentTop = widgetTop + (widgetHeight / 2.0) - 90.0;
    drawFinger(currentFinger, currentPos, widgetLeft, widgetTop, currentTop,
        currentWidth, widgetHeight, xUnit);

    currentFinger = 2;
    currentPos = 2.0;
    currentTop = widgetTop + (widgetHeight / 2.0) - 110.0;
    drawFinger(currentFinger, currentPos, widgetLeft, widgetTop, currentTop,
        currentWidth, widgetHeight, xUnit);

    currentFinger = 3;
    currentPos = 3.0;
    currentTop = widgetTop + (widgetHeight / 2.0) - 70.0;
    drawFinger(currentFinger, currentPos, widgetLeft, widgetTop, currentTop,
        currentWidth, widgetHeight, xUnit);

    currentFinger = 8;
    currentPos = 4.0;
    currentTop = widgetTop + (widgetHeight / 2.0) + 70.0;
    drawFinger(currentFinger, currentPos, widgetLeft, widgetTop, currentTop,
        currentWidth, widgetHeight, xUnit);

    currentFinger = 8;
    currentPos = 5.0;
    currentTop = widgetTop + (widgetHeight / 2.0) + 70.0;
    drawFinger(currentFinger, currentPos, widgetLeft, widgetTop, currentTop,
        currentWidth, widgetHeight, xUnit);

    currentFinger = 4;
    currentPos = 6.0;
    currentTop = widgetTop + (widgetHeight / 2.0) - 70.0;
    drawFinger(currentFinger, currentPos, widgetLeft, widgetTop, currentTop,
        currentWidth, widgetHeight, xUnit);

    currentFinger = 5;
    currentPos = 7.0;
    currentTop = widgetTop + (widgetHeight / 2.0) - 110.0;
    drawFinger(currentFinger, currentPos, widgetLeft, widgetTop, currentTop,
        currentWidth, widgetHeight, xUnit);

    currentFinger = 6;
    currentPos = 8.0;
    currentTop = widgetTop + (widgetHeight / 2.0) - 90.0;
    drawFinger(currentFinger, currentPos, widgetLeft, widgetTop, currentTop,
        currentWidth, widgetHeight, xUnit);

    currentFinger = 7;
    currentPos = 9.0;
    currentTop = widgetTop + (widgetHeight / 2.0) - 20.0;
    drawFinger(currentFinger, currentPos, widgetLeft, widgetTop, currentTop,
        currentWidth, widgetHeight, xUnit);
}
