/****************************************************************************
**
** Copyright (C) 2014 Jolla Ltd.
** Contact: http://jolla.com/
**
** This file is part of Qt Creator.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Digia.
**
****************************************************************************/

#include "nxtabstractvmstartstep.h"

#include <vm/nxtconnection.h>
#include <vm/nxtconnectionmanager.h>
#include <nxtconstants.h>
#include <qtc/nxtsdk.h>
#include <qtc/nxtsdkkitinformation.h>
#include <vm/nxtvirtualboxmanager.h>

#include <coreplugin/icore.h>
#include <projectexplorer/target.h>
#include <utils/qtcassert.h>

using namespace Core;
using namespace ProjectExplorer;

namespace Nxt {
namespace Internal {

namespace {
const int CHECK_FOR_CANCEL_INTERVAL = 2000;
const int DISMISS_MESSAGE_BOX_DELAY = 2000;
}

class NxtAbstractVmStartStepConfigWidget : public SimpleBuildStepConfigWidget
{
    Q_OBJECT

public:
    NxtAbstractVmStartStepConfigWidget(NxtAbstractVmStartStep *step)
        : SimpleBuildStepConfigWidget(step)
    {
    }

    QString summaryText() const override
    {
        return QString::fromLatin1("<b>%1:</b> %2")
            .arg(displayName())
            .arg(tr("Starts the virtual machine, if necessary."));
    }
};

NxtAbstractVmStartStep::NxtAbstractVmStartStep(BuildStepList *bsl, Core::Id id)
    : BuildStep(bsl, id)
    , m_connection(nullptr)
    , m_futureInterface(nullptr)
    , m_checkForCancelTimer(nullptr)
{
}

bool NxtAbstractVmStartStep::init(QList<const BuildStep *> &earlierSteps)
{
    Q_UNUSED(earlierSteps);
    QTC_ASSERT(m_connection, return false);

    return true;
}

void NxtAbstractVmStartStep::run(QFutureInterface<bool> &fi)
{
    if (!m_connection) {
        emit addOutput(tr("%1: Internal error.").arg(displayName()), OutputFormat::ErrorMessage);
        reportRunResult(fi, false);
        return;
    }

    if (m_connection->state() == NxtConnection::Connected) {
        emit addOutput(tr("%1: The \"%2\" virtual machine is already running. Nothing to do.").arg(displayName()).arg(m_connection->virtualMachine()), OutputFormat::NormalMessage);
        reportRunResult(fi, true);
    } else {
        emit addOutput(tr("%1: Starting \"%2\" virtual machine...").arg(displayName()).arg(m_connection->virtualMachine()), OutputFormat::NormalMessage);
        m_futureInterface = &fi;

        m_checkForCancelTimer = new QTimer(this);
        connect(m_checkForCancelTimer, &QTimer::timeout, this, &NxtAbstractVmStartStep::checkForCancel);
        m_checkForCancelTimer->start(CHECK_FOR_CANCEL_INTERVAL);

        connect(m_connection.data(), &NxtConnection::stateChanged, this, &NxtAbstractVmStartStep::onStateChanged);
        m_connection->connectTo(NxtConnection::AskStartVm);
    }
}

BuildStepConfigWidget *NxtAbstractVmStartStep::createConfigWidget()
{
    return new NxtAbstractVmStartStepConfigWidget(this);
}

bool NxtAbstractVmStartStep::immutable() const
{
    return false;
}

bool NxtAbstractVmStartStep::runInGuiThread() const
{
    return true;
}

NxtConnection *NxtAbstractVmStartStep::connection() const
{
    return m_connection;
}

void NxtAbstractVmStartStep::setConnection(NxtConnection *connection)
{
    m_connection = connection;
}

void NxtAbstractVmStartStep::onStateChanged()
{
    bool result = false;
    switch (m_connection->state()) {
    case NxtConnection::Disconnected:
    case NxtConnection::Error:
        break;

    case NxtConnection::Connected:
        result = true;
        break;

    default:
        return;
    }

    m_connection->disconnect(this);
    m_connection = nullptr;
    reportRunResult(*m_futureInterface, result);
    m_futureInterface = nullptr;
    delete m_checkForCancelTimer;
    m_checkForCancelTimer = nullptr;
}

void NxtAbstractVmStartStep::checkForCancel()
{
    if (m_futureInterface->isCanceled()) {
        m_connection->disconnect(this);
        m_connection = nullptr;
        delete m_checkForCancelTimer;
        m_checkForCancelTimer = nullptr;
        reportRunResult(*m_futureInterface, false);
        m_futureInterface = nullptr;
    }
}

} // namespace Internal
} // namespace Nxt

#include "nxtabstractvmstartstep.moc"
