#include "kydoctor-server.h"
#define ERRORCODE_FILE_LEN 10240

#define WHITESPACE        " \t\n\r"

static int safe_autolu(const char *s, unsigned long *ret_lu)
{
        char *endptr = NULL;
        unsigned long ul;

        s += strspn(s, WHITESPACE);

        ul = strtoul(s, &endptr, 0);

        //printf("endptr:%s\n", endptr);
        if (endptr == s || !endptr)
                return -1;
        if (*s == '-')
                return -1;

        *ret_lu = ul;

        return 0;
}

static int execcmd(char* cmd, char* result)
{
        int ret = 0;

        FILE* fp = popen(cmd, "r");  // 建立流管道
        if (!fp) {
                syslog(LOG_INFO, "run cmd %s fail, errno:%d\n", cmd, errno);
                return 0;
        }
        else {
                ret = fread(result, 1, READ_DATA_SIZE, fp);
                if (ret) {
                        syslog(LOG_INFO, "run cmd %s result %s", cmd, result);
                }
                else {
                        syslog(LOG_INFO, "run cmd %s fail or no result", cmd);
                }
        }

        pclose(fp);

        return ret;
}

/*
DBus GetCheckList() -> (String list)
返回值为 Json 格式：
Category：分类
Types：检测项数组，其中每一个对象代表一个检测项
    Type：检测项的标识，用于唯一标识一个检测项
    Name：检测项在界面上显示的名字
    Desc：检测项在界面上显示的描述

[
   //例子
    { 
        "Category": "系统服务",
        "Types": [
            {
                "Type": "0x0300060000000000",
                "Name": "网络",
                "Describe": "检测网络是否正常"
            },
            {
                "Type": "0x0300090000000000",
                "Name": "电源管理",
                "Describe": "检测电源管理是否正常"
            }
        ]
    }
]
*/
static int method_csql_get_checklist(){
     sqlite3 *db;
        int state = sqlite3_open("/opt/kydoctor/common/db/solution_key.db",&db);

        if(!state)
        {
                syslog(LOG_INFO,"database success!\n");
        }
        else
        {
                syslog(LOG_ERR,"database error!\n");
                return -1;
        }

        if(sqlite3_key(db,"kydoctor123",strlen("kydoctor123")) != SQLITE_OK)
        {
                syslog(LOG_ERR,"key error!\n");
                return -1;
        }
        int nrow = 0;
        int ncolumn = 0;
        char **azResult = NULL;
        char *zErrMsg = 0;
        char *select_sql = "select * from checkitemlist";
        int fd = 0;
        sqlite3_get_table(db,select_sql,&azResult,&nrow,&ncolumn,&zErrMsg);
        syslog(LOG_INFO,"row:%d,column:%d\n",nrow,ncolumn);

        fd = open("/tmp/kydoctor_c_sql",O_RDWR|O_CREAT|O_TRUNC,0666);
        if(fd == -1)
        {
                syslog(LOG_ERR,"open /tmp/kydoctor_c_sql error");
                sqlite3_close(db);  
                return -1;   
        }
        for(int i =1;i < nrow+1;i++)
        {
                //printf("row = ");
                for(int j = 0;j<ncolumn;j++)
                {
                        //printf(" %s ",azResult[i*ncolumn+j]);
                        write(fd,azResult[i*ncolumn+j],strlen(azResult[i*ncolumn+j]));
                        write(fd,"+++",3);
                }
                write(fd,"\n",1);
        }
        close(fd);
        sqlite3_close(db);
        return 0;
   
}
static int method_get_checklist(sd_bus_message* message, void* userdata, sd_bus_error* ret_error) {
       long file_size = 0;
        char *json_buff = NULL;
        FILE* jsonfp;
        size_t ret_size = 0, leave_size = 0;
        int ret = 0;
        char *json_str = NULL;
        int r;
        if(method_csql_get_checklist() == -1)
        {
                syslog(LOG_ERR,"method_csql_get_checklist() == -1\n");
                return -1;
        }
        //通过python，对数据库进行处理
        ret = system("python3 /opt/kydoctor/python_src/checkitemlist.py");
        if (ret != 0)
        {
           syslog(LOG_ERR, "Failed to exec python3 /opt/kydoctor/python_src/checkitemlist.py");   
           return -1;  
        }
        syslog(LOG_INFO,"python ok!\n");
        //核对/tmp/kydoctor文件是否存在，不存在返回-1


        jsonfp= fopen(CHECECKITEM_JSON_PATH, "r");
        if (jsonfp == NULL)
        {
                syslog(LOG_ERR, "Failed to opencheckitem.josn.");
                return -1;
        }

        fseek(jsonfp, 0, SEEK_END);
        file_size = ftell(jsonfp);
        rewind(jsonfp);

        json_buff = (char *)malloc(sizeof(char) * file_size);
        memset(json_buff, 0, sizeof(char) * file_size);
        leave_size = file_size;

        do {
                ret_size = fread(&json_buff[file_size - leave_size], sizeof(char), leave_size, jsonfp);
                if (feof(jsonfp)) {
			syslog(LOG_INFO, "end of file\n");
                        break;
		}
                if (ferror(jsonfp)) {
                        syslog(LOG_ERR, "read file error.");
                        break;
                }
                if (ret_size < leave_size)
                       leave_size -=  ret_size;
        } while (1);

        fclose(jsonfp);

	//syslog(LOG_INFO, "%s\n", json_buff);

         // 解析json字符串为json对象或数组
        cJSON* json = cJSON_Parse(json_buff);
        // 判断解析是否成功
        if (json == NULL) {
                syslog(LOG_INFO, "parse json fail");
                r = -1;
                goto fail;
        } else {
                json_str = cJSON_Print(json);
                syslog(LOG_INFO, "%s\n", json_str);
                r = sd_bus_reply_method_return(message, "s", json_str);
                cJSON_Delete(json);
        }
fail:
        free(json_buff);

        return r;
}

