#include "mnemonicattached.h"
#include <QEvent>
#include <QGuiApplication>
#include <QKeyEvent>

using namespace Qt::Literals::StringLiterals;

class MnemonicEventFilter : public QObject
{
    Q_OBJECT

public:
    static MnemonicEventFilter &instance()
    {
        static MnemonicEventFilter s_instance;
        return s_instance;
    }

    bool isAltPressed() const { return m_altPressed; }

    bool eventFilter(QObject *watched, QEvent *event) override
    {
        Q_UNUSED(watched);

        if (event->type() == QEvent::KeyPress) {
            QKeyEvent *ke = static_cast<QKeyEvent *>(event);
            if (ke->key() == Qt::Key_Alt) {
                m_altPressed = true;
                emit altPressed();
            }
        } else if (event->type() == QEvent::KeyRelease) {
            QKeyEvent *ke = static_cast<QKeyEvent *>(event);
            if (ke->key() == Qt::Key_Alt) {
                m_altPressed = false;
                emit altReleased();
            }
        } else if (event->type() == QEvent::ApplicationStateChange) {
            if (m_altPressed) {
                m_altPressed = false;
                emit altReleased();
            }
        }

        return false;
    }

Q_SIGNALS:
    void altPressed();
    void altReleased();

private:
    MnemonicEventFilter()
        : QObject(nullptr)
    {
        qGuiApp->installEventFilter(this);
    }

    bool m_altPressed = false;
};

MnemonicAttached::MnemonicAttached(QObject *parent)
    : QObject{parent}
    , m_label{}
    , m_richTextLabel{}
    , m_active{MnemonicEventFilter::instance().isAltPressed()}
{
    connect(&MnemonicEventFilter::instance(),
            &MnemonicEventFilter::altPressed,
            this,
            &MnemonicAttached::onAltPressed);
    connect(&MnemonicEventFilter::instance(),
            &MnemonicEventFilter::altReleased,
            this,
            &MnemonicAttached::onAltReleased);
}

MnemonicAttached *MnemonicAttached::qmlAttachedProperties(QObject *object)
{
    return new MnemonicAttached(object);
}

QString MnemonicAttached::label() const
{
    return m_label;
}

void MnemonicAttached::setLabel(const QString &label)
{
    if (m_label == label) {
        return;
    }
    m_label = label;
    emit labelChanged();
    emit sequenceChanged();

    updateRichText();
}

QString MnemonicAttached::richTextLabel() const
{
    return m_richTextLabel;
}

QKeySequence MnemonicAttached::sequence() const
{
    return QKeySequence::mnemonic(m_label);
}

void MnemonicAttached::onAltPressed()
{
    if (m_active) {
        return;
    }
    m_active = true;
    updateRichText();
}

void MnemonicAttached::onAltReleased()
{
    if (!m_active) {
        return;
    }
    m_active = false;
    updateRichText();
}

void MnemonicAttached::updateRichText()
{
    QString richTextLabel;
    qsizetype pos = m_label.indexOf('&'_L1);
    if (pos < 0 || pos + 1 == m_label.length()) {
        richTextLabel = m_label;
    } else if (m_active) {
        richTextLabel = m_label.left(pos) + "<u>"_L1 + m_label.at(pos + 1) + "</u>"
                        + m_label.mid(pos + 2);
    } else {
        richTextLabel = m_label.left(pos) + m_label.mid(pos + 1);
    }
    if (m_richTextLabel == richTextLabel) {
        return;
    }
    m_richTextLabel = richTextLabel;
    emit richTextLabelChanged();
}

#include "mnemonicattached.moc"
#include "moc_mnemonicattached.cpp"
