#include "libkysysinfo.h"
#include <dbus-1.0/dbus/dbus.h>
#include <kysdk/kysdk-base/cstring-extension.h>
#include <kysdk/kysdk-base/libkylog.h>
#include <pwd.h>
#include <stdio.h>
#include <unistd.h>
#include "dlfcn.h"

#define KYLIN_ACTIVATION_DBUS_ADDRESS   "org.freedesktop.activation"


static char* get_val_from_file(FILE *fp, const char *key)
{
    if (! fp)
        return NULL;
    char *val = NULL;
    char buf[1024] = {0};
    while (fgets(buf, 1024, fp))
    {
        if (strncmp(buf, key, strlen(key)) == 0)
        {
            val = strdup((char*)buf + strlen(key) +1);
            break;
        }
    }

    return val;
}

char* kdk_system_get_architecture()
{
    char *architecture = NULL;
#ifdef __linux__
    FILE *fp = fopen("/proc/osinfo", "r");
    if (!fp)
        return NULL;
    
    architecture = get_val_from_file(fp, "Architecture");
    if (!architecture)
        return NULL;
    strstrip(architecture, '\n');
    strstrip(architecture, '\t');

    fclose(fp);
#endif
    return architecture;
}

char* kdk_system_get_systemName()
{
    char *sysname = NULL;
#ifdef __linux__
    FILE *fp = fopen("/etc/os-release", "r");
    if (! fp)
        return NULL;
    
    sysname = get_val_from_file(fp, "NAME");
    if (!sysname)
        return NULL;
    strstrip(sysname, '\n');
    strstrip(sysname, '\"');

    fclose(fp);
#endif
    return sysname;
}

char* kdk_system_get_version(bool verbose)
{
    char *sysversion = NULL;
    if (verbose)
    {
#ifdef __linux__
        FILE *fp = fopen("/etc/.kyinfo", "r");
        if (!fp)
            return NULL;
        
        sysversion = get_val_from_file(fp, "milestone");
        if (!sysversion)
        {
            fclose(fp);
            return NULL;
        }
        fclose(fp);
    }
    else
    {
        FILE *fp = fopen("/etc/os-release", "r");
        if (!fp)
            return NULL;
        
        sysversion = get_val_from_file(fp, "VERSION");
        if (!sysversion)
        {
            fclose(fp);
            return NULL;
        }
        strstrip(sysversion, '\"');
        fclose(fp);
    }
    strstrip(sysversion, '\n');
    strstrip(sysversion, '\"');
#endif
    return sysversion;
}

