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

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

/****************************************************************
**
** Implementation of the KeyBoard class
** File name: keyboard.cpp
**
****************************************************************/

#include <QCoreApplication>
#include <QPainter>
#include <QPen>
#include <QSettings>

#include "def/defines.h"
#include "errormessage.h"
#include "keyboard.h"

KeyBoard::KeyBoard(QWidget* parent)
    : QWidget(parent)
    , isStarted(false)
    , isPaused(false)
    , keyLayoutFound(false) // Flag whether the key properties where found
    , activeKey('0')
    , activeX(0)
    , activeY(0)
    , activeColor(0)
    , activeForm(0)
    , activeFinger(8)
    , activeModifier(0)
    , activeModifierX(0)
    , activeModifierY(0)
    , activeModifierColor(0)
    , activeModifierForm(0)
    , activeModifierFinger(8)
    , activeModifier2X(0)
    , activeModifier2Y(0)
    , activeModifier2Color(0)
    , activeModifier2Form(0)
    , activeModifier2Finger(8)
    , showErrorImage(false)
{
    // Read settings (keyboard layout and key coloring)
    readSettings();

    // Load all images used in the keyboard
    loadKeyImages();

    colorIndex[0] = 4; // yellow
    colorIndex[1] = 3; // green
    colorIndex[2] = 2; // blue
    colorIndex[3] = 1; // red
    colorIndex[4] = 0; // grey (no additional key)
    keyColors[0] = QColor(253, 232, 151);
    keyColors[1] = QColor(181, 235, 157);
    keyColors[2] = QColor(172, 215, 254);
    keyColors[3] = QColor(249, 174, 174);

    currentPen.setWidth(3);
    currentPen.setStyle(Qt::DotLine);

    // Sql class to get the key layout of a given char
    keyboardSql = new KeyboardSql(layout);
    // Fix the size of this class because of using fix sized images
    setFixedSize(610, 228);
    setAttribute(Qt::WA_NoSystemBackground);
}

void KeyBoard::startBoard()
{
    // Turn start flag true
    isStarted = true;
    // Turn pause flag false
    isPaused = false;

    showErrorImage = false;
    // Call the paint event (refresh the keyboard)
    repaint();
}

void KeyBoard::pauseBoard()
{
    // Turn start flag false
    isStarted = false;
    // Turn pause flag true
    isPaused = true;
    // Call the paint event (refresh the keyboard)
    update();
}

void KeyBoard::stopBoard()
{
    // Turn start flag false
    isStarted = false;
    // Call the paint event (refresh the keyboard)
    update();
}

void KeyBoard::paintEvent([[maybe_unused]] QPaintEvent* event)
{
    // Draw empty grey keyboard
    cleanKeyboard();

    if (isStarted) {
        // Color current key and modifier
        colorKey();
    } else {
        if (keyColoringStart) {
            // Color user's start position
            colorStart();
        }
    }
    // Draw keyboard labeling
    drawLayout();
}

void KeyBoard::loadKeyImages()
{
    // Load background
    if (!loadImage(background, ":/img/keyboardbg.png")) {
        return;
    }
    // Keys
    // -> four different key colors
    for (int x = 0; x < 5; x++) {
        // -> six different key forms
        for (int y = 0; y < 9; y++) {
            // Load key
            if (!loadImage(keyImage[x][y],
                    ":/img/key" + QString::number(x) + "_" + QString::number(y)
                        + ".png")) {
                return;
            }
        }
    }
    // -> five different start key colors
    for (int y = 0; y < 5; y++) {
        // Load key
        if (!loadImage(
                keyImageStart[y], ":/img/key" + QString::number(y) + ".png")) {
            return;
        }
    }
    // Load key labeling
    if (!loadImage(keyLayout, ":/img/" + layout + ".png")) {
        return;
    }
    // Load keyboard border
    if (!loadImage(keyBorder, ":/img/keyboard_border.png")) {
        return;
    }
}

bool KeyBoard::loadImage(QPixmap& img, QString filename)
{
    // Check whether loading the image is correct
    if (!img.load(filename)) {
        // Error message
        ErrorMessage* errorMessage = new ErrorMessage(this);
        errorMessage->showMessage(Error::key_pic, ErrorMessage::Type::Warning,
            ErrorMessage::Cancel::Operation);
        return false;
    }
    return true;
}

