#include "upgrade.h"

static int app_manager_add_config(upgrade_var_t * var, app_config_t *app_cfg, char *file, cJSON *jroot, cJSON *jnodes)
{
    cJSON* root=NULL;
    cJSON* nodes = NULL;
	dy_syslog(LOG_DEBUG, "jroot %p jnodes %p", jroot, jnodes);
	if(jroot && jnodes)
	{
		root = jroot;
		nodes = jnodes;
	}
	else
	{
		root=cJSON_CreateObject();
	    if(root == NULL)           return -1;
	    nodes = cJSON_CreateArray();
	    cJSON_AddItemToObject(root,"app_manager_cfg",nodes);
	}

	cJSON *item = cJSON_CreateObject();
    cJSON_AddItemToArray(nodes,item);
	cJSON_AddStringToObject(item, "name", app_cfg->name);
	cJSON_AddStringToObject(item, "version", app_cfg->version);
	if(app_cfg->base_url)
		cJSON_AddStringToObject(item, "base_url", app_cfg->base_url);
	cJSON_AddStringToObject(item, "depend_name", app_cfg->depend_name);
	cJSON_AddStringToObject(item, "cmd", app_cfg->cmd);
	if(strlen(app_cfg->check_cmd))
		cJSON_AddStringToObject(item, "check_cmd", app_cfg->check_cmd);

	char *str = (cJSON_Print(root));
    cJSON_Delete(root);

	write_file_data(file, str, strlen(str));
	free(str);

	app_manager_config_t *ip_camera_cfg = calloc(1, sizeof(app_manager_config_t));
	memcpy(&ip_camera_cfg->app_cfg, app_cfg, sizeof(app_config_t));
	
	dy_syslog(LOG_INFO,"==name:%s version:%s depend_name:%s cmd:%s==",ip_camera_cfg->app_cfg.name,ip_camera_cfg->app_cfg.version,ip_camera_cfg->app_cfg.depend_name,ip_camera_cfg->app_cfg.cmd);
	list_add_tail(&ip_camera_cfg->list, &var->config_list);
	
    return 0;

}

static int app_manager_update_config(upgrade_var_t *var, char *file, app_config_t *app_cfg)
{
	int ret 	   = 0;

	char *json_str = NULL;
    json_str = read_file_data(file);
    if (!json_str)
    {
        goto __add_config;
    }

    cJSON *root = cJSON_Parse(json_str);
    if (!root)
    {
       goto __add_config;
    }

    cJSON *nodes = cJSON_GetObjectItem(root, "app_manager_cfg");
    if (!nodes)
    {
        goto __add_config;
    }

	app_manager_add_config(var, app_cfg, file, root, nodes);
	return ret;

__add_config:
	app_manager_add_config(var, app_cfg, file, NULL, NULL);	
    return ret;
}

int app_manager_load_config(upgrade_var_t *var, char *file)
{
	int ret 	   = -1;
	int i		   = 0;

	char *json_str = NULL;
    json_str = read_file_data(file);
    if (!json_str)
    {
        return -1;
    }

    cJSON *root = cJSON_Parse(json_str);
    if (!root)
    {
        return -1;
    }

    cJSON *nodes = cJSON_GetObjectItem(root, "app_manager_cfg");
    if (!nodes)
    {
        ret = -1;
        goto __cleanup;
    }

    int size = cJSON_GetArraySize(nodes);

    for (i = 0; i < size ; i++)
    {
        cJSON *node = cJSON_GetArrayItem(nodes, i);
        if (!node)
        {
            ret = i + 1;
            goto __cleanup;
        }

		app_manager_config_t *app_manager_cfg = calloc(1, sizeof(app_manager_config_t));
		GET_JSON_VALUE_STRING(node, "name", app_manager_cfg->app_cfg.name);
		GET_JSON_VALUE_STRING(node, "name", app_manager_cfg->app_cfg.version);
		GET_JSON_VALUE_DY_STRING(node, "base_url", app_manager_cfg->app_cfg.base_url);
		GET_JSON_VALUE_STRING(node, "depend_name", app_manager_cfg->app_cfg.depend_name);
		GET_JSON_VALUE_STRING(node, "cmd", app_manager_cfg->app_cfg.cmd);
		GET_JSON_VALUE_STRING(node, "check_cmd", app_manager_cfg->app_cfg.check_cmd);

		dy_syslog(LOG_INFO,"==%d %d name:%s version:%s depend_name:%s cmd:%s check_cmd:%s==",size,i,app_manager_cfg->app_cfg.name, app_manager_cfg->app_cfg.version, app_manager_cfg->app_cfg.depend_name,app_manager_cfg->app_cfg.cmd,app_manager_cfg->app_cfg.check_cmd);
		list_add_tail(&app_manager_cfg->list, &var->config_list);
    }
    ret = 0;

__cleanup:
    cJSON_Delete(root);
    return ret;
}

