#include "libbbfdm-api/dmcommon.h"

#ifdef HAS_VENDOR_EXT

static void get_option_value_by_mac(const char *host_mac, const char *option, char **value)
{
	struct uci_section *s = NULL;

	if (!host_mac || !option)
		return;

	uci_path_foreach_option_eq(bbfdm, "dmmap_hosts", "host", "mac", host_mac, s) {
		dmuci_get_value_by_section_string(s, option, value);
		return;
	}
}

static void set_option_value_by_mac(const char *host_mac, const char *option, char *value)
{
	struct uci_section *s = NULL;

	if (!host_mac || !option)
		return;

	uci_path_foreach_option_eq(bbfdm, "dmmap_hosts", "host", "mac", host_mac, s) {
		dmuci_set_value_by_section_bbfdm(s, option, value);
		break;
	}

	if (!s) {
		dmuci_add_section_bbfdm("dmmap_hosts", "host", &s);
		dmuci_set_value_by_section_bbfdm(s, "mac", host_mac);
		dmuci_set_value_by_section_bbfdm(s, option, value);
	}
}

static void get_host_from_dhcp_by_mac(const char *host_mac, const char *option, char **value)
{
	struct uci_section *s = NULL;

	if (!host_mac || !option)
		return;

	uci_foreach_option_eq("dhcp", "host", "mac", host_mac, s) {
		dmuci_get_value_by_section_string(s, option, value);
		return;
	}
}

static int set_host_from_dhcp_by_mac(const char *host_mac, const char *network, const char *option, char *value)
{
	struct uci_section *s = NULL;
	char *mac = NULL;

	if (!host_mac || !option || !network)
		return 0;

	// name uniqueness check
	uci_foreach_option_eq("dhcp", "host", "name", value, s) {
		dmuci_get_value_by_section_string(s, "mac", &mac);
		if (DM_STRCMP(mac, host_mac) != 0)
			return FAULT_9007;
		break;
	}

	uci_foreach_option_eq("dhcp", "host", "mac", host_mac, s) {
		dmuci_set_value_by_section(s, option, value);
		break;
	}

	if (!s) {
		dmuci_add_section("dhcp", "host", &s);
		dmuci_set_value_by_section(s, "mac", host_mac);
		dmuci_set_value_by_section(s, "dhcp_pool", network);
		dmuci_set_value_by_section(s, option, value);
	}
	return 0;
}

static int get_HostsHost_isieee1905(char *refparam, struct dmctx *ctx, void *prev_data, char *instance, char **value)
{
	*value = (dmuci_string_to_boolean(dmjson_get_value(((struct dm_data *)prev_data)->json_object, 1, "is1905")) == true) ? "1" : "0";
	return 0;
}

static int get_HostsHost_ieee1905id(char *refparam, struct dmctx *ctx, void *prev_data, char *instance, char **value)
{
	*value = dmjson_get_value(((struct dm_data *)prev_data)->json_object, 1, "ieee1905id");
	return 0;
}

static int get_HostsHost_type(char *refparam, struct dmctx *ctx, void *prev_data, char *instance, char **value)
{
	char *mac = dmjson_get_value(((struct dm_data *)prev_data)->json_object, 1, "macaddr");

	get_option_value_by_mac(mac, "hosttype", value);

	return 0;
}

static int set_HostsHost_type(char *refparam, struct dmctx *ctx, void *prev_data, char *instance, char *value, int action)
{
	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_string(ctx, value, -1, 64, NULL, NULL))
				return FAULT_9007;
			break;
		case VALUESET:
			char *mac = dmjson_get_value(((struct dm_data *)prev_data)->json_object, 1, "macaddr");
			set_option_value_by_mac(mac, "hosttype", value);
			break;
	}
	return 0;
}

static int get_HostsHost_name(char *refparam, struct dmctx *ctx, void *prev_data, char *instance, char **value)
{
	char *mac = dmjson_get_value(((struct dm_data *)prev_data)->json_object, 1, "macaddr");

	get_host_from_dhcp_by_mac(mac, "name", value);
	if (DM_STRLEN(*value) == 0) {
		*value = dmjson_get_value(((struct dm_data *)prev_data)->json_object, 1, "hostname");
	}

	return 0;
}