int cJson_find_Describe(char *file_name,char *outstr) {
    //char json_str[2048] = "[{\"name\": \"Tom\", \"age\": 25}, {\"name\": \"Jerry\", \"age\": 30}]";
    char json_str[ERRORCODE_FILE_LEN] = {0};
    int fd = open("/opt/kydoctor/common/errocode.json",O_RDONLY);

    if(fd == -1)
    {
        perror("open:");
        return -1;
    }

    if(read(fd,json_str,ERRORCODE_FILE_LEN) == -1)
    {
        perror("read:");
        return -1;
    }

    syslog(LOG_INFO, "error json: %s\n", json_str);

    // 解析json字符串为json对象或数组
    cJSON* json = cJSON_Parse(json_str);

    // 判断解析是否成功
    if (json == NULL) {
        const char* error_ptr = "error";//cJSON_GetErrorPtr();
        if (error_ptr != NULL) {
            syslog(LOG_INFO, "Error before: %s\n", error_ptr);
        }
        return -1;
    }

    // 解析成功后，可以进行进一步的操作，比如获取数组的长度
    int array_size = cJSON_GetArraySize(json);
    syslog(LOG_INFO, "Array size: %d\n", array_size);

    // 遍历数组元素并获取指定字段的值
    for (int i = 0; i < array_size; i++) {
        cJSON* array_item = cJSON_GetArrayItem(json, i);
        cJSON* ErrorCode_obj = cJSON_GetObjectItem(array_item, "ErrorCode");
        cJSON* Describe_obj = cJSON_GetObjectItem(array_item, "Describe");
        syslog(LOG_INFO, "Name: %s, Age: %s\n", ErrorCode_obj->valuestring, Describe_obj->valuestring);
        //if (cJSON_IsString(name_obj) && cJSON_IsNumber(age_obj))
        if(strcmp(file_name,ErrorCode_obj->valuestring) == 0) 
        {
            strcpy(outstr,Describe_obj->valuestring);
            break;
        }
    }

    // 释放json对象
    cJSON_Delete(json);
    return 0;
}