void msg_upgrade_requst_apps_list(upgrade_var_t *var, ipc_msg_t *mqtt_msg)
{
    char  exec_cmd[128] = {0};
    char topic[192] = {0};
    int mi = json_pkt_json_mi(mqtt_msg->payload);
    char *buff = NULL;
    char *str = NULL;
    cJSON *root = NULL;

    sprintf(exec_cmd, "%s/%s", NET_BASH_PATH, "opkg_service.sh list");
    system_reply(exec_cmd, &buff);
    if (!buff)
    {
        dy_syslog(LOG_ERR, "system run \'%s\' fail !", exec_cmd);
        goto out;
    }
    root = cJSON_Parse(buff);
    if (!root)
    {
        dy_syslog(LOG_ERR, "opkg_service.sh list failed");
        goto out;
    }

    cJSON_AddNumberToObject(root, "mi", mi);
    str = cJSON_Print(root);

    snprintf(topic, sizeof(topic),  "G/%s/%s/device/%s/service/%s", var->sn_str, TOPIC_GATEWAY_CONFIG, var->sn_str, TOPIC_RSP_APPSLIST);
    ipc_session_publish(var->session, topic, str, strlen(str));
out:
    if (root)
    {
        cJSON_Delete(root);
    }
    if (str)
    {
        free(str);
    }
    if (buff)
    {
        free(buff);
    }
}

static int upgrade_app_call_bash(char *operation, char *name, char *version, char *base_url)
{
    if (operation && name && strlen(name) > 0)
    {
        char  exec_cmd[256] = {0};
        if (base_url)
        {
            sprintf(exec_cmd, NET_BASH_PATH"opkg_service.sh %s --serv %s --name %s", operation, base_url, name);
        }
        else
        {
            sprintf(exec_cmd, NET_BASH_PATH"opkg_service.sh %s --name %s", operation, name);
        }

        pid_t status = system(exec_cmd);
        if (WIFEXITED(status))
        {
            if (WEXITSTATUS(status) == 0)
            {
                return 0;
            }
            else
            {
                dy_syslog(LOG_WARNING, "%s failed,error %d;", exec_cmd, WEXITSTATUS(status));
                return -1;
            }
        }
    }
    return 0;
}

int upgrade_depend_app_call_bash(char *exec_cmd)
{
	//暂时不启用包管理
	return 0;
    pid_t status = system(exec_cmd);
	dy_syslog(LOG_DEBUG, "exec_cmd %s",exec_cmd);
    if (WIFEXITED(status))
    {
        if (WEXITSTATUS(status) == 0)
        {
            return 0;
        }
        else
        {
            dy_syslog(LOG_WARNING, "%s failed,error %d;", exec_cmd, WEXITSTATUS(status));
        }
    }
    return 0;
}

static int is_ipk_name_invalid(struct hash_intptr *ipk_blacklist_hash, const char *ipk_name)
{
    int val = 0;

    if (hash_intptr_findint(ipk_blacklist_hash, ipk_name, strlen(ipk_name), &val) < 0) {
        return 0;
    } else {
        dy_syslog(LOG_ERR, "Invalid ipk: %s!!!", ipk_name);
        return 1;
    }
}

