/*
 * mqtt_dm.c - Library for MQTT Client datamodel
 *
 * Copyright (C) 2024, IOPSYS Software Solutions AB.
 *
 * Author Suvendhu Hansa <suvendhu.hansa@iopsys.eu>
 *
 * See LICENSE file for license related information.
 *
 */

#ifdef ENABLE_MQTT
#include "mqtt_dm.h"

/*************************************************************
* ENTRY METHOD
**************************************************************/
static int browseMQTTClientInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
	char cmd[MAX_CMD_LEN] = {0};
	const char *dm_path = "Device.MQTT.Client.";
	json_object *client_ob = NULL;

	LIST_HEAD(result_list);
	snprintf(cmd, sizeof(cmd), "%s %s | grep \"%s\" | grep -v CMD_", PROG_CMD_GET, dm_path, dm_path);
	exec_cmd(cmd, &result_list);

	client_ob = json_object_new_object();
	if (client_ob == NULL) {
		delete_cmd_result(&result_list);
		return 0;
	}

	convert_list_to_json(client_ob, &result_list);
	delete_cmd_result(&result_list);

	json_object *obj = dmjson_get_obj(client_ob, 3, "Device", "MQTT", "Client");

	if (obj && json_object_is_type(obj, json_type_array)) {
		int idx = 0;
		int con_count = json_object_array_length(obj);

		for (idx = 0; idx < con_count; idx++) {
			json_object *curr = json_object_array_get_idx(obj, idx);
			if (curr == NULL) {
				continue;
			}

			char path[MAX_PATH_LEN] = {0};
			snprintf(path, sizeof(path), "Device.MQTT.Client.%d", idx+1);

			struct dm_data data = {0};
			data.json_object = curr;
			data.additional_data = (void *)dmstrdup(path);

			char *inst = handle_instance_without_section(dmctx, parent_node, idx+1);
			if (DM_LINK_INST_OBJ(dmctx, parent_node, &data, inst) == DM_STOP)
				break;
		}
	}

	if (client_ob != NULL) {
		json_object_put(client_ob);
		client_ob = NULL;
	}

	return 0;
}

static int browseMQTTClientSubscriptionInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
	struct dm_data *data = (struct dm_data *)prev_data;

	if (data == NULL)
		return 0;

	char *dm_path = (char *)data->additional_data;
	json_object *client_obj = data->json_object;
	json_object *obj = dmjson_get_obj(client_obj, 1, "Subscription");

	if (dm_path && obj && json_object_is_type(obj, json_type_array)) {
		int idx = 0;
		int mtp_count = json_object_array_length(obj);

		for (idx = 0; idx < mtp_count; idx++) {
			json_object *curr = json_object_array_get_idx(obj, idx);
			if (curr == NULL) {
				continue;
			}

			char path[MAX_PATH_LEN] = {0};
			snprintf(path, sizeof(path), "%s.Subscription.%d", dm_path, idx+1);

			struct dm_data data = {0};
			data.json_object = curr;
			data.additional_data = (void *)dmstrdup(path);

			char *inst = handle_instance_without_section(dmctx, parent_node, idx+1);
			if (DM_LINK_INST_OBJ(dmctx, parent_node, &data, inst) == DM_STOP)
				break;
		}
	}

	return 0;
}

/*************************************************************
* ADD & DEL OBJ
**************************************************************/
static int addObjMQTTClient(char *refparam, struct dmctx *ctx, void *data, char **instance)
{
	char param_path[MAX_PATH_LEN] = {0};

	snprintf(param_path, sizeof(param_path), "Device.MQTT.Client.");
	return get_instance_number(param_path, instance);
}

static int delObjMQTTClient(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action)
{
	char param_path[MAX_PATH_LEN] = {0};
	struct dm_data *p = (struct dm_data *)data;

	switch (del_action) {
		case DEL_INST:
			snprintf(param_path, sizeof(param_path), "%s.", (char *)p->additional_data);
			break;
		case DEL_ALL:
			snprintf(param_path, sizeof(param_path), "Device.MQTT.Client.*.");
			break;
	}

	return deletion_succeed(param_path);
}

static int addObjMQTTClientSubscription(char *refparam, struct dmctx *ctx, void *data, char **instance)
{
	char param_path[MAX_PATH_LEN] = {0};
	struct dm_data *p = (struct dm_data *)data;

	snprintf(param_path, sizeof(param_path), "%s.Subscription.", (char *)p->additional_data);
	return get_instance_number(param_path, instance);
}