/*
接口定义： 支持那些检测功能
CheckItem(int64 checkitem) -> (String result)
@type：为  GetCheckList 接口中返回的 Type 字段的值
@result：返回值为 Json 格式：

{
    "Overview": "检测了 10 项，7 项正确，3 项错误",
    "Details": [
        {
            "ErrorCode": "123456",
            "Describe": "错误原因描述"
        },
        {
            "ErrorCode": "9876",
            "Describe": "错误原因描述"
        }
    ]
}
*/

static int method_csql_checkitem(unsigned long int num_in){
        char buf[20] = {};
        char buf1[20] = {};
        memset(buf,0,20);
        memset(buf1,0,20);

        sprintf(buf,"%lx",num_in);
        if(strlen(buf) == 15)
        {
                buf1[0] = '0';
                buf1[1] = 'x';
                buf1[2] = '0';
                strcat(buf1,buf);
        }
        else{
                buf1[0] = '0';
                buf1[1] = 'x';
                strcat(buf1,buf);
        }
        for(int i = 8;i < 20;i++)
        {
                buf1[i] = 0;
        }

        sqlite3 *db;
        int state = sqlite3_open("/opt/kydoctor/common/db/solution_key.db",&db);

        if(!state)
        {
                syslog(LOG_INFO,"database success!\n");
        }
        else
        {
                syslog(LOG_ERR,"database error!\n");
                return -1;
        }

        if(sqlite3_key(db,"kydoctor123",strlen("kydoctor123")) != SQLITE_OK)
        {
                syslog(LOG_ERR,"key error!\n");
                return -1;
        }
        int nrow = 0;
        int ncolumn = 0;
        char **azResult = NULL;
        char *zErrMsg = 0;
        //char *select_sql = "select * from checkitemlist";
        char select_sql[256] = {0};
        int fd = 0;
        sprintf(select_sql,"select * from errordata where error_cls='%s'",buf1);
        syslog(LOG_INFO,"select_sql = %s\n",select_sql);
        sqlite3_get_table(db,select_sql,&azResult,&nrow,&ncolumn,&zErrMsg);
        syslog(LOG_INFO,"row:%d,column:%d\n",nrow,ncolumn);

        fd = open("/tmp/kydoctor_c_sql",O_RDWR|O_CREAT|O_TRUNC,0666);
        if(fd == -1)
        {
                syslog(LOG_ERR,"open /tmp/kydoctor_c_sql error");
                sqlite3_close(db);  
                return -1;   
        }
        for(int i =1;i < nrow+1;i++)
        {
                //printf("row = ");
                for(int j = 0;j<ncolumn;j++)
                {
                        //printf(" %s ",azResult[i*ncolumn+j]);
                        write(fd,azResult[i*ncolumn+j],strlen(azResult[i*ncolumn+j]));
                        write(fd,"+++",3);
                }
                write(fd,"****",4);
        }
        close(fd);
        sqlite3_close(db);
        return 0;
   
}
static int method_checkitem(sd_bus_message* message, void* userdata, sd_bus_error* ret_error)
{
        int64_t checkitem;
        int r;

        /* Read the parameters */
        r = sd_bus_message_read(message, "x", &checkitem);
        if (r < 0) {
                syslog(LOG_ERR, "Failed to parse parameters: %s\n", strerror(-r));
                return r;        
        }
        char path_buf[512] = {0};
        char file_path_buf[512] = {0};
        char describe_buf[512] = {0};
        char overview_buf[256] = {0};
        char py_comm_str[256] = {0};
        int i;
        DIR *dirp;
        struct dirent *dp;
        struct stat buf;
        char *cjson_str = NULL;
        cJSON 	*jsonroot = NULL;
        int all_exec = 0;
        int error_exec = 0;
        int right_exec = 0;
        FILE* jsonfp;
        long file_size = 0;
        char *json_buff = NULL;
        size_t ret_size = 0, leave_size = 0;
        char *json_str = NULL;
        method_csql_checkitem(checkitem);
        syslog(LOG_INFO, "checkitem = %ld",checkitem);
        sprintf(py_comm_str,"python3 /opt/kydoctor/python_src/checkitem.py %ld",checkitem);
        //syslog(LOG_INFO, py_comm_str);
        int ret = system(py_comm_str);
        if (ret != 0)
        {
           syslog(LOG_ERR, "Failed to exec python3 /opt/kydoctor/python_src/checkitem.py");   
           return -1;  
        }

        jsonfp= fopen(CHECECKITEM_JSON_PATH, "r");
        if (jsonfp == NULL)
        {
                syslog(LOG_ERR, "Failed to opencheckitem.josn.");
                return -1;
        }

        fseek(jsonfp, 0, SEEK_END);
        file_size = ftell(jsonfp);
        rewind(jsonfp);

        json_buff = (char *)malloc(sizeof(char) * file_size);
        memset(json_buff, 0, sizeof(char) * file_size);
        leave_size = file_size;

        do {
                ret_size = fread(&json_buff[file_size - leave_size], sizeof(char), leave_size, jsonfp);
                if (feof(jsonfp)) {
			syslog(LOG_INFO, "end of file\n");
                        break;
		}
                if (ferror(jsonfp)) {
                        syslog(LOG_ERR, "read file error.");
                        break;
                }
                if (ret_size < leave_size)
                       leave_size -=  ret_size;
        } while (1);

        fclose(jsonfp);

	//syslog(LOG_INFO, "%s\n", json_buff);

         // 解析json字符串为json对象或数组
        cJSON* json = cJSON_Parse(json_buff);
        // 判断解析是否成功
        if (json == NULL) {
                syslog(LOG_INFO, "parse json fail");
                r = -1;
                goto fail;
        } else {
                json_str = cJSON_Print(json);
                syslog(LOG_INFO, "%s\n", json_str);
                r = sd_bus_reply_method_return(message, "s", json_str);
                cJSON_Delete(json);
        }
fail:
        free(json_buff);

        return r;
        // printf("jie gou ti changdu = %ld\n",sizeof(check_pathmaps)/sizeof(check_pathmaps[0]));
        // for(i = 0;i < sizeof(check_pathmaps)/sizeof(check_pathmaps[0]);i++)
        // {
        //         if(check_pathmaps[i].typecode == checkitem)
        //         {
        //               strcpy(path_buf,check_pathmaps[i].path);
        //               break;
        //         }
        // }
        // if(strlen(path_buf))
        // {
        //         printf("i am in method_checkitem1,path_buf = %s\n",path_buf);
        //         //检索目录
        //         if((dirp = opendir(path_buf)) == NULL)
        //         {
        //                 perror("opendir error");
        //                 return -1;
        //         }
        //         //新建一个JSON项目：jsonroot
        //         jsonroot = cJSON_CreateObject(); 
        //         if(NULL == jsonroot)
        //         {
        //                 return -1;
        //         }
        //         cJSON * ObjArr = cJSON_CreateArray();
        //         cJSON * ObjThird = NULL;
        //         while((dp = readdir(dirp)) != NULL)
        //         {
        //                 syslog(LOG_INFO, "i am in method_checkitem1,dp->name = %s\n",dp->d_name);
        //                 memset(file_path_buf,0,512);
        //                 strcpy(file_path_buf,path_buf);
        //                 strcat(file_path_buf,dp->d_name);

        //                 //判断是否为文件
        //                 if(stat(file_path_buf,&buf) < 0)
        //                 {
        //                         perror("stat error:");
        //                         continue;
        //                 }
        //                 if(S_ISREG(buf.st_mode)) //普通文件
        //                 {
        //                         if(system(file_path_buf) == 0)
        //                         {
        //                                 syslog(LOG_INFO, "file_path_buf = %s --!= 0\n",file_path_buf);
        //                                 ObjThird = cJSON_CreateObject();
	//                                 cJSON_AddStringToObject(ObjThird, "ErrorCode", dp->d_name);
        //                                 memset(describe_buf,0,512);
        //                                 //查找Describe
        //                                 if(cJson_find_Describe(dp->d_name,describe_buf) == 0)
        //                                 {
        //                                         syslog(LOG_INFO, "Describe: %s", describe_buf);
	//                                         cJSON_AddStringToObject(ObjThird, "Describe", describe_buf);
        //                                 }

        //                                 cJSON_AddItemToArray(ObjArr, ObjThird);
        //                                 error_exec += 1;
        //                         }
        //                         else
        //                         {
        //                                 syslog(LOG_INFO, "file_path_buf = %s --== 0\n",file_path_buf);  
        //                                 right_exec += 1;
        //                         }
        //                 }

        //         }
        //         closedir(dirp);
        //         all_exec = right_exec + error_exec;
        //         sprintf(overview_buf, "检测了 %d 项，%d 项正确，%d 项错误", all_exec, right_exec,error_exec);
        //         cJSON_AddItemToObject(jsonroot, "Details", ObjArr);
	//         cJSON_AddStringToObject(jsonroot, "Overview", overview_buf);

	//         //cjson_str = cJSON_PrintUnformatted(jsonroot);
	//         cjson_str = cJSON_Print(jsonroot);
	
	//         syslog(LOG_INFO, "jsonroot : \n%s\n", cjson_str);
	//         //strcpy(OutStr, cjson_str);
        //         sd_bus_reply_method_return(message, "s",cjson_str);
	//         free(cjson_str);
	//         cJSON_Delete(jsonroot);
        // }
        return 0;
      
}

