#include "commonsystemdetector.h"

#include <QDebug>
#include <QHostAddress>
#include <QNetworkInterface>
#include <QFile>
#include <QJsonArray>
#include <QJsonDocument>
#include <QCoreApplication>
#include <QJsonObject>

#include "tool.h"
#include "software.h"
#include "wpsoffice.h"
#include "yozooffice.h"

#include "util/config.h"
#include "software/filter_manager.h"

const char *OS_HISTORY_KEY = "os-7ee52f78-7b75-11e8-bd6e-fbeffeb07025";

class CommonSystemDetectorPrivate
{
public:
    CommonSystemDetectorPrivate(CommonSystemDetector *parent) : q_ptr(parent)
    {
        Q_Q(CommonSystemDetector);
        FilterManager::instance()->setPlatform(q->platform());
        systemInfo = QSharedPointer<SystemInfo>(new SystemInfo);
        softwareFilters = FilterManager::instance()->filterList();
    }

    QList<SoftwareFilter> softwareFilters;

    QJsonObject softwareUsedHistory;
    QJsonArray softinfo;

    QSharedPointer<SystemInfo> systemInfo;

    CommonSystemDetector *q_ptr;
    Q_DECLARE_PUBLIC(CommonSystemDetector)
};

CommonSystemDetector::CommonSystemDetector(QObject *parent):
    SystemDetectorInterface(parent), dd_ptr(new CommonSystemDetectorPrivate(this))
{
    Software::registerStatusHandle("WPS Office", new WPSOffice);
    Software::registerStatusHandle("Yozo Office", new YozoOffice);
}

CommonSystemDetector::~CommonSystemDetector()
{

}

QString CommonSystemDetector::version() const
{
    return qApp->applicationVersion();
}

QString CommonSystemDetector::platform() const
{
    QString platform = "";
#if defined Q_OS_WIN
    platform = "windows";
#elif defined Q_OS_MAC
    platform = "osx";
#elif defined Q_OS_LINUX
    platform = "linux";
#elif defined Q_OS_ANDROID
    platform = "android";
#elif defined Q_OS_IOS
    platform = "ios";
#endif
    return platform;
}

QSharedPointer<SystemInfo> CommonSystemDetector::fetchSystemInfo()
{
    Q_D(CommonSystemDetector);
    return d->systemInfo;
}

void CommonSystemDetector::clearCache()
{
    clearSoftwareTimes();
}

QJsonArray CommonSystemDetector::getSoftwareInfo()
{
    Q_D(CommonSystemDetector);
    return d->softinfo;
}

QList<AdapterInfo> CommonSystemDetector::queryAdapterInfo() const
{
    QList<AdapterInfo> adapters;

    for (auto &interface : QNetworkInterface::allInterfaces()) {
        auto flags = interface.flags();
        if (!flags.testFlag(QNetworkInterface::IsLoopBack) && flags.testFlag(QNetworkInterface::CanMulticast)) {
            AdapterInfo info;
            info.name = interface.name();
            info.humanReadableName = interface.humanReadableName();
            info.hardwareAddress = interface.hardwareAddress().toLower();
            info.flags = QString("%1").arg(interface.flags());
            for (auto &address : interface.addressEntries()) {
                info.addressList.push_back(address.ip().toString());
            }
            adapters.push_back(info);
        }
    }
    return adapters;
}

QList<SoftwareFilter> CommonSystemDetector::getSoftwareFilters() const
{
    Q_D(const CommonSystemDetector);
    return d->softwareFilters;
}

QJsonObject CommonSystemDetector::getSoftwareUsedHistory()
{
    Q_D(CommonSystemDetector);
    return d->softwareUsedHistory;
}

void CommonSystemDetector::setSoftareUsedHistory(const QJsonObject &softwareTimes)
{
    Q_D(CommonSystemDetector);
    d->softwareUsedHistory = softwareTimes;
}

void CommonSystemDetector::onSoftwareStarted(int pid, const QString &cmd, const qint64 startup)
{
    Q_D(CommonSystemDetector);
    qDebug() << "started: " << pid << cmd << startup;
    QJsonArray objs;
    if (d->softwareUsedHistory.contains(cmd)) {
        objs = d->softwareUsedHistory.value(cmd).toArray();
    }
    QJsonObject obj;
    obj.insert("pid", pid);
    obj.insert("startup", QString("%1").arg(startup));
    objs.append(obj);
    d->softwareUsedHistory.insert(cmd, objs);

    Q_EMIT softwareInfoCached();
}

void CommonSystemDetector::onSoftwareStoped(int pid, const QString &cmd, const qint64 shutdown)
{
    Q_D(CommonSystemDetector);
    qDebug() << "stoped: " << pid << cmd << shutdown;
    if (d->softwareUsedHistory.contains(cmd)) {
        QJsonArray objs = d->softwareUsedHistory.value(cmd).toArray();
        for (int i = 0; i < objs.count(); i++) {
            if (objs[i].toObject().value("pid").toInt() == pid) {
                QJsonObject obj = objs[i].toObject();
                obj.insert("shutdown", QString("%1").arg(shutdown));
                obj.remove("pid");
                objs[i] = obj;
            }
        }
        d->softwareUsedHistory.insert(cmd, objs);
    }
    Q_EMIT softwareInfoCached();
}

void CommonSystemDetector::clearSoftwareTimes()
{
    Q_D(CommonSystemDetector);
    d->softwareUsedHistory = QJsonObject();
}
