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

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

/****************************************************************
**
** Implementation of the CharTableSql class
** File name: chartablesql.cpp
**
****************************************************************/

#include <QAbstractItemView>
#include <QColor>
#include <QFont>
#include <QHBoxLayout>
#include <QItemSelectionModel>
#include <QMessageBox>
#include <QObject>
#include <QTableView>
#include <QVBoxLayout>

#include "chartablesql.h"
#include "def/defines.h"
#include "startsql.h"
#include "widget/errormessage.h"

CharSqlModel::CharSqlModel(QWidget* parent)
    : QSqlQueryModel(parent)
    , parentWidget(parent)
{
}

QVariant CharSqlModel::data(const QModelIndex& index, int role) const
{
    QVariant value = QSqlQueryModel::data(index, role);
    if (value.isValid() && role == Qt::DisplayRole) {
        // First column (character)
        if (index.column() == 0) {
            return value.toChar();
        }
        // Last column (error weight)
        if (index.column() == 4) {
            return tr("%L1 %").arg(value.toDouble(), 0, 'f', 1);
        }
    }
    // Change font of first column to bold
    if (role == Qt::FontRole && index.column() == 0) {
        QFont font;
        font = parentWidget->font();
        font.setFamily("Courier New");
        font.setPointSize(font.pointSize() + 2);
        font.setBold(true);
        return QVariant::fromValue(font);
    }
    // Change font of first column to bold
    if (role == Qt::FontRole && index.column() == 4) {
        QFont font;
        font = parentWidget->font();
        font.setBold(true);
        return QVariant::fromValue(font);
    }
    return value;
}

CharTableSql::CharTableSql(QWidget* parent)
    : QWidget(parent)
    , model(new CharSqlModel(this))
    , previousColumnIndex(-1)
{
    // Create the table view
    QTableView* view = new QTableView;
    view->setModel(model);
    // User should not be able to select a row
    view->setSelectionMode(QAbstractItemView::NoSelection);

    headerview = view->horizontalHeader();

    // Set the sql query (every unicode, it's errors and an error weight)
    sortColumn(4);

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

    // Resize the columns
    view->resizeColumnsToContents();

    buttonReset = new QPushButton(tr("Reset characters"));
    buttonReset->setFixedHeight(20);
    if (model->rowCount() == 0) {
        buttonReset->setEnabled(false);
    }

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

    connect(headerview, &QHeaderView::sectionClicked, this,
        &CharTableSql::sortColumn);
    connect(buttonReset, &QPushButton::clicked, this,
        &CharTableSql::deleteUserChars);
}

void CharTableSql::sortColumn(int columnindex)
{
    // Select columnname from columnindex
    QString columnName;
    switch (columnindex) {
    case 0:
        columnName = "user_char_unicode";
        break;
    case 1:
        columnName = "user_char_target_errornum";
        break;
    case 2:
        columnName = "user_char_mistake_errornum";
        break;
    case 3:
        columnName = "user_char_occur_num";
        break;
    case 4:
    default:
        columnName
            = "(user_char_target_errornum * 100.0) / user_char_occur_num";
        break;
    }
    bool isDesc = true;
    if (previousColumnIndex != columnindex) {
        headerview->setSortIndicator(columnindex, Qt::DescendingOrder);
    } else {
        isDesc = (headerview->sortIndicatorOrder() != Qt::AscendingOrder);
    }
    previousColumnIndex = columnindex;
    // Call new query
    setQueryOrder(columnName, isDesc);
}

void CharTableSql::setQueryOrder(QString columnname, bool isdesc)
{
    if (columnname != "") {
        QString descText = isdesc ? " DESC" : " ASC";

        sql = "SELECT user_char_unicode, user_char_target_errornum, "
              "user_char_mistake_errornum, user_char_occur_num, "
              "((user_char_target_errornum * 100.0) / user_char_occur_num) "
              "AS user_char_weighted FROM user_chars ORDER BY "
            + columnname + descText + ";";
    }
    // Set the sql query (every unicode, it's errors and an error weight)
    model->setQuery(sql);
    setModelHeader();
}

void CharTableSql::setModelHeader()
{
    // Column headers (see sql query)
    model->setHeaderData(0, Qt::Horizontal, tr("Characters"));
    model->setHeaderData(1, Qt::Horizontal, tr("Target Errors"));
    model->setHeaderData(2, Qt::Horizontal, tr("Actual Errors"));
    model->setHeaderData(3, Qt::Horizontal, tr("Frequency"));
    model->setHeaderData(4, Qt::Horizontal, tr("Error Rate"));

    model->setHeaderData(0, Qt::Horizontal,
        tr("This column shows all of the\n"
           "characters typed"),
        Qt::ToolTipRole);
    model->setHeaderData(1, Qt::Horizontal,
        tr("The character was supposed to be typed, but wasn't"),
        Qt::ToolTipRole);
    model->setHeaderData(
        2, Qt::Horizontal, tr("Character was mistyped"), Qt::ToolTipRole);
    model->setHeaderData(3, Qt::Horizontal,
        tr("This column indicates the total frequency of each\n"
           "character shown"),
        Qt::ToolTipRole);
    model->setHeaderData(4, Qt::Horizontal,
        tr("The error rate shows which characters give\n"
           "you the most problems. The error rate is\n"
           "calculated from the value \"Target Error\"\n"
           "and the value \"Frequency\"."),
        Qt::ToolTipRole);
}

void CharTableSql::deleteUserChars()
{
    switch (QMessageBox::question(this, t10::app_name,
        tr("Recorded error rates affect the intelligence feature and the "
           "selection of the text to be dictated. If the error rate for a "
           "certain character is excessively high it might be useful to reset "
           "the list.\n\n"
           "All recorded characters will now be deleted.\n\n"
           "Do you still wish to proceed?\n"))) {
    case QMessageBox::Yes: {
        StartSql* userSql = new StartSql();
        if (!userSql->deleteUserChars()) {
            // Error message
            ErrorMessage* errorMessage = new ErrorMessage(this);
            errorMessage->showMessage(Error::user_errors_flush,
                ErrorMessage::Type::Warning, ErrorMessage::Cancel::Operation);
            return;
        }
        setQueryOrder("", false);
        buttonReset->setEnabled(false);
        break;
    }
    default:
        break;
    }
}