static int do_repair(cJSON *ErrorCode_obj, cJSON *SolutionType_obj, cJSON *Crc_obj,
        cJSON *CmdLine_obj, cJSON *PackageList_obj, cJSON *OtherInfo_obj)
{
        int ret = 0;
        unsigned long ErrorCode;
        unsigned long SolutionType;
        unsigned long Solution;
        unsigned long Crc;
        char result[READ_DATA_SIZE] = { 0 };

        syslog(LOG_INFO, "do_repair: ErrorCode:%s, SolutionType:%s  Crc:%s CmdLine:%s PackageList:%s OtherInfo:%s\n",
                        ErrorCode_obj->valuestring, SolutionType_obj->valuestring, Crc_obj->valuestring,
                        CmdLine_obj->valuestring, PackageList_obj->valuestring, OtherInfo_obj->valuestring);

        ret = safe_autolu(ErrorCode_obj->valuestring, &ErrorCode);
        if (ret < 0) {
                syslog(LOG_INFO, "prase ErrorCode fail");
                return  ret;
        }
        ret = safe_autolu(SolutionType_obj->valuestring, &SolutionType);
        if (ret < 0) {
                syslog(LOG_INFO, "prase SolutionType fail");
                return  ret;
        }
        ret = safe_autolu(Crc_obj->valuestring, &Crc);
        if (ret < 0) {
                syslog(LOG_INFO, "prase Crc fail");
                return  ret;
        }

        syslog(LOG_INFO, "ErrorCode:0x%lx SolutionType:0x%lx Crc:0x%lx\n", ErrorCode, SolutionType, Crc);

        Solution = SolutionType & 0xFFFF000000000000;
        switch (Solution) {
                case ROOT_CMD:
                        syslog(LOG_INFO, "ROOT_CMD 0x%lx", SolutionType);
                        execcmd(CmdLine_obj->valuestring, result);
                        syslog(LOG_INFO, "do root cmd result: %s", result);
                        break;
                case USER_CMD:
                        syslog(LOG_INFO, "USER_CMD 0x%lx", SolutionType);
                        break;
                case UPDATE_PACKAGE:
                        syslog(LOG_INFO, "UPDATE_PACKAGE 0x%lx, package list:%s", SolutionType, PackageList_obj->valuestring);
                        char update_cmd[4096] = {0};
                        sprintf(update_cmd, "python3 /opt/kydoctor/python_src/update_package.py \"%s\"", PackageList_obj->valuestring);
                        execcmd(update_cmd, result);
                        break;
                default:
                        syslog(LOG_INFO, "undefine 0x%lx", SolutionType);
        }

        return ret;
}