static int resp_ipk_install_failed(ipc_session_t *sesson, const char *name, int mi)
{
    if (sesson == NULL) {
        dy_syslog(LOG_ERR, "Invalid argument!!!");
        return -1;
    }

    char topic[TOPIC_MAX_LEN] = {0};
    GET_SN_PROC
    cJSON *root = cJSON_CreateObject();
    if (root == NULL)
    {
        dy_syslog(LOG_ERR, "cJSON_CreateObject failed!!!");
        return -1;
    }

    cJSON_AddNumberToObject(root, "err_code", 1);
    cJSON_AddStringToObject(root, "name", name);
    cJSON_AddStringToObject(root, "err_msg", "Invalid ipk name");
    cJSON_AddNumberToObject(root, "mi", mi);
    cJSON_AddNumberToObject(root, "timestamp", time(NULL));

    char *str = (cJSON_Print(root));
    cJSON_Delete(root);
    snprintf(topic, TOPIC_MAX_LEN, "G/%s/gateway/device/%s/service/%s", sn, sn, "Set_AppInstall");
    dy_syslog(LOG_DEBUG, "pub:topic  :%s", topic);
    dy_syslog(LOG_DEBUG, "pub:payload:%s", str);
    ipc_session_publish(sesson, topic, (unsigned char *)str, (int)strlen(str));

    if (str) {
        free(str);  str = NULL;
    }

    return 0;
}

int msg_upgrade_app_install(upgrade_var_t *var, ipc_msg_t *mqtt_msg)
{
    int mi = 0;
    int err_code = 1;
    cJSON *root = NULL;
	app_config_t app_cfg = {0};

    root = cJSON_Parse(mqtt_msg->payload);
    if (!root)
    {
        dy_syslog(LOG_WARNING, "parse payload failed");
        goto out;
    }
    GET_JSON_VALUE_INT(root, "mi", mi);
    GET_JSON_VALUE_STRING(root, "version", app_cfg.version);
    GET_JSON_VALUE_STRING(root, "name", app_cfg.name);
    GET_JSON_VALUE_DY_STRING(root, "base_url", app_cfg.base_url);
    cJSON_Delete(root);

    if (is_ipk_name_invalid(var->ipk_blacklist_hash, app_cfg.name)) {
        resp_ipk_install_failed(var->session, app_cfg.name, 1);
        return -1;
    }

	//更新配置文件
	//app_manager_update_config(var, APP_MANAGER_CFG, &app_cfg);

    if (strstr(app_cfg.name, "upgrade"))
    {
        // 如果是自己模块被升级，则直接发送升级成功的消息上去
        gw_common_result(var->session, mi, 0, TOPIC_SET_APPINSTALL);
        sleep(5);// wait result send out
    }
    err_code = upgrade_app_call_bash("update", app_cfg.name, app_cfg.version, app_cfg.base_url);
    if (err_code == 0)
    {
        dy_syslog(LOG_INFO, "Intasll application[%s] sucussful!", app_cfg.name);
    }
    else
    {
        dy_syslog(LOG_INFO, "Intasll application[%s] failed!", app_cfg.name);
    }
    free(app_cfg.base_url);
out:
    gw_common_result(var->session, mi, err_code, TOPIC_SET_APPINSTALL);
    return err_code;
}

int msg_upgrade_app_remove(upgrade_var_t *var, ipc_msg_t *mqtt_msg)
{
    int mi = 0;
    char *name = NULL;
    char *version = NULL;
    char *base_url = NULL;
    int err_code = 1;
    cJSON *root = cJSON_Parse(mqtt_msg->payload);
    if (!root)
    {
        dy_syslog(LOG_WARNING, "install app failed");
        goto err;
    }
    GET_JSON_VALUE_INT(root, "mi", mi);
    GET_JSON_VALUE_DY_STRING(root, "name", name);
    cJSON_Delete(root);

    if (is_ipk_name_invalid(var->ipk_blacklist_hash, name)) {
        resp_ipk_install_failed(var->session, name, 1);
        return -1;
    }

    int ret = upgrade_app_call_bash("delete", name, version, base_url);
    if (ret == 0)
    {
        dy_syslog(LOG_INFO, "Remove application[%s] sucussful!", name);
        err_code = 0;
    }
    else
    {
        dy_syslog(LOG_INFO, "Remove application[%s] failed!", name);
    }
    free(name);
    free(version);
    free(base_url);
err:
    gw_common_result(var->session, mi, err_code, TOPIC_SET_APPREMOVE);
	return 0;
}

