#include "IOModesController.h"
#include "Cutter.h"

#include <QJsonArray>
#include <QPushButton>
#include <QObject>
#include <QMessageBox>
#include <QJsonObject>
#include <qwidget.h>

IOModesController::IOModesController(QWidget *parentWindow)
    : QObject(parentWindow), parentWindow(parentWindow)
{
}

bool IOModesController::canWrite()
{
    return Core()->isIOCacheEnabled() || Core()->isWriteModeEnabled();
}

IOModesController::Mode IOModesController::getIOMode()
{
    if (Core()->isWriteModeEnabled()) {
        return Mode::WRITE;
    } else if (Core()->isIOCacheEnabled()) {
        return Mode::CACHE;
    } else {
        return Mode::READ_ONLY;
    }
}

void IOModesController::setIOMode(IOModesController::Mode mode)
{
    switch (mode) {
    case Mode::READ_ONLY:
        if (askCommitUnsavedChanges()) {
            Core()->setWriteMode(false);
        }
        break;
    case Mode::CACHE:
        Core()->setIOCache(true);
        break;
    case Mode::WRITE:
        if (askCommitUnsavedChanges()) {
            Core()->setWriteMode(true);
        }
        break;
    }
}

bool IOModesController::prepareForWriting()
{
    if (canWrite()) {
        return true;
    }

    QMessageBox msgBox(parentWindow);
    msgBox.setIcon(QMessageBox::Icon::Critical);
    msgBox.setWindowTitle(QObject::tr("Write error"));
    msgBox.setText(QObject::tr(
            "Your file is opened in read-only mode. "
            "Editing is only available when the file is opened in either Write or Cache modes.\n\n"
            "WARNING: In Write mode, any changes will be committed to the file on disk. "
            "For safety, please consider using Cache mode and then commit the changes manually "
            "via File -> Commit modifications to disk."));
    msgBox.addButton(QObject::tr("Cancel"), QMessageBox::RejectRole);
    QAbstractButton *reopenButton =
            msgBox.addButton(QObject::tr("Reopen in Write mode"), QMessageBox::YesRole);
    QAbstractButton *iocacheButton =
            msgBox.addButton(QObject::tr("Enable Cache mode"), QMessageBox::YesRole);

    msgBox.exec();

    if (msgBox.clickedButton() == reopenButton) {
        Core()->setWriteMode(true);
    } else if (msgBox.clickedButton() == iocacheButton) {
        Core()->setIOCache(true);
    } else {
        return false;
    }
    return true;
}

bool IOModesController::allChangesComitted()
{
    RzCoreLocked core(Core());
    for (auto c : CutterPVector<RzIOCache>(&core->io->cache)) {
        if (!c->written) {
            return false;
        }
    }
    return true;
}

bool IOModesController::askCommitUnsavedChanges()
{
    // Check if there are uncommitted changes
    if (!allChangesComitted()) {
        QMessageBox::StandardButton ret = QMessageBox::question(
                parentWindow, QObject::tr("Uncommitted changes"),
                QObject::tr("It seems that you have changes or patches that are not committed to "
                            "the file.\n"
                            "Do you want to commit them now?"),
                (QMessageBox::StandardButtons)(QMessageBox::Save | QMessageBox::Discard
                                               | QMessageBox::Cancel));
        if (ret == QMessageBox::Save) {
            Core()->commitWriteCache();
        } else if (ret == QMessageBox::Discard) {
            Core()->resetWriteCache();
            emit Core()->refreshCodeViews();
        } else if (ret == QMessageBox::Cancel) {
            return false;
        }
    }

    return true;
}
