/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "qmakebuildconfiguration.h"

#include "qmakebuildinfo.h"
#include "qmakekitinformation.h"
#include "qmakeproject.h"
#include "qmakeprojectconfigwidget.h"
#include "qmakeprojectmanagerconstants.h"
#include "qmakenodes.h"
#include "qmakestep.h"
#include "makestep.h"

#include <utils/qtcprocess.h>
#include <utils/qtcassert.h>
#include <limits>
#include <coreplugin/icore.h>
#include <coreplugin/mimedatabase.h>
#include <projectexplorer/buildsteplist.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h>
#include <projectexplorer/toolchain.h>
#include <projectexplorer/toolchainmanager.h>
#include <qtsupport/qtkitinformation.h>
#include <qtsupport/qtversionmanager.h>
#include <utils/qtcassert.h>
#include <QDebug>

#include <QInputDialog>

namespace QmakeProjectManager {

// --------------------------------------------------------------------
// Helpers:
// --------------------------------------------------------------------

static Utils::FileName defaultBuildDirectory(bool supportsShadowBuild,
                                             const QString &projectPath,
                                             const ProjectExplorer::Kit *k,
                                             const QString &suffix)
{
    if (supportsShadowBuild)
        return Utils::FileName::fromString(QmakeProject::shadowBuildDirectory(projectPath, k, suffix));
    return Utils::FileName::fromString(ProjectExplorer::Project::projectDirectory(projectPath));
}

using namespace Internal;
using namespace ProjectExplorer;
using namespace QtSupport;
using namespace Utils;

const char QMAKE_BC_ID[] = "Qt4ProjectManager.Qt4BuildConfiguration";
const char USE_SHADOW_BUILD_KEY[] = "Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild";
const char BUILD_CONFIGURATION_KEY[] = "Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration";

enum { debug = 0 };

QmakeBuildConfiguration::QmakeBuildConfiguration(Target *target) :
    BuildConfiguration(target, Core::Id(QMAKE_BC_ID)),
    m_shadowBuild(true),
    m_isEnabled(false),
    m_qmakeBuildConfiguration(0),
    m_subNodeBuild(0),
    m_fileNodeBuild(0)
{
    ctor();
}

QmakeBuildConfiguration::QmakeBuildConfiguration(Target *target, const Core::Id id) :
    BuildConfiguration(target, id),
    m_shadowBuild(true),
    m_isEnabled(false),
    m_qmakeBuildConfiguration(0),
    m_subNodeBuild(0),
    m_fileNodeBuild(0)
{
    ctor();
}

QmakeBuildConfiguration::QmakeBuildConfiguration(Target *target, QmakeBuildConfiguration *source) :
    BuildConfiguration(target, source),
    m_shadowBuild(source->m_shadowBuild),
    m_isEnabled(false),
    m_qmakeBuildConfiguration(source->m_qmakeBuildConfiguration),
    m_subNodeBuild(0), // temporary value, so not copied
    m_fileNodeBuild(0)
{
    cloneSteps(source);
    ctor();
}

QmakeBuildConfiguration::~QmakeBuildConfiguration()
{
}

QVariantMap QmakeBuildConfiguration::toMap() const
{
    QVariantMap map(BuildConfiguration::toMap());
    map.insert(QLatin1String(USE_SHADOW_BUILD_KEY), m_shadowBuild);
    map.insert(QLatin1String(BUILD_CONFIGURATION_KEY), int(m_qmakeBuildConfiguration));
    return map;
}

bool QmakeBuildConfiguration::fromMap(const QVariantMap &map)
{
    if (!BuildConfiguration::fromMap(map))
        return false;

    m_shadowBuild = map.value(QLatin1String(USE_SHADOW_BUILD_KEY), true).toBool();
    m_qmakeBuildConfiguration = BaseQtVersion::QmakeBuildConfigs(map.value(QLatin1String(BUILD_CONFIGURATION_KEY)).toInt());

    m_qtVersionSupportsShadowBuilds =  supportsShadowBuilds();

    m_lastKitState = LastKitState(target()->kit());

    connect(ProjectExplorer::ToolChainManager::instance(), SIGNAL(toolChainUpdated(ProjectExplorer::ToolChain*)),
            this, SLOT(toolChainUpdated(ProjectExplorer::ToolChain*)));
    connect(QtSupport::QtVersionManager::instance(), SIGNAL(qtVersionsChanged(QList<int>,QList<int>,QList<int>)),
            this, SLOT(qtVersionsChanged(QList<int>,QList<int>,QList<int>)));
    return true;
}

void QmakeBuildConfiguration::ctor()
{
    connect(this, SIGNAL(environmentChanged()),
            this, SLOT(emitProFileEvaluateNeeded()));
    connect(target(), SIGNAL(kitChanged()),
            this, SLOT(kitChanged()));
}

void QmakeBuildConfiguration::kitChanged()
{
    LastKitState newState = LastKitState(target()->kit());
    if (newState != m_lastKitState) {
        // This only checks if the ids have changed!
        // For that reason the QmakeBuildConfiguration is also connected
        // to the toolchain and qtversion managers
        emitProFileEvaluateNeeded();
        updateShadowBuild();
        m_lastKitState = newState;
    }
}

void QmakeBuildConfiguration::toolChainUpdated(ProjectExplorer::ToolChain *tc)
{
    if (ToolChainKitInformation::toolChain(target()->kit()) == tc)
        emitProFileEvaluateNeeded();
}

void QmakeBuildConfiguration::qtVersionsChanged(const QList<int> &,const QList<int> &, const QList<int> &changed)
{
    if (changed.contains(QtKitInformation::qtVersionId(target()->kit())))
        emitProFileEvaluateNeeded();
}

void QmakeBuildConfiguration::updateShadowBuild()
{
    // We also emit buildDirectoryChanged if the Qt version's supportShadowBuild changed
    bool currentShadowBuild = supportsShadowBuilds();
    if (currentShadowBuild != m_qtVersionSupportsShadowBuilds) {
        if (!currentShadowBuild)
            setBuildDirectory(Utils::FileName::fromString(target()->project()->projectDirectory()));
        m_qtVersionSupportsShadowBuilds = currentShadowBuild;
    }
}

NamedWidget *QmakeBuildConfiguration::createConfigWidget()
{
    return new QmakeProjectConfigWidget(this);
}

QString QmakeBuildConfiguration::defaultShadowBuildDirectory() const
{
    // todo displayName isn't ideal
    return QmakeProject::shadowBuildDirectory(target()->project()->projectFilePath(),
                                            target()->kit(), displayName());
}

bool QmakeBuildConfiguration::supportsShadowBuilds()
{
    BaseQtVersion *version = QtKitInformation::qtVersion(target()->kit());
    return !version || version->supportsShadowBuilds();
}

/// If only a sub tree should be build this function returns which sub node
/// should be build
/// \see QMakeBuildConfiguration::setSubNodeBuild
QmakeProFileNode *QmakeBuildConfiguration::subNodeBuild() const
{
    return m_subNodeBuild;
}

/// A sub node build on builds a sub node of the project
/// That is triggered by a right click in the project explorer tree
/// The sub node to be build is set via this function immediately before
/// calling BuildManager::buildProject( BuildConfiguration * )
/// and reset immediately afterwards
/// That is m_subNodesBuild is set only temporarly
void QmakeBuildConfiguration::setSubNodeBuild(QmakeProFileNode *node)
{
    m_subNodeBuild = node;
}

FileNode *QmakeBuildConfiguration::fileNodeBuild() const
{
    return m_fileNodeBuild;
}

void QmakeBuildConfiguration::setFileNodeBuild(FileNode *node)
{
    m_fileNodeBuild = node;
}

/// returns whether this is a shadow build configuration or not
/// note, even if shadowBuild() returns true, it might be using the
/// source directory as the shadow build directory, thus it
/// still is a in-source build
bool QmakeBuildConfiguration::isShadowBuild() const
{
    return buildDirectory().toString() != target()->project()->projectDirectory();
}

void QmakeBuildConfiguration::setBuildDirectory(const FileName &directory)
{
    if (directory == buildDirectory())
        return;
    BuildConfiguration::setBuildDirectory(directory);
    QTC_CHECK(supportsShadowBuilds()
              || (!supportsShadowBuilds()
                  && buildDirectory().toString() == target()->project()->projectDirectory()));
    emitProFileEvaluateNeeded();
}

QString QmakeBuildConfiguration::makefile() const
{
    return static_cast<QmakeProject *>(target()->project())->rootQmakeProjectNode()->makefile();
}

BaseQtVersion::QmakeBuildConfigs QmakeBuildConfiguration::qmakeBuildConfiguration() const
{
    return m_qmakeBuildConfiguration;
}

void QmakeBuildConfiguration::setQMakeBuildConfiguration(BaseQtVersion::QmakeBuildConfigs config)
{
    if (m_qmakeBuildConfiguration == config)
        return;
    m_qmakeBuildConfiguration = config;

    emit qmakeBuildConfigurationChanged();
    emitProFileEvaluateNeeded();
}

void QmakeBuildConfiguration::emitProFileEvaluateNeeded()
{
    Target *t = target();
    Project *p = t->project();
    if (t->activeBuildConfiguration() == this && p->activeTarget() == t)
        static_cast<QmakeProject *>(p)->scheduleAsyncUpdate();
}

void QmakeBuildConfiguration::emitQMakeBuildConfigurationChanged()
{
    emit qmakeBuildConfigurationChanged();
}

QStringList QmakeBuildConfiguration::configCommandLineArguments() const
{
    QStringList result;
    BaseQtVersion *version = QtKitInformation::qtVersion(target()->kit());
    BaseQtVersion::QmakeBuildConfigs defaultBuildConfiguration =
            version ? version->defaultBuildConfig() : BaseQtVersion::QmakeBuildConfigs(BaseQtVersion::DebugBuild | BaseQtVersion::BuildAll);
    BaseQtVersion::QmakeBuildConfigs userBuildConfiguration = m_qmakeBuildConfiguration;
    if ((defaultBuildConfiguration & BaseQtVersion::BuildAll) && !(userBuildConfiguration & BaseQtVersion::BuildAll))
        result << QLatin1String("CONFIG-=debug_and_release");

    if (!(defaultBuildConfiguration & BaseQtVersion::BuildAll) && (userBuildConfiguration & BaseQtVersion::BuildAll))
        result << QLatin1String("CONFIG+=debug_and_release");
    if ((defaultBuildConfiguration & BaseQtVersion::DebugBuild) && !(userBuildConfiguration & BaseQtVersion::DebugBuild))
        result << QLatin1String("CONFIG+=release");
    if (!(defaultBuildConfiguration & BaseQtVersion::DebugBuild) && (userBuildConfiguration & BaseQtVersion::DebugBuild))
        result << QLatin1String("CONFIG+=debug");
    return result;
}

QMakeStep *QmakeBuildConfiguration::qmakeStep() const
{
    QMakeStep *qs = 0;
    BuildStepList *bsl = stepList(Core::Id(ProjectExplorer::Constants::BUILDSTEPS_BUILD));
    Q_ASSERT(bsl);
    for (int i = 0; i < bsl->count(); ++i)
        if ((qs = qobject_cast<QMakeStep *>(bsl->at(i))) != 0)
            return qs;
    return 0;
}

MakeStep *QmakeBuildConfiguration::makeStep() const
{
    MakeStep *ms = 0;
    BuildStepList *bsl = stepList(Core::Id(ProjectExplorer::Constants::BUILDSTEPS_BUILD));
    Q_ASSERT(bsl);
    for (int i = 0; i < bsl->count(); ++i)
        if ((ms = qobject_cast<MakeStep *>(bsl->at(i))) != 0)
            return ms;
    return 0;
}

// Returns true if both are equal.
QmakeBuildConfiguration::MakefileState QmakeBuildConfiguration::compareToImportFrom(const QString &makefile)
{
    QMakeStep *qs = qmakeStep();
    if (QFileInfo(makefile).exists() && qs) {
        FileName qmakePath = QtVersionManager::findQMakeBinaryFromMakefile(makefile);
        BaseQtVersion *version = QtKitInformation::qtVersion(target()->kit());
        if (!version)
            return MakefileForWrongProject;
        if (QtSupport::QtVersionManager::makefileIsFor(makefile, qs->project()->projectFilePath())
                != QtSupport::QtVersionManager::SameProject) {
            if (debug) {
                qDebug() << "different profile used to generate the Makefile:"
                         << makefile << " expected profile:" << qs->project()->projectFilePath();
            }
            return MakefileIncompatible;
        }
        if (version->qmakeCommand() == qmakePath) {
            // same qtversion
            QPair<BaseQtVersion::QmakeBuildConfigs, QString> result =
                    QtVersionManager::scanMakeFile(makefile, version->defaultBuildConfig());
            if (qmakeBuildConfiguration() == result.first) {
                // The qmake Build Configuration are the same,
                // now compare arguments lists
                // we have to compare without the spec/platform cmd argument
                // and compare that on its own
                QString workingDirectory = QFileInfo(makefile).absolutePath();
                QStringList actualArgs;
                QString userArgs = qs->userArguments();
                // This copies the settings from userArgs to actualArgs (minus some we
                // are not interested in), splitting them up into individual strings:
                extractSpecFromArguments(&userArgs, workingDirectory, version, &actualArgs);
                actualArgs = qs->deducedArguments() + actualArgs + qs->deducedArgumentsAfter();
                FileName actualSpec = qs->mkspec();

                QString qmakeArgs = result.second;
                QStringList parsedArgs;
                FileName parsedSpec = extractSpecFromArguments(&qmakeArgs, workingDirectory, version, &parsedArgs);

                if (debug) {
                    qDebug() << "Actual args:" << actualArgs;
                    qDebug() << "Parsed args:" << parsedArgs;
                    qDebug() << "Actual spec:" << actualSpec.toString();
                    qDebug() << "Parsed spec:" << parsedSpec.toString();
                }

                // Comparing the sorted list is obviously wrong
                // Though haven written a more complete version
                // that managed had around 200 lines and yet faild
                // to be actually foolproof at all, I think it's
                // not feasible without actually taking the qmake
                // command line parsing code

                // Things, sorting gets wrong:
                // parameters to positional parameters matter
                //  e.g. -o -spec is different from -spec -o
                //       -o 1 -spec 2 is diffrent from -spec 1 -o 2
                // variable assignment order matters
                // variable assignment vs -after
                // -norecursive vs. recursive
                actualArgs.sort();
                parsedArgs.sort();
                if (actualArgs == parsedArgs) {
                    // Specs match exactly
                    if (actualSpec == parsedSpec)
                        return MakefileMatches;
                    // Actual spec is the default one
//                    qDebug() << "AS vs VS" << actualSpec << version->mkspec();
                    if ((actualSpec == version->mkspec() || actualSpec == FileName::fromLatin1("default"))
                        && (parsedSpec == version->mkspec() || parsedSpec == FileName::fromLatin1("default") || parsedSpec.isEmpty()))
                        return MakefileMatches;
                }
                return MakefileIncompatible;
            } else {
                if (debug)
                    qDebug() << "different qmake buildconfigurations buildconfiguration:"
                             << qmakeBuildConfiguration() << " Makefile:" << result.first;
                return MakefileIncompatible;
            }
        } else {
            if (debug)
                qDebug() << "different Qt versions, buildconfiguration:" << version->qmakeCommand().toString()
                         << " Makefile:"<< qmakePath.toString();
            return MakefileForWrongProject;
        }
    }
    return MakefileMissing;
}

bool QmakeBuildConfiguration::removeQMLInspectorFromArguments(QString *args)
{
    bool removedArgument = false;
    for (QtcProcess::ArgIterator ait(args); ait.next(); ) {
        const QString arg = ait.value();
        if (arg.contains(QLatin1String(Constants::QMAKEVAR_QMLJSDEBUGGER_PATH))
            || arg.contains(QLatin1String(Constants::QMAKEVAR_QUICK1_DEBUG))
            || arg.contains(QLatin1String(Constants::QMAKEVAR_QUICK2_DEBUG))) {
            ait.deleteArg();
            removedArgument = true;
        }
    }
    return removedArgument;
}

FileName QmakeBuildConfiguration::extractSpecFromArguments(QString *args,
                                                         const QString &directory, const BaseQtVersion *version,
                                                         QStringList *outArgs)
{
    FileName parsedSpec;

    bool ignoreNext = false;
    bool nextIsSpec = false;
    for (QtcProcess::ArgIterator ait(args); ait.next(); ) {
        if (ignoreNext) {
            ignoreNext = false;
            ait.deleteArg();
        } else if (nextIsSpec) {
            nextIsSpec = false;
            parsedSpec = FileName::fromUserInput(ait.value());
            ait.deleteArg();
        } else if (ait.value() == QLatin1String("-spec") || ait.value() == QLatin1String("-platform")) {
            nextIsSpec = true;
            ait.deleteArg();
        } else if (ait.value() == QLatin1String("-cache")) {
            // We ignore -cache, because qmake contained a bug that it didn't
            // mention the -cache in the Makefile.
            // That means changing the -cache option in the additional arguments
            // does not automatically rerun qmake. Alas, we could try more
            // intelligent matching for -cache, but i guess people rarely
            // do use that.
            ignoreNext = true;
            ait.deleteArg();
        } else if (outArgs && ait.isSimple()) {
            outArgs->append(ait.value());
        }
    }

    if (parsedSpec.isEmpty())
        return FileName();

    FileName baseMkspecDir = FileName::fromUserInput(
            version->qmakeProperty("QT_HOST_DATA") + QLatin1String("/mkspecs"));
    baseMkspecDir = Utils::FileName::fromString(baseMkspecDir.toFileInfo().canonicalFilePath());

    // if the path is relative it can be
    // relative to the working directory (as found in the Makefiles)
    // or relatively to the mkspec directory
    // if it is the former we need to get the canonical form
    // for the other one we don't need to do anything
    if (parsedSpec.toFileInfo().isRelative()) {
        if (QFileInfo(directory + QLatin1Char('/') + parsedSpec.toString()).exists())
            parsedSpec = FileName::fromUserInput(directory + QLatin1Char('/') + parsedSpec.toString());
        else
            parsedSpec = FileName::fromUserInput(baseMkspecDir.toString() + QLatin1Char('/') + parsedSpec.toString());
    }

    QFileInfo f2 = parsedSpec.toFileInfo();
    while (f2.isSymLink()) {
        parsedSpec = FileName::fromString(f2.symLinkTarget());
        f2.setFile(parsedSpec.toString());
    }

    if (parsedSpec.isChildOf(baseMkspecDir)) {
        parsedSpec = parsedSpec.relativeChildPath(baseMkspecDir);
    } else {
        FileName sourceMkSpecPath = FileName::fromString(version->sourcePath().toString()
                                                         + QLatin1String("/mkspecs"));
        if (parsedSpec.isChildOf(sourceMkSpecPath))
            parsedSpec = parsedSpec.relativeChildPath(sourceMkSpecPath);
    }
    return parsedSpec;
}

bool QmakeBuildConfiguration::isEnabled() const
{
    return m_isEnabled;
}

QString QmakeBuildConfiguration::disabledReason() const
{
    if (!m_isEnabled)
        return tr("Parsing the .pro file");
    return QString();
}

void QmakeBuildConfiguration::setEnabled(bool enabled)
{
    if (m_isEnabled == enabled)
        return;
    m_isEnabled = enabled;
    emit enabledChanged();
}

/*!
  \class QmakeBuildConfigurationFactory
*/

QmakeBuildConfigurationFactory::QmakeBuildConfigurationFactory(QObject *parent) :
    IBuildConfigurationFactory(parent)
{
    update();

    connect(QtVersionManager::instance(),
            SIGNAL(qtVersionsChanged(QList<int>,QList<int>,QList<int>)),
            this, SLOT(update()));
}

QmakeBuildConfigurationFactory::~QmakeBuildConfigurationFactory()
{
}

void QmakeBuildConfigurationFactory::update()
{
    emit availableCreationIdsChanged();
}

bool QmakeBuildConfigurationFactory::canHandle(const Target *t) const
{
    if (!t->project()->supportsKit(t->kit()))
        return false;
    return qobject_cast<QmakeProject *>(t->project());
}

QmakeBuildInfo *QmakeBuildConfigurationFactory::createBuildInfo(const Kit *k,
                                                              const QString &projectPath,
                                                              BuildConfiguration::BuildType type) const
{
    QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(k);
    QmakeBuildInfo *info = new QmakeBuildInfo(this);
    QString suffix;
    if (type == BuildConfiguration::Release) {
        //: The name of the release build configuration created by default for a qmake project.
        info->displayName = tr("Release");
        //: Non-ASCII characters in directory suffix may cause build issues.
        suffix = tr("Release", "Shadow build directory suffix");
    } else {
        //: The name of the debug build configuration created by default for a qmake project.
        info->displayName = tr("Debug");
        //: Non-ASCII characters in directory suffix may cause build issues.
        suffix = tr("Debug", "Shadow build directory suffix");
    }
    info->typeName = tr("Build");
    // Leave info->buildDirectory unset;
    info->kitId = k->id();
    info->supportsShadowBuild = (version && version->supportsShadowBuilds());
    info->buildDirectory
            = defaultBuildDirectory(info->supportsShadowBuild, projectPath, k, suffix);
    info->type = type;
    return info;
}

int QmakeBuildConfigurationFactory::priority(const Target *parent) const
{
    return canHandle(parent) ? 0 : -1;
}

QList<BuildInfo *> QmakeBuildConfigurationFactory::availableBuilds(const Target *parent) const
{
    QList<ProjectExplorer::BuildInfo *> result;
    QmakeBuildInfo *info = createBuildInfo(parent->kit(), parent->project()->projectFilePath(),
                                           BuildConfiguration::Debug);
    info->displayName.clear(); // ask for a name
    info->buildDirectory.clear(); // This depends on the displayName
    result << info;

    return result;
}

int QmakeBuildConfigurationFactory::priority(const Kit *k, const QString &projectPath) const
{
    return (k && Core::MimeDatabase::findByFile(QFileInfo(projectPath))
            .matchesType(QLatin1String(Constants::PROFILE_MIMETYPE))) ? 0 : -1;
}

QList<BuildInfo *> QmakeBuildConfigurationFactory::availableSetups(const Kit *k, const QString &projectPath) const
{
    QList<ProjectExplorer::BuildInfo *> result;
    result << createBuildInfo(k, projectPath, ProjectExplorer::BuildConfiguration::Debug);
    result << createBuildInfo(k, projectPath, ProjectExplorer::BuildConfiguration::Release);

    return result;
}

BuildConfiguration *QmakeBuildConfigurationFactory::create(Target *parent, const BuildInfo *info) const
{
    QTC_ASSERT(info->factory() == this, return 0);
    QTC_ASSERT(info->kitId == parent->kit()->id(), return 0);
    QTC_ASSERT(!info->displayName.isEmpty(), return 0);

    const QmakeBuildInfo *qmakeInfo = static_cast<const QmakeBuildInfo *>(info);

    BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(parent->kit());
    QTC_ASSERT(version, return 0);

    BaseQtVersion::QmakeBuildConfigs config = version->defaultBuildConfig();
    if (qmakeInfo->type == BuildConfiguration::Release)
        config &= ~QtSupport::BaseQtVersion::DebugBuild;
    else
        config |= QtSupport::BaseQtVersion::DebugBuild;

    QmakeBuildConfiguration *bc = new QmakeBuildConfiguration(parent);
    bc->setDefaultDisplayName(info->displayName);
    bc->setDisplayName(info->displayName);

    BuildStepList *buildSteps = bc->stepList(Core::Id(ProjectExplorer::Constants::BUILDSTEPS_BUILD));
    BuildStepList *cleanSteps = bc->stepList(Core::Id(ProjectExplorer::Constants::BUILDSTEPS_CLEAN));
    Q_ASSERT(buildSteps);
    Q_ASSERT(cleanSteps);

    QMakeStep *qmakeStep = new QMakeStep(buildSteps);
    buildSteps->insertStep(0, qmakeStep);

    MakeStep *makeStep = new MakeStep(buildSteps);
    buildSteps->insertStep(1, makeStep);

    MakeStep *cleanStep = new MakeStep(cleanSteps);
    cleanStep->setClean(true);
    cleanStep->setUserArguments(QLatin1String("clean"));
    cleanSteps->insertStep(0, cleanStep);

    QString additionalArguments = qmakeInfo->additionalArguments;

    bool enableQmlDebugger
            = QmakeBuildConfiguration::removeQMLInspectorFromArguments(&additionalArguments);
    if (!additionalArguments.isEmpty())
        qmakeStep->setUserArguments(additionalArguments);
    if (!qmakeInfo->makefile.isEmpty())
        qmakeStep->setLinkQmlDebuggingLibrary(enableQmlDebugger);

    bc->setQMakeBuildConfiguration(config);

    Utils::FileName directory = qmakeInfo->buildDirectory;
    if (directory.isEmpty()) {
        directory = defaultBuildDirectory(qmakeInfo->supportsShadowBuild,
                                          parent->project()->projectFilePath(),
                                          parent->kit(), info->displayName);
    }

    bc->setBuildDirectory(directory);
    return bc;
}

bool QmakeBuildConfigurationFactory::canClone(const Target *parent, BuildConfiguration *source) const
{
    return canHandle(parent) && qobject_cast<QmakeBuildConfiguration *>(source);
}

BuildConfiguration *QmakeBuildConfigurationFactory::clone(Target *parent, BuildConfiguration *source)
{
    if (!canClone(parent, source))
        return 0;
    QmakeBuildConfiguration *oldbc(static_cast<QmakeBuildConfiguration *>(source));
    return new QmakeBuildConfiguration(parent, oldbc);
}

bool QmakeBuildConfigurationFactory::canRestore(const Target *parent, const QVariantMap &map) const
{
    if (!canHandle(parent))
        return false;
    return ProjectExplorer::idFromMap(map) == QMAKE_BC_ID;
}

BuildConfiguration *QmakeBuildConfigurationFactory::restore(Target *parent, const QVariantMap &map)
{
    if (!canRestore(parent, map))
        return 0;
    QmakeBuildConfiguration *bc = new QmakeBuildConfiguration(parent);
    if (bc->fromMap(map))
        return bc;
    delete bc;
    return 0;
}

BuildConfiguration::BuildType QmakeBuildConfiguration::buildType() const
{
    if (qmakeBuildConfiguration() & BaseQtVersion::DebugBuild)
        return Debug;
    else
        return Release;
}

QmakeBuildConfiguration::LastKitState::LastKitState()
{

}

QmakeBuildConfiguration::LastKitState::LastKitState(Kit *k)
    : m_qtVersion(QtKitInformation::qtVersionId(k)),
      m_sysroot(SysRootKitInformation::sysRoot(k).toString()),
      m_mkspec(QmakeKitInformation::mkspec(k).toString())
{
    ToolChain *tc = ToolChainKitInformation::toolChain(k);
    m_toolchain = tc ? tc->id() : QString();
}

bool QmakeBuildConfiguration::LastKitState::operator ==(const LastKitState &other) const
{
    return m_qtVersion == other.m_qtVersion
            && m_toolchain == other.m_toolchain
            && m_sysroot == other.m_sysroot
            && m_mkspec == other.m_mkspec;
}

bool QmakeBuildConfiguration::LastKitState::operator !=(const LastKitState &other) const
{
    return !operator ==(other);
}

} // namespace QmakeProjectManager
