/*
 * Copyright (C) 2023 iopsys Software Solutions AB
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 2.1
 * as published by the Free Software Foundation
 *
 */

#include "servicesvoiceservice.h"
#include "servicesvoiceservicedect.h"

#define ASTERISK_CONFIG_DEF "/usr/voice/asterisk_defaults"
#define ASTERISK_CONFIG UCI_CONFIG_DIR "asterisk"
#define DECT_CONFIG_DEF "/usr/voice/dect_defaults"
#define DECT_CONFIG UCI_CONFIG_DIR "dect"
#define DMMAP_CONFIG BBFDM_CONFIG "/dmmap"
#define DMMAP_ASTERISK_CONFIG BBFDM_CONFIG "/dmmap_asterisk"

static int get_ServicesVoiceHalInit(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
    	struct uci_section *s;

	if ((s = is_dmmap_section_exist("dmmap_voice_hal_init", "general")))
	    *value = dmuci_get_value_by_section_fallback_def(s, "init_done", "0");

	return 0;
}

static int set_ServicesVoiceHalInit(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	bool b;
	struct uci_section *dmmap = NULL, *s = NULL, *stmp = NULL;

	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_boolean(ctx, value))
				return FAULT_9007;
		case VALUESET:
			if (!(dmmap = is_dmmap_section_exist("dmmap_voice_hal_init", "general"))) {
				dmuci_add_section("voice_hal_init", "general", &s);
				dmuci_add_section_bbfdm("dmmap_voice_hal_init", "general", &dmmap);
				dmuci_set_value_by_section(dmmap, "section_name", section_name(s));
			}
			string_to_bool(value, &b);
			uci_foreach_sections_safe("voice_hal_init", "general", stmp, s) {
				get_dmmap_section_of_config_section("dmmap_voice_hal_init", "general", section_name(s), &dmmap);
				dmuci_set_value_by_section(dmmap, "init_done", b ? "1" : "0");
				dmuci_set_value_by_section(s, "init_done", b ? "1" : "0");
			}

			return 0;
	}
	return 0;
}

static int get_ServicesVoiceService_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmuci_get_option_value_fallback_def("asterisk", "general", "enable", "0");
	return 0;
}

static int set_ServicesVoiceService_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	bool b;

	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_boolean(ctx, value))
				return FAULT_9007;
			break;
		case VALUESET:
			string_to_bool(value, &b);
			dmuci_set_value("asterisk", "general", "enable", b ? "1" : "0");
			break;
	}
	return 0;
}

static int get_ServicesVoiceService_BoundIpAddr(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_option_value_string("asterisk", "sip_options", "bindaddr", value);
	return 0;
}

static int set_ServicesVoiceService_BoundIpAddr(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action) {
		case VALUECHECK:
			if (!*value)
				break;
			if (bbfdm_validate_string(ctx, value, -1, 45, NULL, IPAddress))
				return FAULT_9007;
			break;
		case VALUESET:
			dmuci_set_value("asterisk", "sip_options", "bindaddr", value);
			break;
	}
	return 0;
}

static int get_ServicesVoiceService_FactoryReset(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmstrdup("0");
	return 0;
}

static int set_ServicesVoiceService_FactoryReset(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	bool b;

	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_boolean(ctx, value))
				return FAULT_9007;
			break;
		case VALUESET:
			string_to_bool(value, &b);
			if (!b)
				break;
			if ( (dm_file_copy(ASTERISK_CONFIG_DEF, ASTERISK_CONFIG) < 0) || (dm_file_copy(DECT_CONFIG_DEF, DECT_CONFIG) < 0) )
				return FAULT_9002;

			remove(DMMAP_CONFIG);
			remove(DMMAP_ASTERISK_CONFIG);
			break;
	}
	return 0;
}

static int get_ServicesVoiceService_DnsServers(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	int i;

	dmuci_get_option_value_string("asterisk", "dns_options", "dns_server", value);

	if (!value || !*value)
		return 0;

	// Convert space-separated list to comma-separated
	for (i = 0; i < strlen(*value); i++) {
		if ((*value)[i] == ' ')
			(*value)[i] = ',';
	}

	return 0;
}

