/*
 * Copyright (C) 2020 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
 *
 *	Author: Yalu Zhang, yalu.zhang@iopsys.eu
 */

#include "servicesvoiceservicevoipprofile.h"
#include "common.h"

/*************************************************************
* GET & SET PARAM
**************************************************************/
static int get_ServicesVoiceServiceVoIPProfile_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmuci_get_option_value_fallback_def("asterisk", "general", "profile_enable", "1");
	return 0;
}

static int set_ServicesVoiceServiceVoIPProfile_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", "profile_enable", b ? "1" : "0");
			break;
	}
	return 0;
}

/*#Device.Services.VoiceService.{i}.VoIPProfile.{i}.DTMFMethod!UCI:asterisk/sip_advanced,sip_options/dtmf_mode*/
static int get_ServicesVoiceServiceVoIPProfile_DTMFMethod(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	char *method = NULL;

	dmuci_get_option_value_string(TR104_UCI_PACKAGE, "sip_options", "dtmf_mode", &method);
	if (method && *method) {
		if (strcasecmp(method, "inband") == 0)
			*value = dmstrdup("InBand");
		else if (strcasecmp(method, "rfc4733") == 0)
			*value = dmstrdup("RFC4733");
		else if (strcasestr(method, "info") != NULL)
			*value = dmstrdup("SIPInfo");
	}

	return 0;
}

static int set_ServicesVoiceServiceVoIPProfile_DTMFMethod(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char buf[8] = {0};

	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_string_list(ctx, value, -1, -1, -1, -1, -1, DTMFMethod, NULL))
				return FAULT_9007;
			break;
		case VALUESET:
			if (strcasecmp(value, "InBand") == 0)
				snprintf(buf, sizeof(buf), "%s", "inband");
			else if (strcasecmp(value, "RFC4733") == 0)
				snprintf(buf, sizeof(buf), "%s", "rfc4733");
			else if (strcasecmp(value, "SIPInfo") == 0)
				snprintf(buf, sizeof(buf), "%s", "info");
			dmuci_set_value(TR104_UCI_PACKAGE, "sip_options", "dtmf_mode", buf);
			break;
	}

	return 0;
}

/*#Device.Services.VoiceService.{i}.VoIPProfile.{i}.RTP.LocalPortMin!UCI:asterisk/sip_advanced,sip_options/rtp_start*/
static int get_ServicesVoiceServiceVoIPProfileRTP_LocalPortMin(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmuci_get_option_value_fallback_def("asterisk", "sip_options", "rtp_start", "1024");
	return 0;
}

static int set_ServicesVoiceServiceVoIPProfileRTP_LocalPortMin(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{"1","65535"}}, 1))
				return FAULT_9007;
			break;
		case VALUESET:
			dmuci_set_value("asterisk", "sip_options", "rtp_start", value);
			break;
	}
	return 0;
}

/*#Device.Services.VoiceService.{i}.VoIPProfile.{i}.RTP.LocalPortMax!UCI:asterisk/sip_advanced,sip_options/rtp_end*/
static int get_ServicesVoiceServiceVoIPProfileRTP_LocalPortMax(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmuci_get_option_value_fallback_def("asterisk", "sip_options", "rtp_end", "1024");
	return 0;
}

static int set_ServicesVoiceServiceVoIPProfileRTP_LocalPortMax(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{"1","65535"}}, 1))
				return FAULT_9007;
			break;
		case VALUESET:
			dmuci_set_value("asterisk", "sip_options", "rtp_end", value);
			break;
	}
	return 0;
}

/*#Device.Services.VoiceService.{i}.VoIPProfile.{i}.RTP.DSCPMark!UCI:asterisk/sip_advanced,sip_options/tos_audio*/
static int get_ServicesVoiceServiceVoIPProfileRTP_DSCPMark(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmuci_get_option_value_fallback_def("asterisk", "sip_options", "tos_audio", "0");
	return 0;
}

static int set_ServicesVoiceServiceVoIPProfileRTP_DSCPMark(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{"0","63"}}, 1))
				return FAULT_9007;
			break;
		case VALUESET:
			dmuci_set_value("asterisk", "sip_options", "tos_audio", value);
			break;
	}
	return 0;
}

/*#Device.Services.VoiceService.{i}.VoIPProfile.{i}.RTP.TelephoneEventPayloadType!UCI:asterisk/tel_advanced,tel_options/tel_event_pt*/
static int get_ServicesVoiceServiceVoIPProfileRTP_TelephoneEventPayloadType(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmuci_get_option_value_fallback_def("asterisk", "tel_options", "tel_event_pt", "0");
	return 0;
}

static int set_ServicesVoiceServiceVoIPProfileRTP_TelephoneEventPayloadType(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{"96","127"}}, 1))
				return FAULT_9007;
			break;
		case VALUESET:
			dmuci_set_value("asterisk", "tel_options", "tel_event_pt", value);
			break;
	}
	return 0;
}