static int delObjMQTTClientSubscription(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action)
{
	char param_path[MAX_PATH_LEN] = {0};
	struct dm_data *p = (struct dm_data *)data;

	switch (del_action) {
		case DEL_INST:
			snprintf(param_path, sizeof(param_path), "%s.", (char *)p->additional_data);
			break;
		case DEL_ALL:
			snprintf(param_path, sizeof(param_path), "%s.Subscription.*.", (char *)p->additional_data);
			break;
	}

	return deletion_succeed(param_path);
}

/*************************************************************
* GET & SET PARAM
**************************************************************/
static int get_MQTT_ClientNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	char cmd[MAX_CMD_LEN] = {0};
	const char *dm_path = "Device.MQTT.ClientNumberOfEntries";

	LIST_HEAD(result_list);
	snprintf(cmd, sizeof(cmd), "%s %s | grep \"%s =>\"", PROG_CMD_GET, dm_path, dm_path);
	exec_cmd(cmd, &result_list);

	collect_value(dm_path, &result_list, value);
	delete_cmd_result(&result_list);

	return 0;
}

static int get_MQTTCapabilities_ProtocolVersionsSupported(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	char cmd[MAX_CMD_LEN] = {0};
	const char *dm_path = "Device.MQTT.Capabilities.ProtocolVersionsSupported";

	LIST_HEAD(result_list);
	snprintf(cmd, sizeof(cmd), "%s %s | grep \"%s =>\"", PROG_CMD_GET, dm_path, dm_path);
	exec_cmd(cmd, &result_list);

	collect_value(dm_path, &result_list, value);
	delete_cmd_result(&result_list);

	return 0;
}

static int get_MQTTCapabilities_TransportProtocolSupported(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	char cmd[MAX_CMD_LEN] = {0};
	const char *dm_path = "Device.MQTT.Capabilities.TransportProtocolSupported";

	LIST_HEAD(result_list);
	snprintf(cmd, sizeof(cmd), "%s %s | grep \"%s =>\"", PROG_CMD_GET, dm_path, dm_path);
	exec_cmd(cmd, &result_list);

	collect_value(dm_path, &result_list, value);
	delete_cmd_result(&result_list);

	return 0;
}

static int get_MQTTCapabilities_MaxNumberOfClientSubscriptions(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	char cmd[MAX_CMD_LEN] = {0};
	const char *dm_path = "Device.MQTT.Capabilities.MaxNumberOfClientSubscriptions";

	LIST_HEAD(result_list);
	snprintf(cmd, sizeof(cmd), "%s %s | grep \"%s =>\"", PROG_CMD_GET, dm_path, dm_path);
	exec_cmd(cmd, &result_list);

	collect_value(dm_path, &result_list, value);
	delete_cmd_result(&result_list);
	
	return 0;
}

static int get_MQTTClient_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct dm_data *ob_data = (struct dm_data *)data;

	*value = dmjson_get_value(ob_data->json_object, 1, "Alias");
	return 0;
}

static int set_MQTTClient_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char param_path[MAX_PATH_LEN] = {0};
	int ret = FAULT_9002;

	struct dm_data *ob_data = (struct dm_data *)data;
	char *dm_path = (char *)ob_data->additional_data;

	if (DM_STRLEN(dm_path) == 0) {
		return ret;
	}

	switch (action) {
	case VALUECHECK:
		if (bbfdm_validate_string(ctx, value, -1, 64, NULL, NULL)) {
			ret = FAULT_9007;
			break;
		}

		ret = 0;
		break;
	case VALUESET:
		snprintf(param_path, sizeof(param_path), "%s.Alias", dm_path);
		ret = set_succeed(param_path, value);
		break;
	}

	return ret;
}

static int get_MQTTClient_Name(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct dm_data *ob_data = (struct dm_data *)data;

	*value = dmjson_get_value(ob_data->json_object, 1, "Name");
	return 0;
}

static int set_MQTTClient_Name(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char param_path[MAX_PATH_LEN] = {0};
	int ret = FAULT_9002;

	struct dm_data *ob_data = (struct dm_data *)data;
	char *dm_path = (char *)ob_data->additional_data;

	if (DM_STRLEN(dm_path) == 0) {
		return ret;
	}

	switch (action) {
	case VALUECHECK:
		if (bbfdm_validate_string(ctx, value, -1, 64, NULL, NULL)) {
			ret = FAULT_9007;
			break;
		}

		ret = 0;
		break;
	case VALUESET:
		snprintf(param_path, sizeof(param_path), "%s.Name", dm_path);
		ret = set_succeed(param_path, value);
		break;
	}

	return ret;
}