/*  测试例子
接口定义：修复接口
Repair(string repairitems) -> (bool ok)
@repairitems: 需要修复的错误项，为 json 数组格式的字符串，每个元素代表一个修复项
[
    {
        "ErrorCode": 123456,
        "SolutionType": 987,
        "Crc": 111,
        "CmdLine": "xxxx",
        "PackageList": "xxx",
        "OtherInfo": "xxx"
        
    },
    {
        "ErrorCode": 98765,
        "SolutionType": 456,
        "Crc": 222,
        "CmdLine": "xxxx",
        "PackageList": "xxx",
        "OtherInfo": "xxx"
        
    },
]

@ok：是否执行成功

测试例子：
"[ \
    { \
        \"ErrorCode\":\"0x0300090200000005\", \
        \"SolutionType\": \"0x0101000000000001\", \
        \"Crc\":\"0xFFFFFFFF\", \
        \"CmdLine\":\"rm /lib/systemd/logind.conf.d/kylin-unattended-upgrades-logind-maxdelay.conf\", \
        \"PackageList\":\"\", \
        \"OtherInfo\": \"\" \
    }, \
    {\
        \"ErrorCode\":\"0x0300060200000001\", \
        \"SolutionType\": \"0x0201000000000001\", \
        \"Crc\":\"0xFFFFFFFF\", \
        \"CmdLine\": \"\", \
        \"PackageList\":\"tree(>=1.8.0-1)\", \
        \"OtherInfo\":\"\" \
    }\
]"
*/
static int method_repairitem(sd_bus_message* message, void* userdata, sd_bus_error* ret_error) {
        const char* solution;
        int solutioncode, crccode, r;
        int64_t errocode;

        const char *repairitem;
        bool repair_ok = true;
        bool single_repair = true;
        int i;
        int ret;
        unsigned long ErrorCode;
        char *single_fix_reason = NULL;
        int progress = 0;
        /* Read the parameters */
        
        r = sd_bus_message_read(message, "s", &repairitem);
        if (r < 0) {
                syslog(LOG_ERR, "Failed to parse parameters: %s\n", strerror(-r));
                return r;
        }

        syslog(LOG_INFO, "origin JSON strings: %s", repairitem);

        // 解析json字符串为json对象或数组
        cJSON* json = cJSON_Parse(repairitem);
        // 判断解析是否成功
        if (json == NULL) {
                syslog(LOG_INFO, "JSON parse fail\n");
                return sd_bus_reply_method_return(message, "b", 0);
        } else {
                syslog(LOG_INFO, "JSON:  %s\r\n",cJSON_Print(json)); //测试
        }

        // 解析成功后，可以进行进一步的操作，比如获取数组的长度
        int array_size = cJSON_GetArraySize(json);
        syslog(LOG_INFO, "Array size: %d\n", array_size);

        cJSON **ErrorCode_obj = malloc(sizeof(cJSON *) * array_size);
        cJSON **SolutionType_obj = malloc(sizeof(cJSON *) * array_size);
        cJSON **Crc_obj = malloc(sizeof(cJSON *) * array_size);
        cJSON **CmdLine_obj = malloc(sizeof(cJSON *) * array_size);
        cJSON **PackageList_obj = malloc(sizeof(cJSON *) * array_size);
        cJSON **OtherInfo_obj = malloc(sizeof(cJSON *) * array_size);

        // 遍历数组元素并获取指定字段的值
        for (i = 0; i < array_size; i++) {
                cJSON* array_item = cJSON_GetArrayItem(json, i);
                ErrorCode_obj[i] = cJSON_GetObjectItem(array_item, "ErrorCode");
                SolutionType_obj[i] = cJSON_GetObjectItem(array_item, "SolutionType");
                Crc_obj[i] = cJSON_GetObjectItem(array_item, "Crc");
                CmdLine_obj[i] = cJSON_GetObjectItem(array_item, "CmdLine");
                PackageList_obj[i] = cJSON_GetObjectItem(array_item, "PackageList");
                OtherInfo_obj[i] = cJSON_GetObjectItem(array_item, "OtherInfo");
                syslog(LOG_INFO, "JSON Array:%d\n", i);
                /*syslog(LOG_INFO, "ErrorCode:%s, SolutionType:%s  Crc:%s CmdLine:%s PackageList:%s OtherInfo:%s\n",
                        ErrorCode_obj[i]->valuestring, SolutionType_obj[i]->valuestring, Crc_obj[i]->valuestring,
                        CmdLine_obj[i]->valuestring, PackageList_obj[i]->valuestring, OtherInfo_obj[i]->valuestring);
                */
        }

        //开始修复
        for (i=0; i< array_size; i++) {
               ret = do_repair(ErrorCode_obj[i], SolutionType_obj[i], Crc_obj[i],
                                CmdLine_obj[i], PackageList_obj[i], OtherInfo_obj[i]);
                safe_autolu(ErrorCode_obj[i]->valuestring, &ErrorCode);
                if (!ret) {
                        single_repair = true;
                } else {
                        single_repair = false;
                        single_fix_reason = "修复失败"; // TODO:测试例子暂时先这样写后续再修改
                }

                //接口定义：每执行一个小项发送一次信号
                //SigFixed(int64 errorcode, bool ok, string reason)
                //@errorcode: 本次修复完成的错误码
                //@ok: 是否修复成功
                //@reason: 错误原因，如果成功则为空
                r = sd_bus_emit_signal(manager->bus,
                        OBJECT_PATH,        /* object path */
                        INTERFACE_NAME,        /* interface name */
                        "SigFixed",
                        "xbs", ErrorCode, single_repair, single_fix_reason);

                //接口定义：执行进度信号
                //SigProgress(int64 type, int progress)
                //@type: DiagnosticsList 函数返回值中的 type 值
                //@progress: 进度值 0 - 100
                progress = (int)(((i+1)*100 / array_size));
                syslog(LOG_INFO, "progress:%d", progress);
                r = sd_bus_emit_signal(
                        manager->bus,
                        OBJECT_PATH,        /* object path */
                        INTERFACE_NAME,        /* interface name */
                        "SignalProgress",
                        "xi", ErrorCode & 0xffffff0000000000, progress);
        }

        free(ErrorCode_obj);
        free(SolutionType_obj);
        free(Crc_obj);
        free(CmdLine_obj);
        free(PackageList_obj);
        free(OtherInfo_obj);
        // 释放json对象
        cJSON_Delete(json);

        return sd_bus_reply_method_return(message, "b", repair_ok);
}