int kdk_system_get_activationStatus(int *status_error_num,int *date_error_num)
{
    if (NULL == status_error_num || NULL == date_error_num)
    {
        klog_err("激活状态接口调用失败：参数错误\n");
        return -1;
    }
    
    int res = 0;

// #define _KYLIN_ACTIVATION_H_
#ifdef  __linux__
#ifdef _KYLIN_ACTIVATION_H_
    int err;
    int ret = -1;

    typedef int (*kylin_activation_activate_status)(int *);
    typedef int (*kylin_activation_trial_status)(int *);
    void *hwnd = dlopen("/usr/lib/libkylin-activation.so", RTLD_LAZY);

    if (!hwnd)
    {
        klog_err("加载libkylin-activation.so失败\n");
        return ret;
    }

    do
    {
        kylin_activation_activate_status pkylin_activation_activate_status = (kylin_activation_activate_status)dlsym(hwnd, "kylin_activation_activate_status");
        kylin_activation_trial_status pkylin_activation_trial_status = (kylin_activation_trial_status)dlsym(hwnd, "kylin_activation_trial_status");

        if (!pkylin_activation_activate_status || !pkylin_activation_trial_status)
        {
            klog_err("获取接口地址失败\n");
            break;
        }
        res = pkylin_activation_activate_status(&err);
        if (err != 0)
        {
            klog_err("激活状态获取失败：%d\n", err);
            ret = 0;
            break;
        }
        if (res)
        {
            ret = 1;
            break;
        }

        res = pkylin_activation_trial_status(&err);
        if (err != 0)
        {
            klog_err("试用状态获取失败：%d\n", err);
            ret = 0;
            break;
        }

        if (res == 1)
        {
            ret = 0;
            break;
        }
    } while (false);

    dlclose(hwnd);
    return ret;
#else // 修改dbus通信
    DBusConnection *conn;
    DBusError err;
    int ret;

    dbus_error_init(&err);
    conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);

    if (dbus_error_is_set(&err)) {
        fprintf(stderr, "Connection Error (%s)\n", err.message);
        dbus_error_free(&err);
    }

    if (NULL == conn) {
    return -1;
    }

    DBusMessage* status_msg=NULL;
    DBusMessage* status_pending_msg=NULL;
    DBusMessage* date_msg=NULL;
    DBusMessage* date_pending_msg=NULL;
    DBusMessageIter args;
    DBusPendingCall* status_pending=NULL;
    DBusPendingCall* date_pending=NULL;
    int stat;

    //获取激活状态
    status_msg = dbus_message_new_method_call("org.freedesktop.activation", // target for the method call
                                   "/org/freedesktop/activation", // object to call on
                                   "org.freedesktop.activation.interface", // interface to call on
                                   "status"); // method name

    if (!status_msg)
    { // -1 is default timeout
        klog_err("status_msg：dbus_message_new_method_call调用失败\n");
        return -1;
    }

    if (!dbus_connection_send_with_reply (conn, status_msg, &status_pending, -1)) { // -1 is default timeout
        klog_err("status_msg：dbus_connection_send_with_reply调用失败\n");
        return -1;
    }
    if (NULL == status_pending){
        klog_err("status_pending：返回值为null\n");
        return -1;  
    }
    dbus_connection_flush(conn);
    dbus_message_unref(status_msg);

    //接收返回值
    dbus_pending_call_block(status_pending); 
    status_pending_msg = dbus_pending_call_steal_reply(status_pending);
    if (NULL == status_pending_msg) {
        klog_err("status_pending_msg：获取激活状态接口返回值异常\n");
        return -1;
    }

    //释放status_pending
    dbus_pending_call_unref(status_pending);

    if (!dbus_message_iter_init(status_pending_msg, &args)){
        klog_err("status_pending_msg：dbus_message_iter_init获取激活状态接口返回值异常\n");
        return -1;
    }
    else
        dbus_message_iter_get_basic(&args, &stat);
    if (!dbus_message_iter_next(&args)){
        klog_err("status_pending_msg：dbus_message_iter_next获取激活状态接口返回值异常\n");
        return -1;
    }
    else
        dbus_message_iter_get_basic(&args, status_error_num);
    klog_debug("激活状态：%d，错误码：%d\n",stat,*status_error_num);

    //释放status_pending_msg
    dbus_message_unref(status_pending_msg);

    if (stat == 0)
    {
        char *date_stat;
        
        //获取技术服务日期
        date_msg = dbus_message_new_method_call("org.freedesktop.activation", // target for the method call
                            "/org/freedesktop/activation", // object to call on
                            "org.freedesktop.activation.interface", // interface to call on
                            "date"); // method name
        if (!dbus_connection_send_with_reply (conn, date_msg, &date_pending, -1)) { // -1 is default timeout
            klog_err("date_msg：dbus_connection_send_with_reply 接口调用失败\n");
            return -1;
        }
        if (NULL == date_pending){
            klog_err("date_pending：返回值为null\n");
            return -1;
        }
        dbus_connection_flush(conn);
        dbus_message_unref(date_msg);
        //接收返回值
        dbus_pending_call_block(date_pending); 
        date_pending_msg = dbus_pending_call_steal_reply(date_pending);

        if (NULL == date_pending_msg) {
            klog_err("date_pending_msg：Reply Null\n"); 
            return -1;
        }
        if (!dbus_message_iter_init(date_pending_msg, &args)){
            dbus_message_unref(date_pending_msg);
            klog_err("date_pending_msg：dbus_message_iter_init获取技术服务日期接口返回值异常\n");
            return -1;
        }
        else
            dbus_message_iter_get_basic(&args, &date_stat);
        if (!dbus_message_iter_next(&args)){
            dbus_message_unref(date_pending_msg);
            klog_err("date_pending_msg：dbus_message_iter_next获取技术服务日期接口返回值异常\n");
            return -1;
        }
        else
            dbus_message_iter_get_basic(&args, date_error_num);
        klog_debug("技术服务日期：%s，错误码：%d\n",date_stat,*date_error_num);
        if (*date_error_num == 0)
        {
            if (strcmp(date_stat, ""))
            {
                dbus_message_unref(date_pending_msg);
                return 2;
            }
            else
            {
                dbus_message_unref(date_pending_msg);
                return 0;
            }  
        }
        else{
            return 0;
        }
    }
    else if(stat == 1)
    {
        return 1;
    }
    