static int get_MQTTClient_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct dm_data *ob_data = (struct dm_data *)data;

	*value = dmjson_get_value(ob_data->json_object, 1, "Enable");
	return 0;
}

static int set_MQTTClient_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char param_path[MAX_PATH_LEN] = {0};
	int ret = FAULT_9002;

	struct dm_data *ob_data = (struct dm_data *)data;
	char *dm_path = (char *)ob_data->additional_data;

	if (DM_STRLEN(dm_path) == 0) {
		return ret;
	}

	switch (action) {
	case VALUECHECK:
		if (bbfdm_validate_boolean(ctx, value)) {
			ret = FAULT_9007;
			break;
		}

		ret = 0;
		break;
	case VALUESET:
		snprintf(param_path, sizeof(param_path), "%s.Enable", dm_path);
		ret = set_succeed(param_path, value);
		break;
	}

	return ret;
}

static int get_MQTTClient_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct dm_data *ob_data = (struct dm_data *)data;

	*value = dmjson_get_value(ob_data->json_object, 1, "Status");
	return 0;
}

static int get_MQTTClient_ProtocolVersion(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct dm_data *ob_data = (struct dm_data *)data;

	*value = dmjson_get_value(ob_data->json_object, 1, "ProtocolVersion");
	return 0;
}

static int set_MQTTClient_ProtocolVersion(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char param_path[MAX_PATH_LEN] = {0};
	int ret = FAULT_9002;
	char *sup_proto = NULL;
	bool valid_value = false;

	struct dm_data *ob_data = (struct dm_data *)data;
	char *dm_path = (char *)ob_data->additional_data;

	if (DM_STRLEN(dm_path) == 0) {
		return ret;
	}

	switch (action) {
	case VALUECHECK:
		get_MQTTCapabilities_ProtocolVersionsSupported(refparam, ctx, data, instance, &sup_proto);
		if (DM_STRLEN(sup_proto) == 0) {
			ret = FAULT_9007;
			break;
		}

		char *tmp = strtok(sup_proto, ",");
		while (tmp) {
			remove_whitespaces(tmp);
			if (DM_STRCMP(tmp, value) == 0) {
				valid_value = true;
				break;
			}

			tmp = strtok(NULL, ",");
		}

		if (!valid_value) {
			ret = FAULT_9007;
			break;
		}

		ret = 0;
		break;
	case VALUESET:
		snprintf(param_path, sizeof(param_path), "%s.ProtocolVersion", dm_path);
		ret = set_succeed(param_path, value);
		break;
	}

	return ret;
}

static int get_MQTTClient_BrokerAddress(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct dm_data *ob_data = (struct dm_data *)data;

	*value = dmjson_get_value(ob_data->json_object, 1, "BrokerAddress");
	return 0;
}

static int set_MQTTClient_BrokerAddress(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char param_path[MAX_PATH_LEN] = {0};
	int ret = FAULT_9002;

	struct dm_data *ob_data = (struct dm_data *)data;
	char *dm_path = (char *)ob_data->additional_data;

	if (DM_STRLEN(dm_path) == 0) {
		return ret;
	}

	switch (action) {
	case VALUECHECK:
		if (bbfdm_validate_string(ctx, value, -1, 256, NULL, NULL)) {
			ret = FAULT_9007;
			break;
		}

		ret = 0;
		break;
	case VALUESET:
		snprintf(param_path, sizeof(param_path), "%s.BrokerAddress", dm_path);
		ret = set_succeed(param_path, value);
		break;
	}

	return ret;
}

static int get_MQTTClient_BrokerPort(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct dm_data *ob_data = (struct dm_data *)data;

	*value = dmjson_get_value(ob_data->json_object, 1, "BrokerPort");
	return 0;
}

