#include "autorunregisteroperation.h"

#include <QProcess>
#include <QCoreApplication>
#ifdef Q_OS_WIN
#include <QDir>
#include <QSysInfo>
#elif defined(Q_OS_MAC)
#include <QFile>
#include <AdminAuthorization.h>
#endif

using namespace QInstaller;

namespace
{
#ifdef Q_OS_WIN
QString windowsPath()
{
    QStringList env_list(QProcess::systemEnvironment());

    int idx = env_list.indexOf(QRegExp("^WINDIR=.*", Qt::CaseInsensitive));
    if (idx > -1) {
        QStringList windir = env_list[idx].split('=');
        // Var windir[0]
        // Path windir[1]

        return windir[1];
    }

    return QString();
}

QString schtasksCmd()
{
    // Skip unsupported desktop version
    if (QSysInfo::currentCpuArchitecture() != "x86_64" &&
        QSysInfo::currentCpuArchitecture() != "i386")
        return QString();

    if (windowsPath().isEmpty())
        return QString();

    const QString cmd_x86_64 = QString("%1/sysnative/cmd.exe /C schtasks.exe").arg(windowsPath());
    const QString cmd_i386 = QString("%1/system32/cmd.exe /C schtasks.exe").arg(windowsPath());

    // Convert native separators
    return QFileInfo(QSysInfo::currentCpuArchitecture() == "x86_64" ? cmd_x86_64 : cmd_i386).absoluteFilePath();
}
#elif defined(Q_OS_MAC)
QString launchAgentsPath()
{
    return QString("/Library/LaunchAgents");
}
QString launchAgentsPlistPath()
{
    return QString("%1/%2.%3_autolaunch.plist")
        .arg(launchAgentsPath())
        .arg("com.lacie")
        .arg("lacie");
}
#endif

bool isAutoLaunchApplicable()
{
#ifdef Q_OS_WIN
    return !windowsPath().isEmpty();
#elif defined(Q_OS_MAC)
    return true;
#endif

    // By default
    return false;
}

bool isAutoLaunchEnabled(const QString &taskName = QString("LaCie RAID Manager"))
{
    if (!isAutoLaunchApplicable())
        return false;

#ifdef Q_OS_WIN
    QString cmd = schtasksCmd();
    if (cmd.isEmpty())
        return false;

    QProcess p;
    p.start(cmd);
    p.waitForFinished();

    QString data = p.readAll();
    return (data.contains(taskName, Qt::CaseInsensitive));
#elif defined(Q_OS_MAC)
    return QFile::exists(launchAgentsPlistPath());
#endif

    // By default
    return false;
}

bool setAutoLaunchEnabled(bool v, const QString &path, const QString &taskName)
{
    if (!isAutoLaunchApplicable())
        return false;

    if (isAutoLaunchEnabled() == v)
        return true;

#ifdef Q_OS_WIN
    QString cmd = schtasksCmd();
    if (cmd.isEmpty())
        return false;

    QProcess p;
    QStringList args;
    if (v) {
        args = QStringList{"/create",
                           "/sc",
                           "onlogon",
                           "/tn",
                           QString("\"%1\"").arg(taskName),
                           "/rl",
                           "highest",
                            "/tr",
                           QString(R"("\"%1\" --minimized=true")").arg(QDir::toNativeSeparators(path))};
    }
    else {
        args = QStringList{"/delete",
                           "/f",
                           "/tn",
                           QString("\"%1\"").arg(taskName)};
    }

    p.setNativeArguments(args.join(" "));
    p.start(cmd);
    p.waitForFinished();

    return (p.exitCode() == 0);
#elif defined(Q_OS_MAC)
    const QString cmd("/bin/sh");
    QStringList args{"-c"};
    if (v) {
        static QString plistXMLContent(R"(<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>%1.autolaunch</string>
  <key>ProgramArguments</key>
  <array>
      <string>%2</string>
      <string>--minimized=true</string>
  </array>
  <key>RunAtLoad</key>
  <true/>
</dict>
</plist>)");
        QString xmlData = plistXMLContent.arg("com.lacie").arg(path);
        args.push_back(QString("echo \"%1\" >> \"%2\"").arg(xmlData).arg(launchAgentsPlistPath()));
    }
    else {
        args.push_back(QString("rm \"%1\"").arg(launchAgentsPlistPath()));
    }

    QProcess p;
    p.start(cmd, args);
    p.waitForFinished();

    return (p.exitCode() == 0);
#endif

    return true;
}
}

AutorunRegisterOperation::AutorunRegisterOperation()
{
    setName(QLatin1String("AutorunRegister"));
}

void AutorunRegisterOperation::backup()
{
}

bool AutorunRegisterOperation::performOperation()
{    
    const QStringList args = arguments();

    if (args.count() != 2 && args.count() != 3) {
        setError(InvalidArguments);
        setErrorString(QString("Invalid arguments in %0: %1 arguments given, %2 expected%3.")
            .arg(name()).arg(arguments().count()).arg(tr("2 or 3")));
        return false;
    }

    const QString path = args.at(0);
    const QString taskName = args.at(1);

    return setAutoLaunchEnabled(true, path, taskName);
}

bool AutorunRegisterOperation::undoOperation()
{
    const QStringList args = arguments();

    if (args.count() != 2 && args.count() != 3) {
        setError(InvalidArguments);
        setErrorString(QString("Invalid arguments in %0: %1 arguments given, %2 expected%3.")
            .arg(name()).arg(arguments().count()).arg(tr("2 or 3")));
        return false;
    }

    const QString path = args.at(0);
    const QString taskName = args.at(1);

    return setAutoLaunchEnabled(false, path, taskName);
}

bool AutorunRegisterOperation::testOperation()
{
    return isAutoLaunchApplicable();
}

Operation *AutorunRegisterOperation::clone() const
{
    return new AutorunRegisterOperation();
}