void KeyBoard::cleanKeyboard()
{
    QPainter painter(this);
    // Background image
    painter.drawPixmap(0, 0, background);

    // Keys first row
    for (int i = 0; i < 13; i++) {
        painter.drawPixmap(10 + (40 * i), 15, keyImage[0][0]);
    }
    painter.drawPixmap(530, 15, keyImage[0][5]);

    // Enter key QWERTZ; other QWERTY
    if (layout.left(2) != "us") {
        painter.drawPixmap(550, 55, keyImage[0][4]);
    } else {
        painter.drawPixmap(550, 55, keyImage[0][1]);
    }

    // Keys second row
    painter.drawPixmap(10, 55, keyImage[0][6]);
    for (int i = 0; i < 12; i++) {
        painter.drawPixmap(70 + (40 * i), 55, keyImage[0][0]);
    }

    // Keys third row
    painter.drawPixmap(10, 95, keyImage[0][5]);
    if (keyColoringStart) {
        // Four keys left hand
        // COMAK-Release
        /*for (i = 4; i >= 0; i--) {
                if (i != 4 && i != activeFinger && i != activeModifierFinger) {
                        painter.drawImage(80 + (40 * i), 95, keyImageStart[4 -
        i]); } else { if (i == 4 && (i - 1) != activeFinger && (i - 1) !=
        activeModifierFinger) { painter.drawImage(80 + (40 * i), 95,
        keyImageStart[5 - i]); } else { painter.drawImage(80 + (40 * i), 95,
        keyImageStart[0]);
                        }
                }
        }*/
        // TIPP10
        for (int i = 3; i >= 0; i--) {
            if (i != activeFinger && i != activeModifierFinger
                && i != activeModifier2Finger) {
                painter.drawPixmap(
                    80 + (40 * i), 95, keyImageStart[colorIndex[i]]);
            } else {
                painter.drawPixmap(80 + (40 * i), 95, keyImageStart[0]);
            }
        }
        painter.drawPixmap(80 + (40 * 4), 95, keyImage[0][0]);
        painter.drawPixmap(80 + (40 * 5), 95, keyImage[0][0]);
        for (int i = 6; i < 10; i++) {
            if ((i - 2) != activeFinger && (i - 2) != activeModifierFinger
                && (i - 2) != activeModifier2Finger) {
                painter.drawPixmap(
                    80 + (40 * i), 95, keyImageStart[colorIndex[9 - i]]);
            } else {
                painter.drawPixmap(80 + (40 * i), 95, keyImageStart[0]);
            }
        }
        painter.drawPixmap(80 + (40 * 10), 95, keyImage[0][0]);
    } else {
        for (int i = 0; i < 11; i++) {
            painter.drawPixmap(80 + (40 * i), 95, keyImage[0][0]);
        }
    }
    // Enter key QWERTY; other QWERTZ
    if (layout.left(2) != "us") {
        painter.drawPixmap(80 + (40 * 11), 95, keyImage[0][0]);
    } else {
        painter.drawPixmap(80 + (40 * 11), 95, keyImage[0][7]);
    }

    // Keys fourth row
    if (layout.left(2) != "us") {
        painter.drawPixmap(10, 135, keyImage[0][1]);
        painter.drawPixmap(60, 135, keyImage[0][0]);
    } else {
        painter.drawPixmap(10, 135, keyImage[0][8]);
    }
    for (int i = 1; i < 11; i++) {
        painter.drawPixmap(60 + (40 * i), 135, keyImage[0][0]);
    }
    painter.drawPixmap(500, 135, keyImage[0][2]);

    // Keys fifth row
    painter.drawPixmap(10, 175, keyImage[0][6]);
    painter.drawPixmap(70, 175, keyImage[0][0]);
    painter.drawPixmap(110, 175, keyImage[0][6]);
    painter.drawPixmap(170, 175, keyImage[0][3]);
    painter.drawPixmap(440, 175, keyImage[0][6]);
    painter.drawPixmap(500, 175, keyImage[0][0]);
    painter.drawPixmap(540, 175, keyImage[0][6]);
}

void KeyBoard::drawLayout()
{
    QPainter painter(this);
    // Draw the labeling of the keyboard
    painter.drawPixmap(10, 15, keyLayout);
    // Draw the border of the keyboard
    if (keyDrawBorder) {
        painter.drawPixmap(270, 15, keyBorder);
    }
}

void KeyBoard::colorStart()
{
    QPainter painter(this);

    if (keyColoring && !isPaused) {
        // User's startposition
        // Four keys left hand
        for (int i = 3; i >= 0; i--) {
            painter.drawPixmap(80 + (40 * i), 95, keyImageStart[colorIndex[i]]);
        }
        // Four keys right hand
        for (int i = 6; i < 10; i++) {
            painter.drawPixmap(
                80 + (40 * i), 95, keyImageStart[colorIndex[9 - i]]);
        }
    }
    // Colored space key
    painter.drawPixmap(170, 175, keyImage[1][3]);
}

