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

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

/****************************************************************
**
** Implementation of the LessonTableSql class
** File name: lessontablesql.h
**
****************************************************************/

#include <QAbstractItemView>
#include <QChar>
#include <QColor>
#include <QCoreApplication>
#include <QDateTime>
#include <QFont>
#include <QHBoxLayout>
#include <QItemSelectionModel>
#include <QList>
#include <QObject>
#include <QPen>
#include <QString>
#include <QTextCharFormat>
#include <QTextCursor>
#include <QTextEdit>
#include <QTextFrame>
#include <QTextFrameFormat>
#include <QTextTable>
#include <QTextTableFormat>
#include <QVBoxLayout>
#include <cmath>

#include "lessontablesql.h"

LessonSqlModel::LessonSqlModel(int row, int type, QWidget* parent)
    : QSqlQueryModel(parent)
    , lastIdInserted(row)
    , lastTypeInserted(type)
    , parentWidget(parent)
{
}

QVariant LessonSqlModel::data(const QModelIndex& index, int role) const
{
    QVariant value = QSqlQueryModel::data(index, role);
    QDateTime timeStamp;
    static int coloredRow = -1;
    QString lessonName;
    if (value.isValid() && role == Qt::DisplayRole) {
        if (index.column() == 0) {
            // Expand lesson name
            lessonName = value.toString();
            return lessonName; //.prepend(tr("Uebungslektion "));
        }
        if (index.column() == 1) {
            // Convert time stamp into a readable format
            timeStamp
                = QDateTime::fromString(value.toString(), "yyyyMMddhhmmss");
            return timeStamp.toString(QLocale::system().dateTimeFormat(
                QLocale::FormatType::ShortFormat));
        }
        if (index.column() == 2) {
            int timeSec = value.toInt();
            // Show time length in seconds or minutes
            if (timeSec < 60) {
                return tr("%L1 s").arg(timeSec);
            }

            double timeMin = floor((timeSec / 60.0) / 0.1 + 0.5) * 0.1;
            return tr("%L1 min").arg(timeMin, 0, 'f', 1);
        }
        if (index.column() == 5) {
            // Rate
            return tr("%L1 %").arg(value.toDouble(), 0, 'f', 1);
        }
        if (index.column() == 6) {
            // There is never grade smaller than zero
            return QString("%1").arg(value.toInt());
        }
        if (index.column() == 7) {
            double lessonGrade = value.toDouble();
            // There is never grade smaller than zero
            if (lessonGrade < 0) {
                lessonGrade = 0;
            }
            return tr("%n point(s)", "", static_cast<int>(lessonGrade));
        }
        if (index.column() == 8 && value.toInt() == lastIdInserted) {
            // Current row has to be colored
            coloredRow = index.row();
            return QString::number(coloredRow);
        }
        if (lastIdInserted == 0) {
            // No row is colored
            coloredRow = -1;
        }
    }
    if (role == Qt::FontRole && (index.column() == 0 || index.column() == 7)) {
        // Show the lesson number bold
        QFont font;
        font = parentWidget->font();
        font.setBold(true);
        return QVariant::fromValue(font);
    }

    return value;
}

LessonTableSql::LessonTableSql(int row, int type, QWidget* parent)
    : QWidget(parent)
    , comboFilter(new QComboBox())
    , model(new LessonSqlModel(row, type, this))
    , view(new QTableView())
    , headerview(view->horizontalHeader())
    , previousColumnIndex(-1)
    , whereClausel("")
{
    // Create filter headline
    labelFilter = new QLabel(tr("Show: "));

    comboFilter->insertItem(0, tr("All Lessons"));
    comboFilter->insertItem(1, tr("Training Lessons"));
    comboFilter->insertItem(2, tr("Open Lessons"));
    comboFilter->insertItem(3, tr("Own Lessons"));

    view->setModel(model);
    // User should not be able to select a row
    view->setSelectionMode(QAbstractItemView::NoSelection);
    // Hide the lesson id column

    headerview->setStretchLastSection(true);
    headerview->setSectionResizeMode(QHeaderView::Interactive);
    headerview->setSortIndicatorShown(true);

    // Set the sql query (every lesson, it's properties and rating)
    sortColumn(-1);

    // Set a horizonal layout
    QHBoxLayout* filterLayout = new QHBoxLayout;
    filterLayout->addStretch(1);
    filterLayout->addWidget(labelFilter);
    filterLayout->addWidget(comboFilter);
    QVBoxLayout* mainLayout = new QVBoxLayout;
    mainLayout->addLayout(filterLayout);
    mainLayout->addWidget(view);
    // Pass layout to parent widget (this)
    this->setLayout(mainLayout);

    connect(headerview, &QHeaderView::sectionClicked, this,
        &LessonTableSql::sortColumn);
    connect(comboFilter, &QComboBox::activated, this,
        &LessonTableSql::changeFilter);
}