// #endif  // _KYLIN_ACTIVATION_H_
// #endif  // __linux__
    if (status_msg)
    {
        dbus_message_unref(status_msg);
    }
    if (status_pending_msg)
    {
        dbus_message_unref(status_pending_msg);
    }
    if (date_msg)
    {
        dbus_message_unref(date_msg);
    }
    if (date_pending_msg)
    {
        dbus_message_unref(date_pending_msg);
    }
    if (status_pending)
    {
        dbus_pending_call_unref(status_pending);
    }
    if (date_pending)
    {
        dbus_pending_call_unref(date_pending);
    }
    return 0;
#endif  // _KYLIN_ACTIVATION_H_
#endif  // __linux__
}

char* kdk_system_get_serialNumber()
{
    char *serial = NULL;
#ifdef  __linux__
#ifndef _KYLIN_ACTIVATION_H_ //修改成dbus通信
    FILE *fp = fopen("/etc/.kyinfo", "r");
    if (!fp)
        return NULL;
    
    serial = get_val_from_file(fp, "key");
    fclose(fp);
    if (serial)
        strskipspace(serial);
#else
    int err;

    typedef char *(*kylin_activation_get_serial_number)(int *);
    void *hwnd = dlopen("/usr/lib/libkylin-activation.so", RTLD_LAZY);

    if (!hwnd)
    {
        klog_err("加载libkylin-activation.so失败\n");
        return serial;
    }
    kylin_activation_get_serial_number pkylin_activation_get_serial_number = (kylin_activation_get_serial_number)dlsym(hwnd,"kylin_activation_get_serial_number");
    if(!pkylin_activation_get_serial_number)
    {
        klog_err("加载接口kylin_activation_get_serial_number失败\n");
        return serial;
    }
    serial = pkylin_activation_get_serial_number(&err);
    if (!serial)
    {
        klog_err("序列号获取失败：%d\n", err);
    }
    else
    {
        strskipspace(serial);
    }
    dlclose(hwnd);
    return serial;
#endif  // _KYLIN_ACTIVATION_H_
#endif  // __linux__
    return serial;
}

char* kdk_system_get_kernelVersion()
{
    char *kernver = NULL;
#ifdef __linux__
    FILE *fp = fopen("/proc/version", "r");
    if (!fp)
        return NULL;
    
    char buf[1024];
    if (fgets(buf, 1024, fp) == NULL)
    {
        fclose(fp);
        return NULL;
    }
    fclose(fp);

    char *p = buf;
    size_t pos = strfirstof(p, ' ');
    p += pos +1;
    pos = strfirstof(p, ' ');
    p += pos +1;
    size_t endpos = strfirstof(p, ' ');
    kernver = strndup(p, endpos);
#endif

    return kernver;
}

char* kdk_system_get_eUser()
{
    char *loginName = NULL;
#ifdef __linux__
    loginName = strdup(getpwuid(getuid())->pw_name);
#endif
    return loginName;
}