/* The vtable of our little object, implements the interface */
// SD_BUS_METHOD(_member, _signature, _result, _handler, _flag)
// SD_BUS_SIGNAL(_member, _signature, _flags) 
// types for signature: 
// BYTE: y
// BOOLEAN: b
// INT16: n, UINT16: q
// INT32: i, UINT32: u
// INT64: x, UINT64: t
// DOUBLE: d
// UNIX_FD: h
// STRING: s
// OBJECT_PATH: o
// SIGNATURE: g
// ARRAY: a, ARRAY of two Int32: a(ii)

const sd_bus_vtable service_vtable[] = {
        SD_BUS_VTABLE_START(0),

        SD_BUS_METHOD("GetCheckList", "", "s", method_get_checklist, SD_BUS_VTABLE_UNPRIVILEGED),
        SD_BUS_METHOD("CheckItem", "x", "s", method_checkitem, SD_BUS_VTABLE_UNPRIVILEGED),
        SD_BUS_METHOD("RepairItem", "s", "b", method_repairitem, SD_BUS_VTABLE_UNPRIVILEGED),

        SD_BUS_SIGNAL("SignalProgress", "xi", 0),
        SD_BUS_SIGNAL("SigFixed", "xbs", 0),


        SD_BUS_VTABLE_END
};