static int set_MQTTClient_BrokerPort(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char param_path[MAX_PATH_LEN] = {0};
	int ret = FAULT_9002;

	struct dm_data *ob_data = (struct dm_data *)data;
	char *dm_path = (char *)ob_data->additional_data;

	if (DM_STRLEN(dm_path) == 0) {
		return ret;
	}

	switch (action) {
	case VALUECHECK:
		if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{"1","65535"}}, 1)) {
			ret = FAULT_9007;
			break;
		}

		ret = 0;
		break;
	case VALUESET:
		snprintf(param_path, sizeof(param_path), "%s.BrokerPort", dm_path);
		ret = set_succeed(param_path, value);
		break;
	}

	return ret;
}

static int get_MQTTClient_TransportProtocol(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct dm_data *ob_data = (struct dm_data *)data;

	*value = dmjson_get_value(ob_data->json_object, 1, "TransportProtocol");
	return 0;
}

static int set_MQTTClient_TransportProtocol(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char param_path[MAX_PATH_LEN] = {0};
	int ret = FAULT_9002;
	char *sup_proto = NULL;
	bool valid_value = false;

	struct dm_data *ob_data = (struct dm_data *)data;
	char *dm_path = (char *)ob_data->additional_data;

	if (DM_STRLEN(dm_path) == 0) {
		return ret;
	}

	switch (action) {
	case VALUECHECK:
		get_MQTTCapabilities_TransportProtocolSupported(refparam, ctx, data, instance, &sup_proto);
		if (DM_STRLEN(sup_proto) == 0) {
			ret = FAULT_9007;
			break;
		}

		char *tmp = strtok(sup_proto, ",");
		while (tmp) {
			remove_whitespaces(tmp);
			if (DM_STRCMP(tmp, value) == 0) {
				valid_value = true;
				break;
			}

			tmp = strtok(NULL, ",");
		}

		if (!valid_value) {
			ret = FAULT_9007;
			break;
		}

		ret = 0;
		break;
	case VALUESET:
		snprintf(param_path, sizeof(param_path), "%s.TransportProtocol", dm_path);
		ret = set_succeed(param_path, value);
		break;
	}

	return ret;
}

static int get_MQTTClient_CleanSession(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct dm_data *ob_data = (struct dm_data *)data;

	*value = dmjson_get_value(ob_data->json_object, 1, "CleanSession");
	return 0;
}

static int set_MQTTClient_CleanSession(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char param_path[MAX_PATH_LEN] = {0};
	int ret = FAULT_9002;

	struct dm_data *ob_data = (struct dm_data *)data;
	char *dm_path = (char *)ob_data->additional_data;

	if (DM_STRLEN(dm_path) == 0) {
		return ret;
	}

	switch (action) {
	case VALUECHECK:
		if (bbfdm_validate_boolean(ctx, value)) {
			ret = FAULT_9007;
			break;
		}

		ret = 0;
		break;
	case VALUESET:
		snprintf(param_path, sizeof(param_path), "%s.CleanSession", dm_path);
		ret = set_succeed(param_path, value);
		break;
	}

	return ret;
}

static int get_MQTTClient_CleanStart(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct dm_data *ob_data = (struct dm_data *)data;

	*value = dmjson_get_value(ob_data->json_object, 1, "CleanStart");
	return 0;
}

static int set_MQTTClient_CleanStart(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char param_path[MAX_PATH_LEN] = {0};
	int ret = FAULT_9002;

	struct dm_data *ob_data = (struct dm_data *)data;
	char *dm_path = (char *)ob_data->additional_data;

	if (DM_STRLEN(dm_path) == 0) {
		return ret;
	}

	switch (action) {
	case VALUECHECK:
		if (bbfdm_validate_boolean(ctx, value)) {
			ret = FAULT_9007;
			break;
		}

		ret = 0;
		break;
	case VALUESET:
		snprintf(param_path, sizeof(param_path), "%s.CleanStart", dm_path);
		ret = set_succeed(param_path, value);
		break;
	}

	return ret;
}

static int get_MQTTClient_KeepAliveTime(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct dm_data *ob_data = (struct dm_data *)data;

	*value = dmjson_get_value(ob_data->json_object, 1, "KeepAliveTime");
	return 0;
}

static int set_MQTTClient_KeepAliveTime(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char param_path[MAX_PATH_LEN] = {0};
	int ret = FAULT_9002;

	struct dm_data *ob_data = (struct dm_data *)data;
	char *dm_path = (char *)ob_data->additional_data;

	if (DM_STRLEN(dm_path) == 0) {
		return ret;
	}

	switch (action) {
	case VALUECHECK:
		if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{NULL,"65535"}}, 1)) {
			ret = FAULT_9007;
			break;
		}

		ret = 0;
		break;
	case VALUESET:
		snprintf(param_path, sizeof(param_path), "%s.KeepAliveTime", dm_path);
		ret = set_succeed(param_path, value);
		break;
	}

	return ret;
}

