/* Osmocom CBC (Cell Broacast Centre) */

/* (C) 2019 by Harald Welte <laforge@gnumonks.org>
 * All Rights Reserved
 *
 * SPDX-License-Identifier: AGPL-3.0+
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */


#include <errno.h>

#include <osmocom/core/linuxlist.h>
#include <osmocom/core/utils.h>
#include <osmocom/gsm/cbsp.h>
#include <osmocom/cbc/cbsp_msg.h>
#include <osmocom/cbc/cbc_message.h>

/* convert cbc_message to osmo_cbsp_cell_list */
static int cbcmsg_to_cbsp_cell_list(const void *ctx, struct osmo_cbsp_cell_list *list,
				    const struct cbc_message *cbcmsg)
{
	struct osmo_cbsp_cell_ent *ent;

	switch (cbcmsg->scope) {
	case CBC_MSG_SCOPE_PLMN:
		list->id_discr = CELL_IDENT_BSS;
		ent = talloc_zero(ctx, struct osmo_cbsp_cell_ent);
		if (!ent)
			return -ENOMEM;
		//ent->cell_id = ?
		llist_add_tail(&ent->list, &list->list);
		return 0;
	default:
		OSMO_ASSERT(0);
	}
}

/* generate a CBSP WRITE-REPLACE from our internal representation */
struct osmo_cbsp_decoded *cbsp_gen_write_replace_req(void *ctx, const struct cbc_message *cbcmsg)
{
	struct osmo_cbsp_write_replace *wrepl;
	const struct smscb_message *smscb = &cbcmsg->msg;
	struct osmo_cbsp_decoded *cbsp = osmo_cbsp_decoded_alloc(ctx, CBSP_MSGT_WRITE_REPLACE);
	unsigned int i;
	int rc;

	if (!cbsp)
		return NULL;
	wrepl = &cbsp->u.write_replace;

	wrepl->msg_id = smscb->message_id;
	wrepl->new_serial_nr = smscb->serial_nr;
	/* FIXME: old? */
	/* Cell list */
	rc = cbcmsg_to_cbsp_cell_list(cbcmsg, &wrepl->cell_list, cbcmsg);
	if (rc < 0) {
		talloc_free(cbsp);
		return NULL;
	}
	if (!smscb->is_etws)
		wrepl->is_cbs = true;
	if (wrepl->is_cbs) {
		if (cbcmsg->extended_cbch)
			wrepl->u.cbs.channel_ind = CBSP_CHAN_IND_EXTENDED;
		else
			wrepl->u.cbs.channel_ind = CBSP_CHAN_IND_BASIC;
		wrepl->u.cbs.category = cbcmsg->priority;
		wrepl->u.cbs.rep_period = cbcmsg->rep_period;
		wrepl->u.cbs.num_bcast_req = cbcmsg->num_bcast;
		wrepl->u.cbs.dcs = smscb->cbs.dcs;
		INIT_LLIST_HEAD(&wrepl->u.cbs.msg_content);
		for (i = 0; i < smscb->cbs.num_pages; i++) {
			struct osmo_cbsp_content *ce = talloc_zero(cbsp, struct osmo_cbsp_content);
			if (i == smscb->cbs.num_pages - 1)
				ce->user_len = smscb->cbs.data_user_len - (i * SMSCB_RAW_PAGE_LEN);
			else
				ce->user_len = SMSCB_RAW_PAGE_LEN;
			memcpy(ce->data, smscb->cbs.data[i], SMSCB_RAW_PAGE_LEN);
			llist_add_tail(&ce->list, &wrepl->u.cbs.msg_content);
		}
	} else {
		wrepl->u.emergency.indicator = 1;
		wrepl->u.emergency.warning_type = (smscb->etws.warning_type & 0x7f) << 9;
		if (smscb->etws.user_alert)
			wrepl->u.emergency.warning_type |= 0x0100;
		if (smscb->etws.popup_on_display)
			wrepl->u.emergency.warning_type |= 0x0080;
		memcpy(wrepl->u.emergency.warning_sec_info, smscb->etws.warning_sec_info,
			sizeof(wrepl->u.emergency.warning_sec_info));
		if (cbcmsg->warning_period_sec == 0xffffffff)
			wrepl->u.emergency.warning_period = 0;
		else
			wrepl->u.emergency.warning_period = cbcmsg->warning_period_sec;
	}
	return cbsp;
}