#include "operationholder.hpp"

#include "operation.hpp"

CSMDoc::OperationHolder::OperationHolder(QObject* parent, Operation* operation)
    : QObject(parent)
    , mOperation(operation)
{
    connect(mOperation, &Operation::progress, this, &OperationHolder::progress);

    connect(mOperation, &Operation::reportMessage, this, &OperationHolder::reportMessage);

    connect(mOperation, &Operation::done, this, &OperationHolder::doneSlot);

    connect(this, &OperationHolder::abortSignal, mOperation, &Operation::abort);

    connect(&mThread, &QThread::started, mOperation, &Operation::run);

    // When the worker thread finishes, move the operation (and its child QTimer)
    // back to the main thread so it can be safely reused or deleted. This must be
    // a DirectConnection so it runs on the worker thread before it fully exits —
    // moveToThread requires being called from the object's current thread.
    connect(&mThread, &QThread::finished, mOperation, &Operation::cleanup, Qt::DirectConnection);
}

CSMDoc::OperationHolder::~OperationHolder()
{
    quit();
}

bool CSMDoc::OperationHolder::isRunning() const
{
    return mThread.isRunning();
}

void CSMDoc::OperationHolder::start()
{
    if (!mOperation || mThread.isRunning())
        return;

    mOperation->moveToThread(&mThread);
    mThread.start();
}

void CSMDoc::OperationHolder::abort()
{
    emit abortSignal();
}

void CSMDoc::OperationHolder::quit()
{
    if (mThread.isRunning())
    {
        abort();
        mThread.quit();
        mThread.wait();
    }

    if (mOperation)
    {
        delete mOperation;
        mOperation = nullptr;
    }
}

void CSMDoc::OperationHolder::doneSlot(int type, bool failed)
{
    mThread.quit();
    mThread.wait();
    emit done(type, failed);
}