// Places the current colored keys
void KeyBoard::colorKey()
{
    QPainter painter(this);

    if (keyLayoutFound) {

        if (keyDrawPath) {

            int activeFingerTemp = activeFinger;
            if (activeFingerTemp > 3) {
                activeFingerTemp += 2;
            }
            currentPen.setColor(keyColors[4 - colorIndex[4 - activeColor]]);
            painter.setPen(currentPen);
            if ((activeY != 95 || activeX != (activeFingerTemp * 40))
                && (activeY != 175 || activeX != 170)) {
                painter.drawLine(100 + (activeFingerTemp * 40), 115,
                    activeX + 20, activeY + 20);
            }
            int activeModifierFingerTemp = activeModifierFinger;
            if (activeModifierFingerTemp > 3) {
                activeModifierFingerTemp += 2;
            }
            currentPen.setColor(
                keyColors[4 - colorIndex[4 - activeModifierColor]]);
            painter.setPen(currentPen);
            if (activeModifier != 0) {
                painter.drawLine(100 + (activeModifierFingerTemp * 40), 115,
                    activeModifierX + 20, activeModifierY + 20);
            }
            int activeModifier2FingerTemp = activeModifier2Finger;
            if (activeModifier2FingerTemp > 3) {
                activeModifier2FingerTemp += 2;
            }
            currentPen.setColor(
                keyColors[4 - colorIndex[4 - activeModifier2Color]]);
            painter.setPen(currentPen);
            if (activeModifier2 != 0) {
                painter.drawLine(100 + (activeModifier2FingerTemp * 40), 115,
                    activeModifier2X + 20, activeModifier2Y + 20);
            }
        }

        if (keyColoring) {
            // Color current key
            painter.drawPixmap(activeX, activeY,
                keyImage[colorIndex[4 - activeColor]][activeForm]);
            if (activeModifier != 0) {
                // Color current modifier
                painter.drawPixmap(activeModifierX, activeModifierY,
                    keyImage[colorIndex[4 - activeModifierColor]]
                            [activeModifierForm]);
            }
            if (activeModifier2 != 0) {
                // Color current modifier
                painter.drawPixmap(activeModifier2X, activeModifier2Y,
                    keyImage[colorIndex[4 - activeModifier2Color]]
                            [activeModifier2Form]);
            }
        }
    }
}

void KeyBoard::setErrorImage(QChar key)
{
    if (errorImage.load(":/img/" + QString::number(key.unicode()) + ".png")) {
        /*errorImage = errorImage.scaledToHeight(40);
        for (int y = 0; y < errorImage.height(); ++y) {
            QRgb *row = (QRgb*)errorImage.scanLine(y);
            for (int x = 0; x < errorImage.width(); ++x) {
                ((unsigned char*)&row[x])[3] = 50;
            }
        }*/
        showErrorImage = true;
    }
}

void KeyBoard::setKey(QChar key)
{
    QString statusText = "0";

    showErrorImage = false;

    // Check whether key is already colored and whether keyboard is started
    if (activeKey != key && isStarted) {
        activeModifierFinger = 8;
        activeModifier2Finger = 8;
        activeFinger = 8;
        // New current key
        activeKey = key;
        // Get the properties of the key
        if (keyboardSql->getKeyLayout(activeKey, &activeX, &activeY,
                &activeColor, &activeForm, &activeModifier, &activeModifier2,
                &activeFinger, &statusText)) {
            keyLayoutFound = true;
            if (activeModifier != 0) {
                // If there is also a modifier get the properties, too
                if (!keyboardSql->getModifierLayout(activeModifier,
                        &activeModifierX, &activeModifierY,
                        &activeModifierColor, &activeModifierForm,
                        &activeModifierFinger, &statusText)) {
                    activeModifier = 0;
                }
            }
            if (activeModifier2 != 0) {
                // If there is also a modifier get the properties, too
                if (!keyboardSql->getModifierLayout(activeModifier2,
                        &activeModifier2X, &activeModifier2Y,
                        &activeModifier2Color, &activeModifier2Form,
                        &activeModifier2Finger, &statusText)) {
                    activeModifier2 = 0;
                }
            }
        } else {
            // No properties were found
            keyLayoutFound = false;
        }
        // Emit the help text of current key(s)
        emit statusRefreshed(statusText);
        // Call the paint event (refresh the keyboard)
        if (keyColoring || keyColoringStart || keyDrawPath) {
            repaint();
        }
    }
}

void KeyBoard::readSettings()
{
#if APP_PORTABLE
    QSettings settings(
        QCoreApplication::applicationDirPath() + "/portable/settings.ini",
        QSettings::IniFormat);
#else
    QSettings settings;
#endif

    settings.beginGroup("main");
    layout = settings.value("language_layout", t10::app_std_language_layout)
                 .toString();
    settings.endGroup();
    // Check if key coloring is turned on
    settings.beginGroup("support");
    keyColoring = settings.value("check_selection", true).toBool();
    keyColoringStart = settings.value("check_selection_start", true).toBool();
    keyDrawBorder = settings.value("check_border", true).toBool();
    keyDrawPath = settings.value("check_path", true).toBool();
    settings.endGroup();
}