/*#Device.Services.VoiceService.{i}.VoIPProfile.{i}.RTP.JitterBufferType!UCI:asterisk/tel_advanced,tel_options/jb_impl*/
static int get_ServicesVoiceServiceVoIPProfileRTP_JitterBufferType(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	char *tmp = NULL;

	dmuci_get_option_value_string("asterisk", "tel_options", "jb_impl", &tmp);
	if (tmp && *tmp) {
		if (strcasecmp(tmp, "adaptive") == 0)
			*value = dmstrdup("Dynamic");
		else
			*value = dmstrdup("Static");
		dmfree(tmp);
	} else {
		*value = dmstrdup("");
	}
	return 0;
}

static int set_ServicesVoiceServiceVoIPProfileRTP_JitterBufferType(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_string(ctx, value, -1, -1, JitterBufferType, NULL))
				return FAULT_9007;
			break;
		case VALUESET:
			dmuci_set_value("asterisk", "tel_options", "jb_impl", (strcasecmp(value, "Dynamic") == 0) ? "adaptive" : "fixed");
			break;
	}
	return 0;
}

/*#Device.Services.VoiceService.{i}.VoIPProfile.{i}.RTP.JitterBufferMaxSize!UCI:asterisk/tel_advanced,tel_options/jb_maxsize*/
static int get_ServicesVoiceServiceVoIPProfileRTP_JitterBufferMaxSize(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmuci_get_option_value_fallback_def("asterisk", "tel_options", "jb_maxsize", "0");
	return 0;
}

static int set_ServicesVoiceServiceVoIPProfileRTP_JitterBufferMaxSize(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{NULL,NULL}}, 1))
				return FAULT_9007;
			break;
		case VALUESET:
			dmuci_set_value("asterisk", "tel_options", "jb_maxsize", value);
			break;
	}
	return 0;
}

/*#Device.Services.VoiceService.{i}.VoIPProfile.{i}.RTP.RTCP.TxRepeatInterval!UCI:asterisk/sip_advanced,sip_options/rtcpinterval*/
static int get_ServicesVoiceServiceVoIPProfileRTPRTCP_TxRepeatInterval(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmuci_get_option_value_fallback_def("asterisk", "sip_options", "rtcpinterval", "1");
	return 0;
}

static int set_ServicesVoiceServiceVoIPProfileRTPRTCP_TxRepeatInterval(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{"1",NULL}}, 1))
				return FAULT_9007;
			break;
		case VALUESET:
			dmuci_set_value("asterisk", "sip_options", "rtcpinterval", value);
			break;
	}
	return 0;
}

/*#Device.Services.VoiceService.{i}.VoIPProfile.{i}.RTP.SRTP.Enable!UCI:asterisk/sip_service_provider,@i-1/encryption*/
static int get_ServicesVoiceServiceVoIPProfileRTPSRTP_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "encryption", "1");
	return 0;
}

static int set_ServicesVoiceServiceVoIPProfileRTPSRTP_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_by_section(((struct dm_data *)data)->config_section, "encryption", b ? "1" : "0");
			break;
	}
	return 0;
}

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

static int set_ServicesVoiceServiceVoIPProfileRTPSRTP_KeyingMethods(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_string_list(ctx, value, -1, -1, -1, -1, -1, KeyingMethods, NULL))
				return FAULT_9007;
			break;
		case VALUESET:
			// To be supported in the future perhaps
			return FAULT_9000;
	}
	return 0;
}

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

static int set_ServicesVoiceServiceVoIPProfileRTPSRTP_EncryptionKeySizes(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_unsignedInt_list(ctx, value, -1, -1, -1, RANGE_ARGS{{NULL,NULL}}, 1))
				return FAULT_9007;
			break;
		case VALUESET:
			// To be supported in the future perhaps
			return FAULT_9000;
	}
	return 0;
}

/*Get Device.Services.VoiceService.{i}.VoIPProfile.{i}. Alias*/
static int get_ServicesVoiceServiceVoIPProfile_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	return get_Alias_value_by_inst(refparam, ctx, data, instance, value, "clientalias");
}

/*Set Device.Services.VoiceService.{i}.VoIPProfile.{i}. Alias*/
static int set_ServicesVoiceServiceVoIPProfile_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	return set_Alias_value_by_inst(refparam, ctx, data, instance, value, action, "clientalias");
}

/**********************************************************************************************************************************
*                                            OBJ & PARAM DEFINITION
***********************************************************************************************************************************/
/* *** Device.Services.VoiceService.{i}.VoIPProfile.{i}. *** */
DMOBJ tServicesVoiceServiceVoIPProfileObj[] = {
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys*/
{"RTP", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, tServicesVoiceServiceVoIPProfileRTPObj, tServicesVoiceServiceVoIPProfileRTPParams, NULL, BBFDM_BOTH},
{0}
};

