/*
 * Copyright (C) 2016 ~ 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 "systeminfo.h"

#include <QDebug>
#include <QSettings>
#include <QProcess>

#include "diskid.h"

namespace SystemInfo
{

typedef QMap<QString, QString> DiskInfo;

QString stripValue(QString value)
{
    if (value.length() >= 2) {
        if (value.at(value.length() - 1) == '"') {
            value = value.left(value.length() - 1);
        }

        if (value.at(0) == '"') {
            value = value.right(value.length() - 1);
        }
    }
    return value;
}

QList<DiskInfo> parseLsblk(const QString &lsblkOut)
{
    QList<DiskInfo> disks;
    auto entrys = lsblkOut.split("\n");
    for (auto entry : entrys) {
        DiskInfo info;
        auto propertys = entry.split(" ");
        for (auto pro : propertys) {
            auto kv = pro.split("=");
            if (kv.length() != 2) {
                continue;
            }
            info.insert(kv.value(0), stripValue(kv.value(1)));
        }
        disks << info;
    }
    return disks;
}

QList<DiskInfo> getMountDisk()
{
    QProcess lsblk;
    lsblk.setProgram("lsblk");
    lsblk.setArguments(QStringList() << "-P");
    lsblk.start();
    lsblk.waitForFinished();

    auto rootMountpoint = QStringList() << "/" << "/boot";
    auto lsblkOut = QString::fromLatin1(lsblk.readAll());
    auto disks = parseLsblk(lsblkOut);
    QList<DiskInfo> mountDisk;
    for (auto disk : disks) {
        auto mp =  disk.value("MOUNTPOINT");

        if (! rootMountpoint.contains(mp)) {
            continue;
        }
        mountDisk << disk;
    }
    return mountDisk;
}

QList<DiskInfo> getPhyDisk()
{
    QProcess lsblk;
    lsblk.setProgram("lsblk");
    lsblk.setArguments(QStringList() << "-P" << "-d");
    lsblk.start();
    lsblk.waitForFinished();

    auto lsblkOut = QString::fromLatin1(lsblk.readAll());
    return parseLsblk(lsblkOut);
}

QString getDiskMaj(const DiskInfo &disk)
{
    auto mm = disk.value("MAJ:MIN");
    auto mms = mm.split(":");
    if (mms.length() != 2) {
        return "";
    }
    return mms.first();
}

QString getRootDisk()
{
    auto mountDisk = getMountDisk();
    auto phyDisk = getPhyDisk();

    for (auto disk : mountDisk) {
        auto maj = getDiskMaj(disk);
        for (auto phy : phyDisk) {
            auto phyMaj = getDiskMaj(phy);
            if (phyMaj == maj) {
                return  QString("/dev/%1").arg(phy.value("NAME"));
            }
        }
    }
    return "";
}

QString getSystemMachineCode()
{
    unsigned char id[MD5_DIGEST_LENGTH];
    auto diskName = getRootDisk();
    diskid(diskName.toStdString().c_str(), id);
    for (int i = 0; i < MD5_DIGEST_LENGTH / 2; i++) {
        id[i] = id[i] / 2 + id[MD5_DIGEST_LENGTH - 1 - i] / 2;
    }

    QString machine_code;
    for (int i = 0; i < 4; i++) {
        machine_code.append(QString().sprintf("%02x", id[i * 4]));
        machine_code.append(QString().sprintf("%02x", id[i * 4 + 1]));
        if (i < 3) {
            machine_code += "-";
        }
    }
    return machine_code;
}

QString getSystemCopyright()
{
    QSettings deepin_version("/etc/deepin-version", QSettings::IniFormat);
    deepin_version.setIniCodec("UTF8");
    QString systemType = deepin_version.value("Release/Copyright").toString();
    return systemType;
}

QString getSystemEdition()
{
    QSettings deepin_version("/etc/deepin-version", QSettings::IniFormat);
    deepin_version.setIniCodec("UTF8");
    QString systemType = deepin_version.value("Release/Edition").toString();
    return systemType;
}

QString getSystemVersion()
{
    QSettings deepin_version("/etc/deepin-version", QSettings::IniFormat);
    deepin_version.setIniCodec("UTF8");
    QString systemType = deepin_version.value("Release/Version").toString();
    return systemType;
}

QString getSystemMajorVersion()
{
    return getSystemVersion().split(".").first();
}

}
