/***
   This file is part of fly-ocr.

   Copyright (C) 2016-2020 Sandro Mani <manisandro@gmail.com>
   Copyright (C) 2021 LLC "RusBITech-Astra" (https://astralinux.ru)

    Based on gImageReader source code by Sandro Mani under the GNU
    General Public License (GPL) version 3 or later

   Foobar 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 3 of the License, or
   (at your option) any later version.

   Foobar 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 fly-ocr. If not, see <https://www.gnu.org/licenses/>.
***/

#include <QActionGroup>
#include <QDateTime>
#include <QMessageBox>
#include <QMouseEvent>
#include <QtSpell.hpp>
#include <fly-ocr/ocrengine.h>
#include "languageselectiondialog.h"
#include "configsettings.h"
#include "mainwindow.h"
#include "recognitionmenu.h"


RecognitionMenu::RecognitionMenu(QWidget* parent)
    : QMenu(parent)
{
    m_charListDialog = new QDialog(this);
    m_charListDialogUi.setupUi(m_charListDialog);

    connect(m_charListDialogUi.radioButtonBlacklist, &QRadioButton::toggled, m_charListDialogUi.lineEditBlacklist, &QLineEdit::setEnabled);
    connect(m_charListDialogUi.radioButtonWhitelist, &QRadioButton::toggled, m_charListDialogUi.lineEditWhitelist, &QLineEdit::setEnabled);

    ADD_SETTING(LineEditSetting("ocrcharwhitelist", m_charListDialogUi.lineEditWhitelist));
    ADD_SETTING(LineEditSetting("ocrcharblacklist", m_charListDialogUi.lineEditBlacklist));
    ADD_SETTING(SwitchSetting("ocrblacklistenabled", m_charListDialogUi.radioButtonBlacklist, true));
    ADD_SETTING(SwitchSetting("ocrwhitelistenabled", m_charListDialogUi.radioButtonWhitelist, false));
}

void RecognitionMenu::rebuild()
{
    clear();
    m_engineName.clear();
    m_selectedLanguages.clear();
    delete m_psmCheckGroup;

    m_psmCheckGroup = new QActionGroup(this);
    connect(m_psmCheckGroup, &QActionGroup::triggered, this, &RecognitionMenu::onPsmSelected);

    emit selectedLanguagesChanged(QList<FlyOcr::Lang>());

    const QList<QString> dicts = QtSpell::Checker::getLanguageList();
    const OcrEngineFactory* factory = OcrEngine::selected();

    if (!factory) {
        QMessageBox::warning(MAIN, tr("Error"), tr("Unable to find OCR engine."));
        return;
    }

    //read engine settings
    m_engineName = factory->shortName();
    ADD_SETTING(VarSetting<QStringList>(m_engineName + QStringLiteral("/languages"), factory->defaultLanguages()));
    ADD_SETTING(VarSetting<int>(m_engineName + QStringLiteral("/psm"), factory->defaultPageSegmentationModeId()));

    const QList<FlyOcr::Lang> availLanguages = factory->languages();
    const QStringList selected = ConfigSettings::get<VarSetting<QStringList>>(m_engineName + QStringLiteral("/languages"))->getValue();
    qWarning() << selected;
    const int activePsm = ConfigSettings::get<VarSetting<int>>(m_engineName + QStringLiteral("/psm"))->getValue();


    if (availLanguages.isEmpty()) {
        QMessageBox::warning(MAIN,
                             tr("No languages available"),
                             tr("No %1 languages are available for use. Recognition will not work.").arg(factory->name()));
    }

    // Add menu items for languages, with spelling submenu if available
    for (const FlyOcr::Lang& lang : qAsConst(availLanguages)) {

        if (selected.contains(lang.shortName))
            m_selectedLanguages.append(lang);

    }

    addAction(tr("Select languages"), this, &RecognitionMenu::selectLanguages);

    // Add PSM items
    addSeparator();
    QMenu* psmMenu = new QMenu();

    const QList<PageSegmentationMode> psmModes = factory->pageSegmentationModes();

    for (const auto& entry : qAsConst(psmModes)) {
        QAction* item = psmMenu->addAction(entry.label);
        item->setData(entry.id);
        item->setCheckable(true);
        item->setChecked(activePsm == entry.id);
        m_psmCheckGroup->addAction(item);
    }

    if (!m_psmCheckGroup->checkedAction() && !m_psmCheckGroup->actions().isEmpty())
        m_psmCheckGroup->actions().first()->setChecked(true);

    QAction* psmAction = new QAction(tr("Page segmentation mode"), this);
    psmAction->setMenu(psmMenu);
    addAction(psmAction);
    addAction(tr("Character whitelist / blacklist..."), m_charListDialog, &QDialog::exec);


    // Add installer item
    addSeparator();

    emit selectedLanguagesChanged(m_selectedLanguages);
}

int RecognitionMenu::getPageSegmentationMode() const
{
    return m_psmCheckGroup->checkedAction() ? m_psmCheckGroup->checkedAction()->data().toInt() : -1;
}

QString RecognitionMenu::getCharacterWhitelist() const
{
    return m_charListDialogUi.radioButtonWhitelist->isChecked() ? m_charListDialogUi.lineEditWhitelist->text() : QString();
}

QString RecognitionMenu::getCharacterBlacklist() const
{
    return m_charListDialogUi.radioButtonBlacklist->isChecked() ? m_charListDialogUi.lineEditBlacklist->text() : QString();
}

const QList<FlyOcr::Lang>& RecognitionMenu::selectedLanguages() const
{
    return m_selectedLanguages;
}

QString RecognitionMenu::selectedLanguageCode() const
{
    if (m_engineName.isEmpty())
        return QString();

    QStringList selectedLanguages = ConfigSettings::get<VarSetting<QStringList>>(m_engineName + QStringLiteral("/languages"))->getValue();
    if (selectedLanguages.count() == 1 && selectedLanguages.first().contains(":"))
        return selectedLanguages.first().split(":").at(1);

    return QString();
}

void RecognitionMenu::selectLanguages()
{
    const OcrEngineFactory* factory = OcrEngine::selected();
    if (!factory)
        return;

    LanguageSelectionDialog d(factory->languages(), selectedLanguages(), MAIN);
    if (d.exec() == QDialog::Accepted) {
        m_selectedLanguages = d.selectedLaguages();
        ConfigSettings::get<VarSetting<QStringList>>(m_engineName + QStringLiteral("/languages"))->setValue(serialize(m_selectedLanguages));
        emit selectedLanguagesChanged(m_selectedLanguages);
    }
}

void RecognitionMenu::onPsmSelected(QAction* action)
{
    ConfigSettings::get<VarSetting<int>>(m_engineName + QStringLiteral("/psm"))->setValue(action->data().toInt());
}

QStringList RecognitionMenu::serialize(const QList<FlyOcr::Lang>& langs) const
{
    QStringList result;

    for (const FlyOcr::Lang& lang : qAsConst(langs)) {
        //if (lang.code.isEmpty())
        result << lang.shortName;
        //else
        //result << lang.shortName + ":" + lang.code;
    }

    return result;
}
