/*
 * Copyright (C) 2018 Tianjin KYLIN Information Technology Co., Ltd.
 *
 * 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, or (at your option)
 * 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 "users.h"

#include <QDBusInterface>
#include <QDBusMessage>
#include <QDBusArgument>
#include <QDebug>
#include <QFile>
#include <utils.h>

#include "types.h"
#include <unistd.h>
#include <sys/types.h>

QDebug operator<<(QDebug stream, const UserItem &user)
{
    stream << user.name << user.realName << user.uid
           << user.icon << user.path;
    return stream;
}

Users::Users(QObject *parent) : QObject(parent)
{
    if (Utils::isCommunity()) {
        defaultIcon = ":/image/assets/01-default-community.png";
    } else {
	//优先读取控制面板的默认头像文件，保持登录锁屏默认头像和控制面板一致
	QFile faceFile("/usr/share/ukui/faces/default.png");
        if(faceFile.exists()){
            defaultIcon =  "/usr/share/ukui/faces/default.png";
        }else{
            defaultIcon = ":/image/assets/01-default-commercial.png";
	}
    }

    loadUsers();
}

QList<UserItem> Users::getUsers()
{
    return users;
}

UserItem Users::getUserByName(const QString &name)
{
    for(int i = 0 ; i < users.size() ; i++) {
        if(users.at(i).name == name)
        {
            return users.at(i);
        }
    }
    UserItem user;
    if(name == "root")
    {
        user.icon = "/root/.face";
        if(!QFile(user.icon).exists())
        {
            user.icon = defaultIcon;
        }
    }
    else
    {
        user.icon = qgetenv("HOME")+"/.face";
        if(!QFile(user.icon).exists())
        {
            user.icon = defaultIcon;
        }
    }
    user.name = name;
    user.path = "";
    user.realName = name;
    user.uid = getuid();
    return user;
}

QString Users::getDefaultIcon()
{
    return defaultIcon;
}

bool compareBarData(const UserItem &user1, const UserItem &user2)
{
    if (user1.realName < user2.realName)
    {
        return true;
    }
    return false;
}

//https://stackoverflow.com/questions/20206376/
//how-do-i-extract-the-returned-data-from-qdbusmessage-in-a-qt-dbus-call
void Users::loadUsers()
{
    qDebug() << "loadUsers";
    actService = new QDBusInterface(ACT_DBUS_SERVICE,
                                    ACT_DBUS_PATH,
                                    ACT_DBUS_INTERFACE,
                                    QDBusConnection::systemBus());

    connect(actService, SIGNAL(UserAdded(const QDBusObjectPath&)),
            this, SLOT(onUserAdded(const QDBusObjectPath&)));
    connect(actService, SIGNAL(UserDeleted(const QDBusObjectPath&)),
            this, SLOT(onUserDeleted(const QDBusObjectPath&)));
    QDBusMessage ret = actService->call("ListCachedUsers");
    QList<QVariant> outArgs = ret.arguments();  //(QVariant(QDBusArgument,))
    QVariant first = outArgs.at(0); //QVariant(QDBusArgument,)
    const QDBusArgument &dbusArgs = first.value<QDBusArgument>();
    QDBusObjectPath path;
    dbusArgs.beginArray();
    while (!dbusArgs.atEnd())
    {
        dbusArgs >> path;
        getUser(path.path());
    }
    dbusArgs.endArray();
    qSort(users.begin(), users.end(), compareBarData);
}

UserItem Users::getUser(const QString &path)
{
    QDBusInterface iface(ACT_DBUS_SERVICE,
                         path,
                         DBUS_PROP_INTERFACE,
                         QDBusConnection::systemBus());
    QDBusMessage ret = iface.call("GetAll", ACT_USER_INTERFACE);
    QList<QVariant> outArgs = ret.arguments();
    QVariant first = outArgs.at(0);
    const QDBusArgument &dbusArgs = first.value<QDBusArgument>();
    UserItem user;
    user.path = path;
    dbusArgs.beginMap();
    while(!dbusArgs.atEnd())
    {
        QString key;
        QVariant value;
        dbusArgs.beginMapEntry();
        dbusArgs >> key >> value;
        if(key == "UserName")
        {
	    user.name = value.toString();
	}
        else if(key == "RealName")
        {
            user.realName = value.toString();
        }
        else if(key == "IconFile")
        {
            user.icon = value.toString();
            if(!QFile(user.icon).exists())
            {
                user.icon = defaultIcon;
            }
        }
        else if(key == "Uid")
        {
            user.uid = value.toUInt();
        }
        dbusArgs.endMapEntry();
    }
    dbusArgs.endMap();
    if(user.realName.isEmpty())
    {
        user.realName = user.name;
    }
    users.push_back(user);
    return user;
}

void Users::onUserAdded(const QDBusObjectPath& path)
{
    int index = findUserByPath(path.path());
    if(index >=0 &&index<users.count())
    {
        UserItem user = getUser(path.path());
        Q_EMIT userAdded(user);
    }
}
void Users::onUserDeleted(const QDBusObjectPath& path)
{
    int index = findUserByPath(path.path());
    if(index >= 0 && index<users.count())
    {
        UserItem user = users.at(index);
        users.removeAt(index);
        Q_EMIT userDeleted(user);
    }
}

int Users::findUserByPath(const QString &path)
{
    auto iter = std::find_if(users.begin(), users.end(),
                          [&](const UserItem &user){
        return user.path == path;
    });

    int index = iter - users.begin();

    return index;
}