int msg_upgrade_depend_app_install(upgrade_var_t *var, ipc_msg_t *mqtt_msg)
{
    int err_code = 1;
	int find = 0;
    cJSON *root = NULL;
	app_config_t app_cfg = {0};

	//取包名
    root = cJSON_Parse(mqtt_msg->payload);
    if (!root)
    {
        dy_syslog(LOG_WARNING, "parse payload failed");
        goto out;
    }
    GET_JSON_VALUE_STRING(root, "version", app_cfg.version);
    GET_JSON_VALUE_STRING(root, "name", app_cfg.name);
	GET_JSON_VALUE_STRING(root, "depend_name", app_cfg.depend_name);
	GET_JSON_VALUE_STRING(root, "cmd", app_cfg.cmd);
	GET_JSON_VALUE_STRING(root, "check_cmd", app_cfg.check_cmd);
    cJSON_Delete(root);

    if (is_ipk_name_invalid(var->ipk_blacklist_hash, app_cfg.name)) {
        resp_ipk_install_failed(var->session, app_cfg.name, 1);
        return -1;
    }

    if (is_ipk_name_invalid(var->ipk_blacklist_hash, app_cfg.depend_name)) {
        resp_ipk_install_failed(var->session, app_cfg.depend_name, 1);
        return -1;
    }

	//是否已经在管理列表中
	app_manager_config_t *app_manager_cfg = NULL;	
	list_for_each_entry(app_manager_cfg, &var->config_list, list)
	{
		dy_syslog(LOG_DEBUG, "name %s depend_name %s cmd %s", app_manager_cfg->app_cfg.name,app_cfg.depend_name,app_manager_cfg->app_cfg.cmd);
				
		if(strcmp(app_cfg.name, app_manager_cfg->app_cfg.name) == 0 && strcmp(app_cfg.depend_name, app_manager_cfg->app_cfg.depend_name) == 0)
		{
			find = 1;
			break;
		}
	}
	dy_syslog(LOG_DEBUG, "===find %d", find);
	//新包，更新配置文件
	if(find == 0)
	{
		upgrade_depend_app_call_bash(app_cfg.cmd);
		//更新配置文件
		app_manager_update_config(var, APP_MANAGER_CFG, &app_cfg);
	}
	
out:
    return err_code;
}

int msg_upgrade_depend_app_remove(upgrade_var_t *var, ipc_msg_t *mqtt_msg)
{
    return 0;
}

int app_manager_install(upgrade_var_t *var, app_manager_config_t *app_manager_cfg)
{
    int err_code = 1;

    if (is_ipk_name_invalid(var->ipk_blacklist_hash, app_manager_cfg->app_cfg.name)) {
        resp_ipk_install_failed(var->session, app_manager_cfg->app_cfg.name, 1);
        return -1;
    }

	if(strlen(app_manager_cfg->app_cfg.cmd))
	{
	    err_code = upgrade_depend_app_call_bash(app_manager_cfg->app_cfg.cmd);
	}
	else
	{
		err_code = upgrade_app_call_bash("update", app_manager_cfg->app_cfg.name, app_manager_cfg->app_cfg.version, app_manager_cfg->app_cfg.base_url);
	}
	
	if (err_code == 0)
    {
        dy_syslog(LOG_INFO, "Install application[%s] sucussful!", app_manager_cfg->app_cfg.name);
    }
    else
    {
        dy_syslog(LOG_INFO, "Install application[%s] failed!", app_manager_cfg->app_cfg.name);
    }

	return err_code;
}