static int set_HostsHost_name(char *refparam, struct dmctx *ctx, void *prev_data, char *instance, char *value, int action)
{

	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_string(ctx, value, -1, 64, NULL, NULL))
				return FAULT_9007;
			break;
		case VALUESET:
			char *mac = dmjson_get_value(((struct dm_data *)prev_data)->json_object, 1, "macaddr");
			char *network = dmjson_get_value(((struct dm_data *)prev_data)->json_object, 1, "network");
			if (set_host_from_dhcp_by_mac(mac, network, "name", value)) {
				bbfdm_set_fault_message(ctx, "Name %s already used", value);
				return FAULT_9007;
			}
			break;
	}
	return 0;
}

static int get_HostsHost_activeconnections(char *refparam, struct dmctx *ctx, void *prev_data, char *instance, char **value)
{
	*value = dmjson_get_value(((struct dm_data *)prev_data)->json_object, 1, "active_connections");
	return 0;
}

static int get_HostsHost_reconnectcount(char *refparam, struct dmctx *ctx, void *prev_data, char *instance, char **value)
{
	*value = dmjson_get_value(((struct dm_data *)prev_data)->json_object, 1, "reconnect_count");
	return 0;
}

/*#Device.Hosts.AccessControl.{i}.X_IOWRT_EU_ExpiryDate!UCI:hosts/access_control,@i-1/expiry*/
static int get_HostsAccessControl_ExpiryDate(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
       char *expiry_date = NULL;

       dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "expiry", &expiry_date);

       if (DM_STRLEN(expiry_date) != 0 && DM_STRTOL(expiry_date) > 0) {
               char expiry[sizeof "AAAA-MM-JJTHH:MM:SSZ"];
               time_t time_value = DM_STRTOL(expiry_date);

               strftime(expiry, sizeof expiry, "%Y-%m-%dT%H:%M:%SZ", gmtime(&time_value));
               *value = dmstrdup(expiry);
       } else {
               *value = dmstrdup("9999-12-31T23:59:59Z");
       }

       return 0;
}

static int set_HostsAccessControl_ExpiryDate(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
       char expiry_date[16];
       struct tm tm;

       switch (action) {
               case VALUECHECK:
                       if (bbfdm_validate_dateTime(ctx, value))
                               return FAULT_9007;
                       break;
               case VALUESET:
                       memset(&tm, 0, sizeof(tm));
                       strptime(value, "%Y-%m-%dT%H:%M:%SZ", &tm);
                       snprintf(expiry_date, sizeof(expiry_date), "%lld", (long long)timegm(&tm));
                       dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "expiry", expiry_date);
                       break;
       }
       return 0;
}

/**********************************************************************************************************************************
*                                            OBJ & PARAM DEFINITION
***********************************************************************************************************************************/

DMLEAF tHostsHostAccessControlParamsExtn[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{CUSTOM_PREFIX"ExpiryDate", &DMWRITE, DMT_TIME, get_HostsAccessControl_ExpiryDate, set_HostsAccessControl_ExpiryDate, BBFDM_BOTH},
{0}
};

DMLEAF tHostsHostParamsExtn[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{CUSTOM_PREFIX"IsIEEE1905", &DMREAD, DMT_BOOL, get_HostsHost_isieee1905, NULL, BBFDM_BOTH},
{CUSTOM_PREFIX"IEEE1905ID", &DMREAD, DMT_STRING, get_HostsHost_ieee1905id, NULL, BBFDM_BOTH},
{CUSTOM_PREFIX"ActiveIPConnections", &DMREAD, DMT_INT, get_HostsHost_activeconnections, NULL, BBFDM_BOTH},
{CUSTOM_PREFIX"ReconnectCount", &DMREAD, DMT_INT, get_HostsHost_reconnectcount, NULL, BBFDM_BOTH},
{CUSTOM_PREFIX"Type", &DMWRITE, DMT_STRING, get_HostsHost_type, set_HostsHost_type, BBFDM_BOTH},
{CUSTOM_PREFIX"Name", &DMWRITE, DMT_STRING, get_HostsHost_name, set_HostsHost_name, BBFDM_BOTH},
{0}
};

DM_MAP_OBJ tDynamicObj[] = {
/* parentobj, nextobject, parameter */
{"Device.Hosts.Host.{i}.", NULL, tHostsHostParamsExtn},
{"Device.Hosts.AccessControl.{i}.", NULL, tHostsHostAccessControlParamsExtn},
{0}
};

#endif
