/*
 * Copyright (C) 2017 ~ 2017 Deepin Technology Co., Ltd.
 *
 * Author:     Iceyer <me@iceyer.net>
 *
 * Maintainer: Iceyer <me@iceyer.net>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "licenseagent.h"

#include <QFile>
#include <QDebug>
#include <QDir>
#include <QTimer>
#include <QDateTime>
#include <QTemporaryFile>
#include <QSysInfo>
#include <QSettings>
#include <QProcess>
#include <QCoreApplication>

#include <boost/smart_ptr.hpp>

#include "diskid.h"
#include "licenseinfo.h"
#include "licensekernel.h"
#include "systeminfo.h"

class LicenseAgentPrivate
{
public:
    LicenseAgentPrivate(LicenseAgent *parent) : q_ptr(parent)
    {
    }

    void delayQuit(int dealy = 10000 * 1);
    ErrorCode installLicenseFile(const QString &licenseFilename);
    ErrorCode installLicenseFileData(const QByteArray &licenseData);

    LicenseKernel   *m_kernel = nullptr;
    LicenseInfo     *m_licenseInfo = nullptr;

    LicenseAgent *q_ptr;
    Q_DECLARE_PUBLIC(LicenseAgent)
};

ErrorCode LicenseAgentPrivate::installLicenseFileData(const QByteArray &licenseData)
{
    QFile licenseFile(SYSTEM_LICENSE);

    if (!licenseFile.open(QIODevice::WriteOnly)) {
        return OpenLicenseFile;
    }

    if (!licenseFile.write(licenseData)) {
        return WriteLicenseFile;
    }

    licenseFile.close();

    QFile systemLicenseFile(SYSTEM_LICENSE);
    if (!systemLicenseFile.setPermissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner)) {
        qDebug() << "setPermissions" << SYSTEM_LICENSE << "failed";
        return SetPermissions;
    }

    return Success;
}

void LicenseAgentPrivate::delayQuit(int dealy)
{
    QTimer::singleShot(dealy, [ = ]() {
        qDebug() << "quit";
        qApp->exit(0);
    });
}

ErrorCode LicenseAgentPrivate::installLicenseFile(const QString &licenseFilename)
{
    if (SYSTEM_LICENSE == licenseFilename) {
        return Success;
    }

    QFile licenseFile(licenseFilename);

    if (!licenseFile.open(QIODevice::ReadOnly)) {
        return OpenLicenseFile;
    }

    if (QFile::exists(SYSTEM_LICENSE) && !QFile::remove(SYSTEM_LICENSE)) {
        return RemoveSystemLicense;
    }

    if (!licenseFile.copy(SYSTEM_LICENSE)) {
        return CopyLicenseFile;
    }

    licenseFile.close();

    QFile systemLicenseFile(SYSTEM_LICENSE);
    if (!systemLicenseFile.setPermissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner)) {
        qDebug() << "setPermissions" << licenseFilename << "failed";
        return SetPermissions;
    }

    return Success;
}

LicenseAgent::LicenseAgent(LicenseKernel *kernel, LicenseInfo *licenseInfo, QObject *parent) :
    QObject(parent), d_ptr(new LicenseAgentPrivate(this))
{
    Q_D(LicenseAgent);
    d->m_kernel = kernel;
    d->m_licenseInfo = licenseInfo;
}

LicenseAgent::~LicenseAgent()
{

}

void LicenseAgent::loadLicenseFile()
{
    QDir dir = QDir("/var");
    dir.mkpath("deepin");
    ImportLicenseFile(SYSTEM_LICENSE);
}

quint32 LicenseAgent::ImportSerialKey(const QString &key)
{
    Q_D(LicenseAgent);
    auto doFunc = [ = ]()-> quint32{
        QString formatKey = key.toUpper();
        qDebug() << "call ImportSerialKey" << formatKey;

        LicenseKernel checkKernel;
        checkKernel.loadKey(formatKey.toStdString().c_str());
        if (!checkKernel.isActivated())
        {
            return InvailedLicenseFile;
        }

        d->m_kernel->loadKey(formatKey.toStdString().c_str());
        auto state = d->m_licenseInfo->notifyLicenseState();

        if (Authorized != state)
        {
            qDebug() << "verfiyLicenseFile failed" << state;
            return InvailedLicenseFile;
        }

        auto ret = d->installLicenseFileData(d->m_kernel->licenseData());
        if (Success != ret)
        {
            qDebug() << "installLicenseFile" << ret;
            return ret;
        }
        return Success;
    };

    d->delayQuit();

    return doFunc();
}

quint32 LicenseAgent::ImportLicenseFile(const QString &licenseFilename)
{
    Q_D(LicenseAgent);
    auto doFunc = [ = ]()-> quint32{
        qDebug() << "call ImportLicenseFile" << licenseFilename;
        ErrorCode ret = UnknowError;

        QFile importLicenseFile(licenseFilename);
        if (!importLicenseFile.open(QIODevice::ReadOnly))
        {
            qDebug() << "importLicenseFile" << licenseFilename << "failed";
            return OpenSystemLicenseFile;
        }

        boost::scoped_array< char> licenseFileBuffer(new  char[MAX_LICENSE_SIZE]);
        auto readSize = importLicenseFile.read(licenseFileBuffer.get(), MAX_LICENSE_SIZE);
        importLicenseFile.close();
        qDebug() << "read license file with:" << readSize << "bytes";

        LicenseKernel checkKernel;
        checkKernel.loadFile(licenseFileBuffer.get());
        if (!checkKernel.isActivated())
        {
            qDebug() << "verfiyLicenseFile failed";
            return InvailedLicenseFile;
        }

        d->m_kernel->loadFile(licenseFileBuffer.get());
        auto state = d->m_licenseInfo->notifyLicenseState();

        if (Authorized != state)
        {
            qDebug() << "verfiyLicenseFile failed" << state;
            return InvailedLicenseFile;
        }

        ret = d->installLicenseFile(licenseFilename);
        if (Success != ret)
        {
            qDebug() << "installLicenseFile" << ret;
            return ret;
        }

        return Success;
    };

    d->delayQuit();

    return doFunc();
}

quint32 LicenseAgent::Deactive()
{
    Q_D(LicenseAgent);
    QFile::remove(SYSTEM_LICENSE);
    d->m_kernel->deactive();
    d->m_licenseInfo->notifyLicenseState();

    d->delayQuit();

    return Success;
}

void LicenseAgent::Quit()
{
    Q_D(LicenseAgent);
    d->delayQuit(1);
}

QString LicenseAgent::edition()
{
    return SystemInfo::getSystemEdition();
}

QString LicenseAgent::version()
{
    return SystemInfo::getSystemVersion();
}

QString LicenseAgent::copyright()
{
    return SystemInfo::getSystemCopyright();
}

QString LicenseAgent::machineCode()
{
    return SystemInfo::getSystemMachineCode();
}

QString LicenseAgent::installTime()
{
    QDir root("/");
    QFileInfo first = root.entryInfoList(
                          QDir::Dirs | QDir::Files | QDir::Drives | QDir::NoSymLinks,
                          QDir::Time).last();
    return first.created().toString(Qt::ISODate);
}

int LicenseAgent::trialRemind()
{
    QDateTime deadline = QDateTime::fromString(installTime(), Qt::ISODate).addMonths(3);
    return static_cast<int>(QDateTime::currentDateTime().daysTo(deadline));
}