void LessonTableSql::sortColumn(int columnindex)
{
    // Select columnname from columnindex
    switch (columnindex) {
    case 0:
        columnName = "user_lesson_lesson";
        break;
    case 1:
    default:
        columnName = "user_lesson_timestamp";
        columnindex = 1;
        break;
    case 2:
        columnName = "user_lesson_timelen";
        break;
    case 3:
        columnName = "user_lesson_tokenlen";
        break;
    case 4:
        columnName = "user_lesson_errornum";
        break;
    case 5:
        columnName = "user_lesson_rate";
        break;
    case 6:
        columnName = "user_lesson_cpm";
        break;
    case 7:
        columnName = "user_lesson_grade";
        break;
    }
    if (previousColumnIndex != columnindex) {
        isDesc = true;
        headerview->setSortIndicator(columnindex, Qt::DescendingOrder);
    } else {
        isDesc = (headerview->sortIndicatorOrder() != Qt::AscendingOrder);
    }
    previousColumnIndex = columnindex;
    if (columnindex != -1) {
        model->lastIdInserted = 0;
    }
    // Call new query
    setQueryOrder(columnName, isDesc);
}

void LessonTableSql::changeFilter(int rowindex)
{
    // Select columnname from columnindex
    switch (rowindex) {
    case 0:
        whereClausel = "";
        break;
    case 1:
    default:
        whereClausel = "WHERE user_lesson_type = 0 ";
        break;
    case 2:
        whereClausel = "WHERE user_lesson_type = 1 ";
        break;
    case 3:
        whereClausel = "WHERE user_lesson_type = 2 ";
        break;
    }
    model->lastIdInserted = 0;
    // Call new query
    setQueryOrder(columnName, isDesc);
}

void LessonTableSql::setQueryOrder(QString columnname, bool isdesc)
{

    QString descText = isdesc ? " DESC" : " ASC";

    model->clear();

    // Set the sql query (every lesson, it's properties and rating)
    model->setQuery(
        "SELECT user_lesson_name, user_lesson_timestamp, "
        "user_lesson_timelen, user_lesson_tokenlen, "
        "user_lesson_errornum, "
        "((user_lesson_errornum * 100.0) / "
        " user_lesson_strokesnum) AS user_lesson_rate, "
        "(user_lesson_strokesnum / "
        "(user_lesson_timelen / 60.0)) AS user_lesson_cpm, "
        "(((user_lesson_strokesnum - (20.0 * user_lesson_errornum)) / "
        "(user_lesson_timelen / 60.0)) * 0.4) AS user_lesson_grade, "
        "user_lesson_id FROM user_lesson_list "
        + whereClausel + "ORDER BY " + columnname + descText + ";");

    view->setColumnHidden(8, true);
    setModelHeader();
    view->resizeColumnsToContents();
}

void LessonTableSql::setModelHeader()
{
    // Column headers (see sql query)
    model->setHeaderData(0, Qt::Horizontal, tr("Lesson"));
    model->setHeaderData(1, Qt::Horizontal, tr("Time"));
    model->setHeaderData(2, Qt::Horizontal, tr("Duration"));
    model->setHeaderData(3, Qt::Horizontal, tr("Characters"));
    model->setHeaderData(4, Qt::Horizontal, tr("Errors"));
    model->setHeaderData(5, Qt::Horizontal, tr("Rate"));
    model->setHeaderData(6, Qt::Horizontal, tr("Cpm"));
    model->setHeaderData(7, Qt::Horizontal, tr("Score"));

    model->setHeaderData(0, Qt::Horizontal,
        tr("This column shows the names\n"
           "of completed lessons"),
        Qt::ToolTipRole);
    model->setHeaderData(
        1, Qt::Horizontal, tr("Start time of the lesson"), Qt::ToolTipRole);
    model->setHeaderData(
        2, Qt::Horizontal, tr("Total duration of the lesson"), Qt::ToolTipRole);
    model->setHeaderData(3, Qt::Horizontal, tr("Number of characters dictated"),
        Qt::ToolTipRole);
    model->setHeaderData(
        4, Qt::Horizontal, tr("Number of typing errors"), Qt::ToolTipRole);
    model->setHeaderData(5, Qt::Horizontal,
        tr("The error rate is calculated as follows:\n"
           "Errors / Characters\n"
           "The lower the error rate the better!"),
        Qt::ToolTipRole);
    model->setHeaderData(6, Qt::Horizontal,
        tr("\"Cpm\" indicates how many characters per minute\n"
           "were entered on average"),
        Qt::ToolTipRole);
    model->setHeaderData(7, Qt::Horizontal,
        tr("The score is calculated as follows:\n"
           "((Characters - (20 x Errors)) / Duration in minutes) x 0.4\n"
           "\n"
           "Note that slow typing without errors results in a\n"
           "better ranking, than fast typing with several errors!"),
        Qt::ToolTipRole);
}