static int get_MQTTClient_RequestResponseInfo(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct dm_data *ob_data = (struct dm_data *)data;

	*value = dmjson_get_value(ob_data->json_object, 1, "RequestResponseInfo");
	return 0;
}

static int set_MQTTClient_RequestResponseInfo(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char param_path[MAX_PATH_LEN] = {0};
	int ret = FAULT_9002;

	struct dm_data *ob_data = (struct dm_data *)data;
	char *dm_path = (char *)ob_data->additional_data;

	if (DM_STRLEN(dm_path) == 0) {
		return ret;
	}

	switch (action) {
	case VALUECHECK:
		if (bbfdm_validate_boolean(ctx, value)) {
			ret = FAULT_9007;
			break;
		}

		ret = 0;
		break;
	case VALUESET:
		snprintf(param_path, sizeof(param_path), "%s.RequestResponseInfo", dm_path);
		ret = set_succeed(param_path, value);
		break;
	}

	return ret;
}

static int get_MQTTClient_ClientID(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct dm_data *ob_data = (struct dm_data *)data;

	*value = dmjson_get_value(ob_data->json_object, 1, "ClientID");
	return 0;
}

static int set_MQTTClient_ClientID(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char param_path[MAX_PATH_LEN] = {0};
	int ret = FAULT_9002;

	struct dm_data *ob_data = (struct dm_data *)data;
	char *dm_path = (char *)ob_data->additional_data;

	if (DM_STRLEN(dm_path) == 0) {
		return ret;
	}

	switch (action) {
	case VALUECHECK:
		if (bbfdm_validate_string(ctx, value, 0, 65535, NULL, NULL)) {
			ret = FAULT_9007;
			break;
		}

		ret = 0;
		break;
	case VALUESET:
		snprintf(param_path, sizeof(param_path), "%s.ClientID", dm_path);
		ret = set_succeed(param_path, value);
		break;
	}

	return ret;
}

static int get_MQTTClient_Username(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct dm_data *ob_data = (struct dm_data *)data;

	*value = dmjson_get_value(ob_data->json_object, 1, "Username");
	return 0;
}

static int set_MQTTClient_Username(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char param_path[MAX_PATH_LEN] = {0};
	int ret = FAULT_9002;

	struct dm_data *ob_data = (struct dm_data *)data;
	char *dm_path = (char *)ob_data->additional_data;

	if (DM_STRLEN(dm_path) == 0) {
		return ret;
	}

	switch (action) {
	case VALUECHECK:
		if (bbfdm_validate_string(ctx, value, -1, 256, NULL, NULL)) {
			ret = FAULT_9007;
			break;
		}

		ret = 0;
		break;
	case VALUESET:
		snprintf(param_path, sizeof(param_path), "%s.Username", dm_path);
		ret = set_succeed(param_path, value);
		break;
	}

	return ret;
}

static int get_MQTTClient_Password(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct dm_data *ob_data = (struct dm_data *)data;

	*value = dmjson_get_value(ob_data->json_object, 1, "Password");
	return 0;
}

static int set_MQTTClient_Password(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char param_path[MAX_PATH_LEN] = {0};
	int ret = FAULT_9002;

	struct dm_data *ob_data = (struct dm_data *)data;
	char *dm_path = (char *)ob_data->additional_data;

	if (DM_STRLEN(dm_path) == 0) {
		return ret;
	}

	switch (action) {
	case VALUECHECK:
		if (bbfdm_validate_string(ctx, value, -1, 256, NULL, NULL)) {
			ret = FAULT_9007;
			break;
		}

		ret = 0;
		break;
	case VALUESET:
		snprintf(param_path, sizeof(param_path), "%s.Password", dm_path);
		ret = set_succeed(param_path, value);
		break;
	}

	return ret;
}

static int get_MQTTClient_ConnectRetryTime(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct dm_data *ob_data = (struct dm_data *)data;

	*value = dmjson_get_value(ob_data->json_object, 1, "ConnectRetryTime");
	return 0;
}

