/* MME (SBc-AP) Connection Handler of CBC test suite in TTCN-3
 * (C) 2022 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
 * All rights reserved.
 *
 * Author: Pau Espin Pedrol <pespin@sysmocom.de>
 *
 * Released under the terms of GNU General Public License, Version 2 or
 * (at your option) any later version.
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

module MME_ConnectionHandler {

import from SBC_AP_IEs all;
import from SBC_AP_Constants all;
import from SBC_AP_PDU_Contents all;
import from SBC_AP_PDU_Descriptions all;
import from SBC_AP_Types all;
import from SBC_AP_Templates all;
import from SBC_AP_CodecPort all;
import from SBC_AP_Adapter all;

import from CBS_Message all;

type function void_fn() runs on MME_ConnHdlr;

/* Coordinate with test_CT: */
type port MME_ConnHdlr_Coord_PT message {
	inout charstring;
} with { extension "internal" };

/* this component represents a single subscriber connection */
type component MME_ConnHdlr extends SBC_AP_Adapter_CT {
	var MME_ConnHdlrPars g_pars;
	port MME_ConnHdlr_Coord_PT COORD;
}

type record MME_ConnHdlrPars {
	charstring mme_host,
	integer mme_sbcap_port,
	charstring cbc_host,
	integer cbc_sbcap_port,
	boolean sctp_is_client,
	void_fn start_fn,
	CBS_Message exp_cbs_msg optional,
	SBC_AP_Cause write_replace_warning_req_cause,
	SBC_AP_Cause write_replace_warning_ind_cause optional,
	List_of_TAIs write_repl_unknown_TAIs optional,
	CellId_Broadcast_List bcast_cell_id_list optional
};

function f_MME_ConnHdlr_main(charstring id, MME_ConnHdlrPars pars) runs on MME_ConnHdlr {
	g_pars := pars;
	if (g_pars.sctp_is_client) {
		SBC_AP_Adapter.f_connect(g_pars.cbc_host, g_pars.cbc_sbcap_port,
					 g_pars.mme_host, g_pars.mme_sbcap_port);
	} else {
		SBC_AP_Adapter.f_bind(g_pars.mme_host, g_pars.mme_sbcap_port);
		SBC_AP_Adapter.f_wait_client_connect();
	}
	COORD.send(COORD_MSG_CONNECTED);
	g_pars.start_fn.apply();
}

function f_sbcap_tx_write_replace_warn_resp(CBS_Message msg, integer idx := 0)
runs on MME_ConnHdlr {
	var template (value) SBC_AP_PDU tx;
	if (ispresent(g_pars.write_repl_unknown_TAIs)) {
		tx := ts_SBCAP_WRITE_WARNING_RESP_UNKNOWN_TAI(
						int2bit(msg.msg_id, 16),
						int2bit(msg.ser_nr, 16),
						g_pars.write_replace_warning_req_cause,
						g_pars.write_repl_unknown_TAIs);
	} else {
		tx := ts_SBCAP_WRITE_WARNING_RESP(int2bit(msg.msg_id, 16),
						  int2bit(msg.ser_nr, 16),
						  g_pars.write_replace_warning_req_cause);
	}
	f_SBC_AP_send(tx, idx);
}

function f_sbcap_tx_write_replace_warn_ind(integer idx := 0, CBS_Message msg,
					   SBC_AP_Cause cause,
					   template (value) CellId_Broadcast_List bcast_cell_id_li)
runs on MME_ConnHdlr {
	var template (value) SBC_AP_PDU tx;
	tx := ts_SBCAP_WRITE_WARNING_IND(int2bit(msg.msg_id, 16),
					 int2bit(msg.ser_nr, 16),
					 cause, bcast_cell_id_li);
	f_SBC_AP_send(tx, idx);
}

function f_sbcap_tx_stop_warn_resp(integer idx := 0, CBS_Message msg)
runs on MME_ConnHdlr {
	var template (value) SBC_AP_PDU tx;
	tx := ts_SBCAP_STOP_WARNING_RESP(int2bit(msg.msg_id, 16),
					  int2bit(msg.ser_nr, 16));
	f_SBC_AP_send(tx, idx);
}

/* handle a SBc-AP Write-Replace Request and respond to it with Response or FAILURE depending on arguments */
function f_sbcap_handle_write_replace_warn_req(CBS_Message msg, integer idx := 0)
runs on MME_ConnHdlr {
	var template (present) SBC_AP_PDU rx_templ;
	var SBC_AP_RecvFrom rf;
	if (msg_id_is_etws(msg.msg_id)) {
		rx_templ := tr_SBCAP_WRITE_WARNING_REQ_ETWS(
				int2bit(msg.msg_id, 16), int2bit(msg.ser_nr, 16),
				msg.rep_period, msg.num_bcast_req, hex2oct('018'H & int2hex(msg.msg_id - 4352, 1)));
	} else {
		rx_templ := tr_SBCAP_WRITE_WARNING_REQ_CBS(
				int2bit(msg.msg_id, 16), int2bit(msg.ser_nr, 16),
				msg.rep_period, msg.num_bcast_req);
	}
	alt {
	[] SBC_AP[idx].receive(tr_SBC_AP_Recv(g_SBC_AP_conn_id[idx], rx_templ)) -> value rf {
		log ("received expected req:", rf);
		f_sbcap_tx_write_replace_warn_resp(msg, idx);
		}
	[] SBC_AP[idx].receive {
		setverdict(fail, "Received unexpected SBc-AP in index ", idx);
		}
	}
}

/* handle a SBc-AP Stop-Warning-Request and respond to it with Response or FAILURE depending on arguments */
function f_sbcap_handle_stop_warn_req(integer idx := 0, CBS_Message msg)
runs on MME_ConnHdlr {
	var template (present) SBC_AP_PDU rx_templ;
	var SBC_AP_RecvFrom rf;

	rx_templ := tr_SBCAP_STOP_WARNING(int2bit(msg.msg_id, 16),
					  int2bit(msg.ser_nr, 16));
	alt {
	[] SBC_AP[idx].receive(tr_SBC_AP_Recv(g_SBC_AP_conn_id[idx], rx_templ)) -> value rf {
		log ("received expected req:", rf);
		f_sbcap_tx_stop_warn_resp(idx, msg);
		}
	[] SBC_AP[idx].receive {
		setverdict(fail, "Received unexpected SBc-AP in index ", idx);
		}
	}
}

}
