/***
   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 <QDesktopServices>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QList>
#include <QMessageBox>
#include <QToolBar>
#include <QHeaderView>
#include "configsettings.h"
#include "filedialogs.h"
#include "mainwindow.h"
#include "outputtextedit.h"
#include "substitutionsmanager.h"
#include "utils.h"

SubstitutionsManager::SubstitutionsManager(QWidget* parent)
    : QDialog(parent)
{
    setWindowTitle(tr("Substitutions"));

    QAction* openAction = new QAction(QIcon::fromTheme("document-open"), tr("Open"), this);
    openAction->setToolTip(tr("Open"));

    QAction* saveAction = new QAction(QIcon::fromTheme("document-save"), tr("Save"), this);
    saveAction->setToolTip(tr("Save"));

    QAction* clearAction = new QAction(QIcon::fromTheme("edit-clear"), tr("Clear"), this);
    clearAction->setToolTip(tr("Clear"));

    QAction* addAction = new QAction(QIcon::fromTheme("list-add"), tr("Add"), this);
    addAction->setToolTip(tr("Add"));

    m_removeAction = new QAction(QIcon::fromTheme("list-remove"), tr("Remove"), this);
    m_removeAction->setToolTip(tr("Remove"));
    m_removeAction->setEnabled(false);

    QToolBar* toolbar = new QToolBar(this);
    toolbar->setIconSize(QSize(1, 1) * toolbar->style()->pixelMetric(QStyle::PM_SmallIconSize));
    toolbar->addAction(openAction);
    toolbar->addAction(saveAction);
    toolbar->addAction(clearAction);
    toolbar->addSeparator();
    toolbar->addAction(addAction);
    toolbar->addAction(m_removeAction);

    m_tableWidget = new QTableWidget(0, 2, this);
    m_tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
    m_tableWidget->setEditTriggers(QAbstractItemView::CurrentChanged);
    m_tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
    m_tableWidget->horizontalHeader()->setVisible(true);
    m_tableWidget->verticalHeader()->setVisible(false);
    m_tableWidget->setHorizontalHeaderLabels(QStringList() << tr("Search for") << tr("Replace with"));

    QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Apply | QDialogButtonBox::Close);

    QVBoxLayout* layout = new QVBoxLayout(this);
    layout->setMargin(4);
    layout->addWidget(toolbar);
    layout->addWidget(m_tableWidget);
    layout->addWidget(buttonBox);

    setLayout(layout);

    connect(openAction, &QAction::triggered, this, &SubstitutionsManager::openList);
    connect(saveAction, &QAction::triggered, this, &SubstitutionsManager::saveList);
    connect(clearAction, &QAction::triggered, this, &SubstitutionsManager::clearList);
    connect(addAction, &QAction::triggered, this, &SubstitutionsManager::addRow);
    connect(buttonBox->button(QDialogButtonBox::Apply), &QPushButton::clicked, this, &SubstitutionsManager::emitApplySubstitutions);
    connect(buttonBox->button(QDialogButtonBox::Close), &QPushButton::clicked, this, &SubstitutionsManager::hide);
    connect(m_removeAction, &QAction::triggered, this, &SubstitutionsManager::removeRows);
    connect(m_tableWidget->selectionModel(), &QItemSelectionModel::selectionChanged, this, &SubstitutionsManager::onTableSelectionChanged);

    ADD_SETTING(TableSetting("substitutionslist", m_tableWidget));
}

SubstitutionsManager::~SubstitutionsManager()
{
    ConfigSettings::get<TableSetting>("substitutionslist")->serialize();
}

void SubstitutionsManager::openList()
{
    if (!clearList()) {
        return;
    }
    QString dir = !m_currentFile.isEmpty() ? QFileInfo(m_currentFile).absolutePath() : QString();
    QStringList files = FileDialogs::openDialog(tr("Open Substitutions List"), dir, "auxdir", QString("%1 (*.txt)").arg(tr("Substitutions List")), false, this);

    if (!files.isEmpty()) {
        QString filename = files.front();
        QFile file(filename);
        if (!file.open(QIODevice::ReadOnly)) {
            QMessageBox::critical(this, tr("Error Reading File"), tr("Unable to read '%1'.").arg(filename));
            return;
        }
        m_currentFile = filename;

        bool errors = false;
        m_tableWidget->blockSignals(true);
        while (!file.atEnd()) {
            QString line = MAIN->config()->useUtf8() ? QString::fromUtf8(file.readLine()) : QString::fromLocal8Bit(file.readLine());
            line.chop(1);
            if (line.isEmpty()) {
                continue;
            }
            QList<QString> fields = line.split('\t');
            if (fields.size() < 2) {
                errors = true;
                continue;
            }
            int row = m_tableWidget->rowCount();
            m_tableWidget->insertRow(row);
            m_tableWidget->setItem(row, 0, new QTableWidgetItem(fields[0]));
            m_tableWidget->setItem(row, 1, new QTableWidgetItem(fields[1]));
        }
        m_tableWidget->blockSignals(false);
        if (errors) {
            QMessageBox::warning(this, tr("Errors Occurred Reading File"), tr("Some entries of the substitutions list could not be read."));
        }
    }
}

bool SubstitutionsManager::saveList()
{
    QString filename = FileDialogs::saveDialog(tr("Save Substitutions List"), m_currentFile, "auxdir", QString("%1 (*.txt)").arg(tr("Substitutions List")), false, this);
    if (filename.isEmpty()) {
        return false;
    }
    QFile file(filename);
    if (!file.open(QIODevice::WriteOnly)) {
        QMessageBox::critical(this, tr("Error Saving File"), tr("Unable to write to '%1'.").arg(filename));
        return false;
    }
    m_currentFile = filename;
    for (int row = 0, nRows = m_tableWidget->rowCount(); row < nRows; ++row) {
        QString line = QString("%1\t%2\n").arg(m_tableWidget->item(row, 0)->text()).arg(m_tableWidget->item(row, 1)->text());
        file.write(MAIN->config()->useUtf8() ? line.toUtf8() : line.toLocal8Bit());
    }
    return true;
}

bool SubstitutionsManager::clearList()
{
    if (m_tableWidget->rowCount() > 0) {
        int response = QMessageBox::question(this, tr("Save List?"), tr("Do you want to save the current list?"), QMessageBox::Save, QMessageBox::Discard, QMessageBox::Cancel);
        if (response == QMessageBox::Save) {
            if (!saveList()) {
                return false;
            }
        } else if (response != QMessageBox::Discard) {
            return false;
        }
        m_tableWidget->setRowCount(0);
    }
    return true;
}

void SubstitutionsManager::addRow()
{
    int row = m_tableWidget->rowCount();
    m_tableWidget->insertRow(row);
    m_tableWidget->setItem(row, 0, new QTableWidgetItem());
    m_tableWidget->setItem(row, 1, new QTableWidgetItem());
    m_tableWidget->editItem(m_tableWidget->item(row, 0));
}

void SubstitutionsManager::removeRows()
{
    m_tableWidget->blockSignals(true);
    for (const QModelIndex& index : m_tableWidget->selectionModel()->selectedRows()) {
        m_tableWidget->removeRow(index.row());
    }
    m_tableWidget->blockSignals(false);
}

void SubstitutionsManager::onTableSelectionChanged(const QItemSelection& selected, const QItemSelection& /*deselected*/)
{
    m_removeAction->setEnabled(!selected.isEmpty());
}

void SubstitutionsManager::emitApplySubstitutions()
{
    QMap<QString, QString> substitutions;
    for (int row = 0, nRows = m_tableWidget->rowCount(); row < nRows; ++row) {
        substitutions.insert(m_tableWidget->item(row, 0)->text(), m_tableWidget->item(row, 1)->text());
    }
    emit applySubstitutions(substitutions);
}