static int set_MQTTClient_ConnectRetryTime(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char param_path[MAX_PATH_LEN] = {0};
	int ret = FAULT_9002;

	struct dm_data *ob_data = (struct dm_data *)data;
	char *dm_path = (char *)ob_data->additional_data;

	if (DM_STRLEN(dm_path) == 0) {
		return ret;
	}

	switch (action) {
	case VALUECHECK:
		if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{"1",NULL}}, 1)) {
			ret = FAULT_9007;
			break;
		}

		ret = 0;
		break;
	case VALUESET:
		snprintf(param_path, sizeof(param_path), "%s.ConnectRetryTime", dm_path);
		ret = set_succeed(param_path, value);
		break;
	}

	return ret;
}

static int get_MQTTClient_ConnectRetryIntervalMultiplier(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct dm_data *ob_data = (struct dm_data *)data;

	*value = dmjson_get_value(ob_data->json_object, 1, "ConnectRetryIntervalMultiplier");
	return 0;
}

static int set_MQTTClient_ConnectRetryIntervalMultiplier(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char param_path[MAX_PATH_LEN] = {0};
	int ret = FAULT_9002;

	struct dm_data *ob_data = (struct dm_data *)data;
	char *dm_path = (char *)ob_data->additional_data;

	if (DM_STRLEN(dm_path) == 0) {
		return ret;
	}

	switch (action) {
	case VALUECHECK:
		if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{"1000","65535"}}, 1)) {
			ret = FAULT_9007;
			break;
		}

		ret = 0;
		break;
	case VALUESET:
		snprintf(param_path, sizeof(param_path), "%s.ConnectRetryIntervalMultiplier", dm_path);
		ret = set_succeed(param_path, value);
		break;
	}

	return ret;
}

static int get_MQTTClient_ConnectRetryMaxInterval(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct dm_data *ob_data = (struct dm_data *)data;

	*value = dmjson_get_value(ob_data->json_object, 1, "ConnectRetryMaxInterval");
	return 0;
}

static int set_MQTTClient_ConnectRetryMaxInterval(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char param_path[MAX_PATH_LEN] = {0};
	int ret = FAULT_9002;

	struct dm_data *ob_data = (struct dm_data *)data;
	char *dm_path = (char *)ob_data->additional_data;

	if (DM_STRLEN(dm_path) == 0) {
		return ret;
	}

	switch (action) {
	case VALUECHECK:
		if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{"1",NULL}}, 1)) {
			ret = FAULT_9007;
			break;
		}

		ret = 0;
		break;
	case VALUESET:
		snprintf(param_path, sizeof(param_path), "%s.ConnectRetryMaxInterval", dm_path);
		ret = set_succeed(param_path, value);
		break;
	}

	return ret;
}

static int get_MQTTClient_ResponseInformation(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct dm_data *ob_data = (struct dm_data *)data;

	*value = dmjson_get_value(ob_data->json_object, 1, "ResponseInformation");
	return 0;
}

static int get_MQTTClient_SubscriptionNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct dm_data *ob_data = (struct dm_data *)data;

	*value = dmjson_get_value(ob_data->json_object, 1, "SubscriptionNumberOfEntries");
	return 0;
}

static int get_MQTTClientSubscription_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct dm_data *ob_data = (struct dm_data *)data;

	*value = dmjson_get_value(ob_data->json_object, 1, "Alias");
	return 0;
}

static int set_MQTTClientSubscription_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char param_path[MAX_PATH_LEN] = {0};
	int ret = FAULT_9002;

	struct dm_data *ob_data = (struct dm_data *)data;
	char *dm_path = (char *)ob_data->additional_data;

	if (DM_STRLEN(dm_path) == 0) {
		return ret;
	}

	switch (action) {
	case VALUECHECK:
		if (bbfdm_validate_string(ctx, value, -1, 64, NULL, NULL)) {
			ret = FAULT_9007;
			break;
		}

		ret = 0;
		break;
	case VALUESET:
		snprintf(param_path, sizeof(param_path), "%s.Alias", dm_path);
		ret = set_succeed(param_path, value);
		break;
	}

	return ret;
}

static int get_MQTTClientSubscription_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct dm_data *ob_data = (struct dm_data *)data;

	*value = dmjson_get_value(ob_data->json_object, 1, "Enable");
	return 0;
}