Manager* manager = NULL;

static void manager_free(Manager* manager);

static void manager_reset_config(Manager* manager) {
        // Do some relative configurations here.

}

static Manager* manager_new(void) {
        Manager* manager;

        manager = new0(Manager, 1);
        if (!manager)
                return NULL;

        manager_reset_config(manager);

        return manager;
}

static void manager_free(Manager* manager) {

        syslog(LOG_INFO, "Free sd-bus\n");

        sd_bus_slot_unref(manager->slot);
        sd_bus_unref(manager->bus);

        free(manager);
}

static int manager_connect_bus(Manager* manager) {
        int r;
        sd_id128_t id;

        const char* unique;

        /* Connect to the user bus this time */
        r = sd_bus_open_system(&manager->bus);
        if (r < 0) {
                syslog(LOG_ERR, "Failed to connect to system bus: %s\n", strerror(-r));
                return r;
        }

        r = sd_bus_get_bus_id(manager->bus, &id);
        if (r < 0) {
                syslog(LOG_ERR, "Failed to get server ID: %s\n", strerror(-r));
                return r;
        }

        r = sd_bus_get_unique_name(manager->bus, &unique);
        if (r < 0) {
                syslog(LOG_ERR, "Failed to get unique name: %s\n", strerror(-r));
                return r;
        }

        syslog(LOG_INFO, "Peer ID is " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(id));
        syslog(LOG_INFO, "Unique ID: %s\n", unique);

        /* Install the object */
        r = sd_bus_add_object_vtable(
                manager->bus,
                &manager->slot,
                OBJECT_PATH,  /* object path */
                INTERFACE_NAME,   /* interface name */
                service_vtable,
                NULL);
        if (r < 0) {
                syslog(LOG_ERR, "Failed to install object: %s\n", strerror(-r));
                return r;
        }

        /* Take a well-known service name so that clients can find us */
        r = sd_bus_request_name(manager->bus, SERVICE_NAME, 0);
        if (r < 0) {
                syslog(LOG_ERR, "Failed to acquire service name: %s\n", strerror(-r));
                return r;
        }

        return 0;
}

