/*
-----BEGIN QCMOD-----
name: QCA >= 2.0
arg: with-qca-inc=[path],Path to QCA include files
arg: with-qca-lib=[path],Path to QCA library or framework files
-----END QCMOD-----
*/

// adapted from crypto.prf
static QString internal_crypto_prf(const QString &incdir, const QString &libdir, const QString &frameworkdir)
{
    QString out = QString("QCA_INCDIR = %1\n"
                          "QCA_LIBDIR = %2\n"
                          "QMAKE_RPATHDIR = %2\n"
                          "QCA_FRAMEWORKDIR = %3\n"
                          "\n"
                          "CONFIG *= qt\n"
                          "\n"
                          "LINKAGE =\n"
                          "QCA_NAME = qca-qt5\n"
                          "\n"
                          "!isEmpty(QCA_FRAMEWORKDIR): {\n"
                          "    framework_dir = $$QCA_FRAMEWORKDIR\n"
                          "    exists($$framework_dir/$${QCA_NAME}.framework) {\n"
                          "        #QMAKE_FRAMEWORKPATH *= $$framework_dir\n"
                          "        LIBS *= -F$$framework_dir\n"
                          "        INCLUDEPATH += $$framework_dir/$${QCA_NAME}.framework/Headers\n"
                          "        LINKAGE = -framework $${QCA_NAME}\n"
                          "    }\n"
                          "}\n"
                          "\n"
                          "# else, link normally\n"
                          "isEmpty(LINKAGE) {\n"
                          "    !isEmpty(QCA_INCDIR):INCLUDEPATH += $$QCA_INCDIR/QtCrypto\n"
                          "    !isEmpty(QCA_LIBDIR):LIBS += -L$$QCA_LIBDIR\n"
                          "    LINKAGE = -l$${QCA_NAME}\n"
                          "    CONFIG(debug, debug|release) {\n"
                          "        windows:LINKAGE = -l$${QCA_NAME}d\n"
                          "        mac:LINKAGE = -l$${QCA_NAME}_debug\n"
                          "    }\n"
                          "}\n"
                          "\n"
                          "LIBS += $$LINKAGE\n")
                      .arg(incdir, libdir, frameworkdir);
    return out;
}

// set either libdir or frameworkdir, but not both
static bool qca_try(Conf *conf, const QString &incdir, const QString &libdir, const QString &frameworkdir, bool release,
                    bool debug, QString *_prf)
{
    QString proextra;
    QString prf;
    if (!incdir.isEmpty() || !libdir.isEmpty() || !frameworkdir.isEmpty()) {
        prf = internal_crypto_prf(conf->escapePath(incdir), conf->escapePath(libdir), frameworkdir);
    } else {
        prf = "CONFIG += crypto\n";
    }
    proextra = "CONFIG += qt\n"
               "CONFIG -= debug_and_release debug release\n"
               "QT -= gui\n";
    proextra += prf;

    QString str = "#include <QtCrypto>\n"
                  "\n"
                  "int main()\n"
                  "{\n"
                  "    unsigned long x = QCA_VERSION;\n"
                  "    if(x >= 0x020000 && x < 0x030000) return 0; else return 1;\n"
                  "}\n";

    // test desired versions, potentially both release and debug

    if (release) {
        int ret;
        if (!conf->doCompileAndLink(str, QStringList(), QString(), proextra + "CONFIG += release\n", &ret) || ret != 0)
            return false;
    }

    if (debug) {
        int ret;
        if (!conf->doCompileAndLink(str, QStringList(), QString(), proextra + "CONFIG += debug\n", &ret) || ret != 0)
            return false;
    }

    *_prf = prf;
    return true;
}

static bool qca_try_lib(Conf *conf, const QString &incdir, const QString &libdir, bool release, bool debug,
                        QString *prf)
{
    return qca_try(conf, incdir, libdir, QString(), release, debug, prf)
        || qca_try(conf, incdir + "/Qca-qt5", libdir, QString(), release, debug, prf);
}

static bool qca_try_framework(Conf *conf, const QString &frameworkdir, bool release, bool debug, QString *prf)
{
    return qca_try(conf, QString(), QString(), frameworkdir, release, debug, prf);
}

static bool qca_try_ext_prf(Conf *conf, bool release, bool debug, QString *prf)
{
    return qca_try(conf, QString(), QString(), QString(), release, debug, prf);
}

//----------------------------------------------------------------------------
// qc_qca
//----------------------------------------------------------------------------
class qc_qca : public ConfObj {
public:
    qc_qca(Conf *c) : ConfObj(c) { }
    QString name() const { return "QCA >= 2.0"; }
    QString shortname() const { return "qca"; }
    bool    exec()
    {
        // get the build mode
#ifdef QC_BUILDMODE
        bool release = qc_buildmode_release;
        bool debug   = qc_buildmode_debug;
#else
        // else, default to just release mode
        bool release = true;
        bool debug   = false;
#endif

        QString qca_incdir, qca_libdir, qca_crypto_prf;
        qca_incdir = conf->getenv("QC_WITH_QCA_INC");
        qca_libdir = conf->getenv("QC_WITH_QCA_LIB");

#if defined(Q_OS_MAC)
        if (!qca_libdir.isEmpty() && qca_try_framework(conf, qca_libdir, release, debug, &qca_crypto_prf)) {
            conf->addExtra(qca_crypto_prf);
            return true;
        }
#endif

        if (!qca_incdir.isEmpty() && !qca_libdir.isEmpty()
            && qca_try_lib(conf, qca_incdir, qca_libdir, release, debug, &qca_crypto_prf)) {
            conf->addExtra(qca_crypto_prf);
            return true;
        }

        if (qca_try_ext_prf(conf, release, debug, &qca_crypto_prf)) {
            conf->addExtra(qca_crypto_prf);
            return true;
        }

        QStringList incs;
        QString     version, libs, other;

        if (conf->findPkgConfig("qca2-qt5", VersionMin, "2.0.0", &version, &incs, &libs, &other)) {
            for (int n = 0; n < incs.count(); ++n)
                conf->addIncludePath(incs[n]);
            if (!libs.isEmpty())
                conf->addLib(libs);
            return true;
        }

        QStringList prefixes;
#ifndef Q_OS_WIN
        prefixes += "/usr";
        prefixes += "/usr/local";
#endif
        QString prefix = conf->getenv("PREFIX");
        if (!prefix.isEmpty()) {
            prefixes += prefix;
        }

        for (int n = 0; n < prefixes.count(); ++n) {
            const QString &prefix = prefixes[n];
            if (qca_try_lib(conf, prefix + "/include", prefix + "/lib", release, debug, &qca_crypto_prf)) {
                conf->addExtra(qca_crypto_prf);
                return true;
            }
        }

        return false;
    }
};