static int set_MQTTClientSubscription_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char param_path[MAX_PATH_LEN] = {0};
	int ret = FAULT_9002;

	struct dm_data *ob_data = (struct dm_data *)data;
	char *dm_path = (char *)ob_data->additional_data;

	if (DM_STRLEN(dm_path) == 0) {
		return ret;
	}

	switch (action) {
	case VALUECHECK:
		if (bbfdm_validate_boolean(ctx, value)) {
			ret = FAULT_9007;
			break;
		}

		ret = 0;
		break;
	case VALUESET:
		snprintf(param_path, sizeof(param_path), "%s.Enable", dm_path);
		ret = set_succeed(param_path, value);
		break;
	}

	return ret;
}

static int get_MQTTClientSubscription_Topic(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct dm_data *ob_data = (struct dm_data *)data;

	*value = dmjson_get_value(ob_data->json_object, 1, "Topic");
	return 0;
}

static int set_MQTTClientSubscription_Topic(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char param_path[MAX_PATH_LEN] = {0};
	int ret = FAULT_9002;

	struct dm_data *ob_data = (struct dm_data *)data;
	char *dm_path = (char *)ob_data->additional_data;

	if (DM_STRLEN(dm_path) == 0) {
		return ret;
	}

	switch (action) {
	case VALUECHECK:
		if (bbfdm_validate_string(ctx, value, -1, 65535, NULL, NULL)) {
			ret = FAULT_9007;
			break;
		}

		ret = 0;
		break;
	case VALUESET:
		snprintf(param_path, sizeof(param_path), "%s.Topic", dm_path);
		ret = set_succeed(param_path, value);
		break;
	}

	return ret;
}

static int get_MQTTClientSubscription_QoS(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct dm_data *ob_data = (struct dm_data *)data;

	*value = dmjson_get_value(ob_data->json_object, 1, "QoS");
	return 0;
}

static int set_MQTTClientSubscription_QoS(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char param_path[MAX_PATH_LEN] = {0};
	int ret = FAULT_9002;

	struct dm_data *ob_data = (struct dm_data *)data;
	char *dm_path = (char *)ob_data->additional_data;

	if (DM_STRLEN(dm_path) == 0) {
		return ret;
	}

	switch (action) {
	case VALUECHECK:
		if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{"0","2"}}, 1)) {
			ret = FAULT_9007;
			break;
		}

		ret = 0;
		break;
	case VALUESET:
		snprintf(param_path, sizeof(param_path), "%s.QoS", dm_path);
		ret = set_succeed(param_path, value);
		break;
	}

	return ret;
}

/**********************************************************************************************************************************
*                                            OBJ & PARAM DEFINITION
***********************************************************************************************************************************/
/* *** Device.MQTT. *** */
DMOBJ tMQTTObj[] = {
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys */
{"Capabilities", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tMQTTCapabilitiesParams, NULL, BBFDM_CWMP, NULL},
{"Client", &DMWRITE, addObjMQTTClient, delObjMQTTClient, NULL, browseMQTTClientInst, NULL, NULL, tMQTTClientObj, tMQTTClientParams, NULL, BBFDM_CWMP, NULL},
{0}
};

DMLEAF tMQTTParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type */
{"ClientNumberOfEntries", &DMREAD, DMT_UNINT, get_MQTT_ClientNumberOfEntries, NULL, BBFDM_CWMP},
{0}
};

/* *** Device.MQTT.Capabilities. *** */
DMLEAF tMQTTCapabilitiesParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type */
{"ProtocolVersionsSupported", &DMREAD, DMT_STRING, get_MQTTCapabilities_ProtocolVersionsSupported, NULL, BBFDM_CWMP},
{"TransportProtocolSupported", &DMREAD, DMT_STRING, get_MQTTCapabilities_TransportProtocolSupported, NULL, BBFDM_CWMP},
{"MaxNumberOfClientSubscriptions", &DMREAD, DMT_UNINT, get_MQTTCapabilities_MaxNumberOfClientSubscriptions, NULL, BBFDM_CWMP},
{0}
};

/* *** Device.MQTT.Client.{i}. *** */
DMOBJ tMQTTClientObj[] = {
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys */
{"Subscription", &DMWRITE, addObjMQTTClientSubscription, delObjMQTTClientSubscription, NULL, browseMQTTClientSubscriptionInst, NULL, NULL, NULL, tMQTTClientSubscriptionParams, NULL, BBFDM_CWMP, NULL},
{0}
};