DMLEAF tServicesVoiceServiceVoIPProfileParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type*/
{"DTMFMethod", &DMWRITE, DMT_STRING, get_ServicesVoiceServiceVoIPProfile_DTMFMethod, set_ServicesVoiceServiceVoIPProfile_DTMFMethod, BBFDM_BOTH},
{"Alias", &DMWRITE, DMT_STRING, get_ServicesVoiceServiceVoIPProfile_Alias, set_ServicesVoiceServiceVoIPProfile_Alias, BBFDM_BOTH, DM_FLAG_UNIQUE|DM_FLAG_LINKER},
{"Enable", &DMWRITE, DMT_BOOL, get_ServicesVoiceServiceVoIPProfile_Enable, set_ServicesVoiceServiceVoIPProfile_Enable, BBFDM_BOTH},
{0}
};

/* *** Device.Services.VoiceService.{i}.VoIPProfile.{i}.RTP. *** */
DMOBJ tServicesVoiceServiceVoIPProfileRTPObj[] = {
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys*/
{"RTCP", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tServicesVoiceServiceVoIPProfileRTPRTCPParams, NULL, BBFDM_BOTH},
{"SRTP", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tServicesVoiceServiceVoIPProfileRTPSRTPParams, NULL, BBFDM_BOTH},
{0}
};

DMLEAF tServicesVoiceServiceVoIPProfileRTPParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type*/
{"LocalPortMin", &DMWRITE, DMT_UNINT, get_ServicesVoiceServiceVoIPProfileRTP_LocalPortMin, set_ServicesVoiceServiceVoIPProfileRTP_LocalPortMin, BBFDM_BOTH},
{"LocalPortMax", &DMWRITE, DMT_UNINT, get_ServicesVoiceServiceVoIPProfileRTP_LocalPortMax, set_ServicesVoiceServiceVoIPProfileRTP_LocalPortMax, BBFDM_BOTH},
{"DSCPMark", &DMWRITE, DMT_UNINT, get_ServicesVoiceServiceVoIPProfileRTP_DSCPMark, set_ServicesVoiceServiceVoIPProfileRTP_DSCPMark, BBFDM_BOTH},
{"TelephoneEventPayloadType", &DMWRITE, DMT_UNINT, get_ServicesVoiceServiceVoIPProfileRTP_TelephoneEventPayloadType, set_ServicesVoiceServiceVoIPProfileRTP_TelephoneEventPayloadType, BBFDM_BOTH},
{"JitterBufferType", &DMWRITE, DMT_STRING, get_ServicesVoiceServiceVoIPProfileRTP_JitterBufferType, set_ServicesVoiceServiceVoIPProfileRTP_JitterBufferType, BBFDM_BOTH},
{"JitterBufferMaxSize", &DMWRITE, DMT_UNINT, get_ServicesVoiceServiceVoIPProfileRTP_JitterBufferMaxSize, set_ServicesVoiceServiceVoIPProfileRTP_JitterBufferMaxSize, BBFDM_BOTH},
{0}
};

/* *** Device.Services.VoiceService.{i}.VoIPProfile.{i}.RTP.RTCP. *** */
DMLEAF tServicesVoiceServiceVoIPProfileRTPRTCPParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type*/
{"TxRepeatInterval", &DMWRITE, DMT_UNINT, get_ServicesVoiceServiceVoIPProfileRTPRTCP_TxRepeatInterval, set_ServicesVoiceServiceVoIPProfileRTPRTCP_TxRepeatInterval, BBFDM_BOTH},
{0}
};

/* *** Device.Services.VoiceService.{i}.VoIPProfile.{i}.RTP.SRTP. *** */
DMLEAF tServicesVoiceServiceVoIPProfileRTPSRTPParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type*/
{"Enable", &DMWRITE, DMT_BOOL, get_ServicesVoiceServiceVoIPProfileRTPSRTP_Enable, set_ServicesVoiceServiceVoIPProfileRTPSRTP_Enable, BBFDM_BOTH},
{"KeyingMethods", &DMWRITE, DMT_STRING, get_ServicesVoiceServiceVoIPProfileRTPSRTP_KeyingMethods, set_ServicesVoiceServiceVoIPProfileRTPSRTP_KeyingMethods, BBFDM_BOTH},
{"EncryptionKeySizes", &DMWRITE, DMT_STRING, get_ServicesVoiceServiceVoIPProfileRTPSRTP_EncryptionKeySizes, set_ServicesVoiceServiceVoIPProfileRTPSRTP_EncryptionKeySizes, BBFDM_BOTH},
{0}
};