static int manager_startup(Manager* manager) {
        int r;

        /* Connect to the bus */
        r = manager_connect_bus(manager);
        if (r < 0)
                return r;

        return 0;
}

static int manager_run(Manager* manager) {
        int r;

        for (;;) {
                /* Process requests */
                r = sd_bus_process(manager->bus, NULL);
                //syslog(LOG_INFO, "sd_bus_process  r = %d\n", r);
                if (r < 0) {
                        syslog(LOG_ERR, "Failed to process bus: %s\n", strerror(-r));
                        return r;
                }
                if (r > 0) /* we processed a request, try to process another one, right-away */
                        continue;

                /* Wait for the next request to process */
                r = sd_bus_wait(manager->bus, DEFAULT_EXIT_USEC);

                //syslog(LOG_INFO, "sd_bus_wait  r = %d\n", r);
                if (r < 0) {
                        syslog(LOG_ERR, "Failed to wait on bus: %s\n", strerror(-r));
                        return r;
                }
                // if (r == 0) {
                //         syslog(LOG_ERR, "sd_bus_wait timeout \n");
                //         return r;
                // }
        }

}

int main(int argc, char* argv[]) {
        //method_checkitem1();
        //return 0;
        int r;
        openlog("kydoctor-server", LOG_CONS | LOG_PID, 0);
        manager = manager_new();
        if (!manager) {
                syslog(LOG_ERR, "Failed to create manager.\n");
                goto finish;
        }

        r = manager_startup(manager);
        if (r < 0) {
                syslog(LOG_ERR, "Failed to fully start up daemon: %s\n", strerror(-r));
                goto finish;
        }

        syslog(LOG_INFO, "kydoctor-server is running...\n");

        r = manager_run(manager);

finish:
        manager_free(manager);
        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}