DMLEAF tMQTTClientParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type */
{"Alias", &DMWRITE, DMT_STRING, get_MQTTClient_Alias, set_MQTTClient_Alias, BBFDM_CWMP},
{"Name", &DMWRITE, DMT_STRING, get_MQTTClient_Name, set_MQTTClient_Name, BBFDM_CWMP},
{"Enable", &DMWRITE, DMT_BOOL, get_MQTTClient_Enable, set_MQTTClient_Enable, BBFDM_CWMP},
{"Status", &DMREAD, DMT_STRING, get_MQTTClient_Status, NULL, BBFDM_CWMP},
{"ProtocolVersion", &DMWRITE, DMT_STRING, get_MQTTClient_ProtocolVersion, set_MQTTClient_ProtocolVersion, BBFDM_CWMP},
{"BrokerAddress", &DMWRITE, DMT_STRING, get_MQTTClient_BrokerAddress, set_MQTTClient_BrokerAddress, BBFDM_CWMP},
{"BrokerPort", &DMWRITE, DMT_UNINT, get_MQTTClient_BrokerPort, set_MQTTClient_BrokerPort, BBFDM_CWMP},
{"TransportProtocol", &DMWRITE, DMT_STRING, get_MQTTClient_TransportProtocol, set_MQTTClient_TransportProtocol, BBFDM_CWMP},
{"CleanSession", &DMWRITE, DMT_BOOL, get_MQTTClient_CleanSession, set_MQTTClient_CleanSession, BBFDM_CWMP},
{"CleanStart", &DMWRITE, DMT_BOOL, get_MQTTClient_CleanStart, set_MQTTClient_CleanStart, BBFDM_CWMP},
{"KeepAliveTime", &DMWRITE, DMT_UNINT, get_MQTTClient_KeepAliveTime, set_MQTTClient_KeepAliveTime, BBFDM_CWMP},
{"RequestResponseInfo", &DMWRITE, DMT_BOOL, get_MQTTClient_RequestResponseInfo, set_MQTTClient_RequestResponseInfo, BBFDM_CWMP},
{"ClientID", &DMWRITE, DMT_STRING, get_MQTTClient_ClientID, set_MQTTClient_ClientID, BBFDM_CWMP},
{"Username", &DMWRITE, DMT_STRING, get_MQTTClient_Username, set_MQTTClient_Username, BBFDM_CWMP},
{"Password", &DMWRITE, DMT_STRING, get_MQTTClient_Password, set_MQTTClient_Password, BBFDM_CWMP},
{"ConnectRetryTime", &DMWRITE, DMT_UNINT, get_MQTTClient_ConnectRetryTime, set_MQTTClient_ConnectRetryTime, BBFDM_CWMP},
{"ConnectRetryIntervalMultiplier", &DMWRITE, DMT_UNINT, get_MQTTClient_ConnectRetryIntervalMultiplier, set_MQTTClient_ConnectRetryIntervalMultiplier, BBFDM_CWMP},
{"ConnectRetryMaxInterval", &DMWRITE, DMT_UNINT, get_MQTTClient_ConnectRetryMaxInterval, set_MQTTClient_ConnectRetryMaxInterval, BBFDM_CWMP},
{"ResponseInformation", &DMREAD, DMT_STRING, get_MQTTClient_ResponseInformation, NULL, BBFDM_CWMP},
{"SubscriptionNumberOfEntries", &DMREAD, DMT_UNINT, get_MQTTClient_SubscriptionNumberOfEntries, NULL, BBFDM_CWMP},
{0}
};

/* *** Device.MQTT.Client.{i}.Subscription.{i}. *** */
DMLEAF tMQTTClientSubscriptionParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type */
{"Alias", &DMWRITE, DMT_STRING, get_MQTTClientSubscription_Alias, set_MQTTClientSubscription_Alias, BBFDM_CWMP},
{"Enable", &DMWRITE, DMT_BOOL, get_MQTTClientSubscription_Enable, set_MQTTClientSubscription_Enable, BBFDM_CWMP},
{"Topic", &DMWRITE, DMT_STRING, get_MQTTClientSubscription_Topic, set_MQTTClientSubscription_Topic, BBFDM_CWMP},
{"QoS", &DMWRITE, DMT_UNINT, get_MQTTClientSubscription_QoS, set_MQTTClientSubscription_QoS, BBFDM_CWMP},
{0}
};
#endif
