/*
 *   This file is part of Dianara
 *   Copyright 2012-2019  JanKusanagi JRR <jancoding@gmx.com>
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the
 *   Free Software Foundation, Inc.,
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA .
 */

#include "characterpicker.h"


CharacterPicker::CharacterPicker(QWidget *parent) : QWidget(parent)
{
    this->setWindowTitle(tr("Select a symbol") + " - Dianara");
    this->setWindowIcon(QIcon::fromTheme("face-smile",
                                         QIcon(":/images/button-symbols.png")));
    this->setWindowFlags(Qt::Dialog);
    this->setWindowModality(Qt::ApplicationModal);

    QSettings settings;
    QSize savedWindowsize = settings.value("CharacterPicker/charPickerWindowSize")
                                    .toSize();
    if (savedWindowsize.isValid())
    {
        this->resize(savedWindowsize);
    }

    m_charSelect = new KCharSelect(this,
                                   // FIXME: use the other constructor to handle Find action
                                   KCharSelect::CharacterTable
                                   | KCharSelect::BlockCombos
                                   | KCharSelect::SearchLine
                                   | KCharSelect::FontSize);
    m_charSelect->setAllPlanesEnabled(true);

    // Select the first symbol from the Emoticons block
    m_charSelect->setCurrentCodePoint(0x1F600);

    QFont charFont = m_charSelect->currentFont();
    charFont.setPointSize(settings.value("CharacterPicker/charPickerFontSize",
                                         24).toInt());
    m_charSelect->setCurrentFont(charFont);

    /*
     * Using KCharSelect::currentCodePointChanged has some drawbacks, mainly
     * that it's emitted whenever the Unicode block is changed or a search is
     * performed. Also it doesn't allow selecting the symbol that's already
     * selected.
     *
     * KCharSelect::codePointSelected works much better, but requires
     * double-clicking the symbol, or pressing Enter.
     *
     * In addition to connecting to that, find the QTableView object used
     * inside KCharSelect and use its clicked() signal.
     *
     * This is a little bit hacky and depends on internal implementation.
     * It could break in future releases of KWidgetsAddons, but selecting
     * via double-click and Enter would still work.
     *
     */
    connect(m_charSelect, &KCharSelect::codePointSelected,
            this, &CharacterPicker::onCodePointSelected);

    m_charSelectTableView = m_charSelect->findChild<QTableView *>();
    if (m_charSelectTableView)
    {
        connect(m_charSelectTableView, &QTableView::clicked,
                this, &CharacterPicker::onCodePointSelected);
    }


    // Line with options and buttons for recently used symbols
    m_makeBigCheckbox = new QCheckBox(tr("Insert in big size"), this);
    m_makeBigCheckbox->setChecked(settings.value("CharacterPicker/bigSymbols")
                                          .toBool());

    const QVariantList codepoints = settings.value("CharacterPicker/recentCodepoints")
                                            .toList();
    m_recentLayout = new QGridLayout();
    int buttonRow = 0;
    int buttonColumn = 0;
    for (int counter = 0; counter < 16; ++counter)
    {
        QToolButton *recentButton = new QToolButton(this);
        recentButton->setFont(charFont);
        recentButton->setSizePolicy(QSizePolicy::MinimumExpanding,
                                    QSizePolicy::Maximum);
        if (counter < codepoints.size())
        {
            uint codepoint = codepoints.at(counter).toUInt();
            recentButton->setText(QString::fromUcs4(&codepoint, 1));
            connect(recentButton, &QToolButton::clicked,
                    this, &CharacterPicker::onRecentButtonClicked);

            m_recentCodepoints.append(codepoint);
        }
        else
        {
            recentButton->setText("-");
            recentButton->setDisabled(true);
        }

        m_recentButtons.append(recentButton);
        m_recentLayout->addWidget(recentButton, buttonRow, buttonColumn);
        ++buttonColumn;
        if (buttonColumn > 7)
        {
            buttonColumn = 0;
            ++buttonRow;
        }
    }


    // Insert / Cancel buttons
    m_insertButton = new QPushButton(QIcon::fromTheme("insert-image",
                                                      QIcon(":/images/list-add.png")),
                                     tr("&Insert Symbol"),
                                     this);
   connect(m_insertButton, &QAbstractButton::clicked,
           this, &CharacterPicker::onCodePointSelected);

    m_cancelButton = new QPushButton(QIcon::fromTheme("dialog-cancel",
                                                      QIcon(":/images/button-cancel.png")),
                                     tr("&Cancel"),
                                     this);
    connect(m_cancelButton, &QAbstractButton::clicked,
            this, &QWidget::close);

    m_buttonBox = new QDialogButtonBox(this);
    m_buttonBox->addButton(m_insertButton, QDialogButtonBox::AcceptRole);
    m_buttonBox->addButton(m_cancelButton, QDialogButtonBox::RejectRole);


    m_mainLayout = new QVBoxLayout();
    m_mainLayout->addLayout(m_recentLayout);
    m_mainLayout->addSpacing(8);
    m_mainLayout->addWidget(m_charSelect);
    m_mainLayout->addWidget(m_makeBigCheckbox);
    m_mainLayout->addWidget(m_buttonBox);
    this->setLayout(m_mainLayout);


    // ESC to close
    m_closeAction = new QAction(this);
    m_closeAction->setShortcut(QKeySequence(Qt::Key_Escape));
    connect(m_closeAction, &QAction::triggered,
            this, &QWidget::close);
    this->addAction(m_closeAction);

    qDebug() << "CharacterPicker created";
}


