/*
    This file is part of Kiten, a KDE Japanese Reference Tool
    SPDX-FileCopyrightText: 2006 Joseph Kerian <jkerian@gmail.com>

    SPDX-License-Identifier: LGPL-2.0-or-later
*/

/**
 * Future Plans:
 *
 * Design a custom QGridLayout to rearrange buttons dynamically to resize
 * Design multiple radical file handling
 * Icon set for displaying radicals outside of this bizarre unicode section
 * Radical decomposition implementation
 */

#include "buttongrid.h"

#include <KLocalizedString>

#include <QGridLayout>
#include <QLabel>
#include <QString>

ButtonGrid::ButtonGrid(QWidget *parent, RadicalFile *radicalInfo)
    : QWidget(parent)
    , CurrentMode(Selection)
    , m_radicalInfo(radicalInfo)
    , m_sortByFrequency(false)
{
    if (m_radicalInfo) {
        buildRadicalButtons();
    }
}

void ButtonGrid::buildRadicalButtons()
{
    if (layout()) {
        // Instead of iterating over our children and deleting them one by one, we
        // simply reparent the previous layout to a temporary widget; when it goes
        // out of scope, everything will be automatically deleted.
        // Thanks to https://stackoverflow.com/a/10439207 for the tip!
        QWidget().setLayout(layout());
    }

    // Setup the grid
    auto grid = new QGridLayout(this);

    // Now make labels
    for (unsigned int i = 0; i < number_of_radical_columns; i++) {
        QString headerString = QString::number(i + 1);
        if (i == (number_of_radical_columns - 1)) {
            headerString.append(QStringLiteral("+"));
        }
        auto header = new QLabel(headerString, this);
        header->setAlignment(Qt::AlignHCenter);
        grid->addWidget(header, 0, i);
    }

    // Get a list of radicals (organized by strokes)
    QMultiMap<int, Radical> *radicalMap = m_radicalInfo->mapRadicalsByStrokes(number_of_radical_columns);
    QList<int> radicalStrokeCounts = radicalMap->uniqueKeys();
    // Now create all the buttons
    for (int strokeCount : radicalStrokeCounts) {
        //(0-based column index)
        unsigned int column_index = strokeCount - 1;
        int row_index = 1;

        QList<Radical> radicals = radicalMap->values(strokeCount);
        std::sort(radicals.begin(), radicals.end(), m_sortByFrequency ? Radical::compareFrequencies : Radical::compareIndices);
        for (const Radical &radical : radicals) {
            // Make the button
            auto button = new RadicalButton(radical.toString(), this);
            grid->addWidget(button, row_index++, column_index);
            // Bind slots/signals for this button
            connect(button, &RadicalButton::userClicked, this, &ButtonGrid::radicalClicked);
            connect(this, &ButtonGrid::clearButtonSelections, button, &RadicalButton::resetButton);

            // Add this button to our list
            m_buttons.insert(radical.toString(), button);
        }
    }
    delete radicalMap;
    setLayout(grid);

    updateButtons();
}

void ButtonGrid::setSortByFrequency(bool enable)
{
    if (m_sortByFrequency != enable) {
        m_sortByFrequency = enable;
        buildRadicalButtons();
    }
}

void ButtonGrid::clearSelections()
{
    m_selectedRadicals.clear();
    Q_EMIT clearButtonSelections();
}

void ButtonGrid::radicalClicked(const QString &newrad, RadicalButton::ButtonStatus newStatus)
{
    if (newStatus == RadicalButton::Related) {
        // TODO: Do something fancy
    } else if (newStatus == RadicalButton::Normal || newStatus == RadicalButton::Selected) {
        CurrentMode = Selection;

        if (newStatus == RadicalButton::Normal) {
            m_selectedRadicals.remove(newrad);
            if (m_selectedRadicals.isEmpty()) {
                Q_EMIT signalChangeStatusbar(i18n("No Radicals Selected"));
            }
        } else {
            m_selectedRadicals.insert(newrad);
        }

        updateButtons();
    }
}

void ButtonGrid::updateButtons()
{
    if (!m_radicalInfo) {
        return;
    }
    // Special Case/Early exit: no radicals selected
    if (m_selectedRadicals.isEmpty()) {
        QList<Kanji> blankList;
        for (RadicalButton *button : m_buttons) {
            button->setStatus(RadicalButton::Normal);
        }

        Q_EMIT possibleKanji(blankList);
        return;
    }

    // Figure out what our kanji possibilities are
    QSet<Kanji> kanjiSet = m_radicalInfo->kanjiContainingRadicals(m_selectedRadicals);

    // Convert to a list, sort, and tell the world!
    QList<Kanji> kanjiList = kanjiSet.values();
    std::sort(kanjiList.begin(), kanjiList.end());
    Q_EMIT possibleKanji(kanjiList);

    // Do the announcement of the selected radical list
    QStringList radicalList(m_selectedRadicals.values());
    Q_EMIT signalChangeStatusbar(i18n("Selected Radicals: ") + radicalList.join(QLatin1String(", ")));

    // Now figure out what our remaining radical possibilities are
    QSet<QString> remainingRadicals = m_radicalInfo->radicalsInKanji(kanjiSet);
    // Remove the already selected ones
    remainingRadicals -= m_selectedRadicals;

    // Now go through and set status appropriately
    QHash<QString, RadicalButton *>::iterator i = m_buttons.begin();
    while (i != m_buttons.end()) {
        if (m_selectedRadicals.contains(i.key())) {
            i.value()->setStatus(RadicalButton::Selected);
        } else if (remainingRadicals.contains(i.key())) {
            i.value()->setStatus(RadicalButton::Normal);
        } else {
            i.value()->setStatus(RadicalButton::NotAppropriate);
        }

        ++i;
    }
}

#include "moc_buttongrid.cpp"