static int set_ServicesVoiceService_DnsServers(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char *dns_server_list = NULL, *token = NULL, *saveptr = NULL;

	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_string(ctx, value, -1, 256, NULL, NULL))
				return FAULT_9007;

			dns_server_list = dmstrdup(value);
			for (token = strtok_r(dns_server_list, ",", &saveptr); token && *token;
				token = strtok_r(NULL, ",", &saveptr)) {
				if (bbfdm_validate_string(ctx, token, -1, 45, NULL, IPAddress)) {
					dmfree(dns_server_list);
					return FAULT_9007;
				}
			}
			dmfree(dns_server_list);
			break;
		case VALUESET:
			// Clean the existing dns servers list
			dmuci_set_value("asterisk", "dns_options", "dns_server", "");

			if (!*value)
				break;

			dns_server_list = dmstrdup(value);
			for (token = strtok_r(dns_server_list, ",", &saveptr); token;
				token = strtok_r(NULL, ",", &saveptr)) {
				dmuci_add_list_value("asterisk", "dns_options", "dns_server", token);
			}
			dmfree(dns_server_list);

			break;
	}
	return 0;
}

static int get_ServicesVoiceService_OngoingEmergencyCall(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	json_object *res = NULL;
	struct dmmap_dup *p = NULL;
	char ext[16], *emergency, *ext_inst = "";
	LIST_HEAD(dup_list);

	*value = dmstrdup("0");

	synchronize_specific_config_sections_with_dmmap("asterisk", "extension", "dmmap_asterisk", &dup_list);

	list_for_each_entry(p, &dup_list, list) {
		dmuci_get_value_by_section_string(p->dmmap_section, "extensioninstance", &ext_inst);
		snprintf(ext, sizeof(ext), "%d", *ext_inst ? (int)DM_STRTOL(ext_inst) - 1 : 0);
		dmubus_call("asterisk", "call_status", UBUS_ARGS{{"extension", ext, Integer}}, 1, &res);
		if (!res) {
			BBF_DEBUG("Failed ubus get of emergency call status\n");
			break;
		}

		emergency = dmjson_get_value(res, 1, "emergency");
		if (DM_STRCMP(emergency, "true") == 0) {
			*value = dmstrdup("1");
			break;
		}
	}

	free_dmmap_config_dup_list(&dup_list);
	return 0;
}

static int get_ServicesVoiceService_IpAddressFamily(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmstrdup("IPv4");

	return 0;
}

static int set_ServicesVoiceService_IpAddressFamily(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_string(ctx, value, 4, 4, NULL, NULL))
				return FAULT_9007;
			if (DM_STRCMP(value, "IPv4") != 0)
				return FAULT_9007;
			break;
		case VALUESET:
			break;
	}

	return 0;
}

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

DMLEAF tVendor_ServicesParams[] = {
{BBF_VENDOR_PREFIX"VoiceHalInit", &DMWRITE, DMT_BOOL, get_ServicesVoiceHalInit, set_ServicesVoiceHalInit, BBFDM_BOTH},
{0}
};

DMLEAF tVendor_VoiceServiceParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type*/
{BBF_VENDOR_PREFIX"Enable", &DMWRITE, DMT_BOOL, get_ServicesVoiceService_Enable, set_ServicesVoiceService_Enable, BBFDM_BOTH},
{BBF_VENDOR_PREFIX"BoundIpAddr", &DMWRITE, DMT_STRING, get_ServicesVoiceService_BoundIpAddr, set_ServicesVoiceService_BoundIpAddr, BBFDM_BOTH},
{BBF_VENDOR_PREFIX"FactoryReset", &DMWRITE, DMT_BOOL, get_ServicesVoiceService_FactoryReset, set_ServicesVoiceService_FactoryReset, BBFDM_BOTH},
{BBF_VENDOR_PREFIX"DnsServers", &DMWRITE, DMT_STRING, get_ServicesVoiceService_DnsServers, set_ServicesVoiceService_DnsServers, BBFDM_BOTH},
{BBF_VENDOR_PREFIX"OngoingEmergencyCall", &DMREAD, DMT_BOOL, get_ServicesVoiceService_OngoingEmergencyCall, NULL, BBFDM_BOTH},
{BBF_VENDOR_PREFIX"IpAddressFamily", &DMWRITE, DMT_STRING, get_ServicesVoiceService_IpAddressFamily, set_ServicesVoiceService_IpAddressFamily, BBFDM_BOTH},
{0}
};

DM_MAP_OBJ tDynamicObj[] = {
/* parentobj, nextobject, parameter */
{"Device.Services.", NULL, tVendor_ServicesParams},
{"Device.Services.VoiceService.{i}.", NULL, tVendor_VoiceServiceParams},
{"Device.Services.VoiceService.{i}.DECT.Base.{i}.", NULL, tVendor_VoiceServiceDECTBaseParams},
{0}
};