CharacterPicker::~CharacterPicker()
{
    qDebug() << "CharacterPicker destroyed";
}


//////////////////////////////////////////////////////////////////////////////
///////////////////////////////////// SLOTS //////////////////////////////////
//////////////////////////////////////////////////////////////////////////////


void CharacterPicker::onCodePointSelected()
{
    const uint codepoint = m_charSelect->currentCodePoint();


    QString htmlToInsert = QString("&#%1;").arg(codepoint);
    if (m_makeBigCheckbox->isChecked())
    {
        htmlToInsert.prepend(QStringLiteral("<h2>"));
        htmlToInsert.append(QStringLiteral("</h2> "));
    }
    else
    {
        htmlToInsert.append(QStringLiteral(" "));
    }

    emit characterSelected(htmlToInsert);

    // Update list of recently used...
    if (m_recentCodepoints.isEmpty())
    {
        m_recentCodepoints.append(codepoint);
    }
    else
    {   // ...unless already present
        if (!m_recentCodepoints.contains(codepoint))
        {
            if (m_recentCodepoints.size() == 16)
            {
                m_recentCodepoints.takeFirst();
            }

            m_recentCodepoints.append(codepoint);
        }
    }

    qDebug() << "CharacterPicker::onCodePointChanged()" << codepoint;

    this->close();
}


void CharacterPicker::onRecentButtonClicked()
{
    if (sender() == 0) // Used inside the slot, it _should_ be valid
    {
        return;        // ...but something's wrong, abort
    }

    // Cast sender() QObject pointer to the original QToolButton, to get its text
    QToolButton *recentButton = qobject_cast<QToolButton *>(sender());
    QString htmlToInsert = recentButton->text();
    if (m_makeBigCheckbox->isChecked())
    {
        htmlToInsert.prepend(QStringLiteral("<h2>"));
        htmlToInsert.append(QStringLiteral("</h2> "));
    }
    else
    {
        htmlToInsert.append(QStringLiteral(" "));
    }

    emit characterSelected(htmlToInsert);
    qDebug() << "CharacterPicker::onRecentButtonClicked()" << htmlToInsert;

    this->close();
}


//////////////////////////////////////////////////////////////////////////////
/////////////////////////////// PROTECTED ////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////


void CharacterPicker::closeEvent(QCloseEvent *event)
{
    QSettings settings;
    settings.setValue("CharacterPicker/charPickerWindowSize",
                      this->size());
    settings.setValue("CharacterPicker/charPickerFontSize",
                      m_charSelect->currentFont().pointSize());
    settings.setValue("CharacterPicker/bigSymbols",
                      m_makeBigCheckbox->isChecked());
    settings.setValue("CharacterPicker/recentCodepoints",
                      m_recentCodepoints);

    this->deleteLater();

    event->accept();
}