char* kdk_system_get_projectName()
{
    char *project_codename = NULL;
#ifdef __linux__
    FILE *fp = fopen("/etc/lsb-release", "rt");
    if (fp)
    {
        project_codename = get_val_from_file(fp, "PROJECT_CODENAME");
        fclose(fp);
    }

    if (!project_codename)
    {
        fp = fopen("/etc/os-release", "rt");
        ASSERT_NOT_NULL(fp, NULL);
        project_codename = get_val_from_file(fp, "PROJECT_CODENAME");
        fclose(fp);
    }
    if (project_codename)
        strstripspace(project_codename);
#endif
    return project_codename;
}

char* kdk_system_get_hostVirtType()
{
    char *virtType = (char*)malloc(sizeof(char) * 65);
    ASSERT_NOT_NULL(virtType, NULL);
#ifdef __linux__
    FILE *pipeLine = popen("systemd-detect-virt", "r");  // 建立流管道
    if (!pipeLine)
    {
        free(virtType);
        return NULL;
    }
    if (fgets(virtType, 64 * sizeof(char), pipeLine) == NULL)
    {
		SAFE_FREE(virtType);
        pclose(pipeLine);
        return NULL;
	}
    pclose(pipeLine);
    strstripspace(virtType);
    if (strcmp(virtType, "microsoft") == 0)
        strcpy(virtType, "hyper-v");
    else if (strcmp(virtType, "oracle") == 0)
        strcpy(virtType, "orcale virtualbox");
#endif
    return virtType;
}

char* kdk_system_get_hostCloudPlatform()
{
    char *cloudplat = (char *)malloc(sizeof(char) * 65);
    ASSERT_NOT_NULL(cloudplat, NULL);
#ifdef __linux__
    cloudplat[0] = 0;
    char buf[256] = {0};
    bool res_flag = false;
    if (geteuid() == 0) // root 用户，可以用dmidecode
    {
        FILE *pipeLine = popen("dmidecode -s chassis-manufacturer", "r");
        if (__glibc_likely(pipeLine != NULL))
        {
            fgets(buf, 255 * sizeof(char), pipeLine);
            strstripspace(buf);
            if (strcmp(buf, "Huawei Inc.") == 0)        // 华为云
            {
                strcpy(cloudplat, "huawei");
                res_flag = true;
            }
            pclose(pipeLine);
        }
        if (!res_flag)
        {
            pipeLine = popen("dmidecode -s chassis-asset-tag", "r");
            if (__glibc_likely(pipeLine != NULL))
            {
                fgets(buf, 255 * sizeof(char), pipeLine);
                strstripspace(buf);
                if (strcmp(buf, "HUAWEICLOUD") == 0)    // 华为云
                {
                    strcpy(cloudplat, "huawei");
                }
                pclose(pipeLine);
            }
        }
    }
    else        // 普通用户，只能读取文件
    {
        FILE *fp = fopen("/sys/devices/virtual/dmi/id/chassis_vendor", "rt");
        if (__glibc_likely(fp != NULL))
        {
            fgets(buf, 255 * sizeof(char), fp);
            strstripspace(buf);
            if (strcmp(buf, "Huawei Inc.") == 0)        // 华为云
            {
                strcpy(cloudplat, "huawei");
                res_flag = true;
            }
            fclose(fp);
        }
        if (!res_flag)
        {
            fp = fopen("chassis_asset_tag", "r");
            if (__glibc_likely(fp != NULL))
            {
                fgets(buf, 255 * sizeof(char), fp);
                strstripspace(buf);
                if (strcmp(buf, "HUAWEICLOUD") == 0)    // 华为云
                {
                    strcpy(cloudplat, "huawei");
                }
                fclose(fp);
            }
        }
    }

    if (strlen(cloudplat) == 0)
        strcpy(cloudplat, "none");
#endif
    return cloudplat;
}

bool kdk_system_is_zyj(void)
{
    bool bool_value = false;
    char *project_codename = kdk_system_get_projectName();
    
    if (project_codename && (strstr(project_codename, "zyj") || strstr(project_codename, "ZYJ")))
        bool_value = TRUE;
        
    SAFE_FREE(project_codename);
    return bool_value;
}
