module NGAP_Functions {

/* (C) 2019 by Harald Welte <laforge@gnumonks.org>
 * (C) 2025 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
 * All rights reserved.
 *
 * 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
 */

import from NGAP_IEs all;
import from NGAP_Types all;
import from NGAP_Constants all;
import from NGAP_PDU_Contents all;
import from NGAP_PDU_Descriptions all;
import from NGAP_Templates all;

function f_NGAP_get_AMF_UE_NGAP_ID(NGAP_PDU ngap) return template (omit) AMF_UE_NGAP_ID
{
	if (ischosen(ngap.initiatingMessage)) {
		var InitiatingMessage im := ngap.initiatingMessage;
		select (im.procedureCode) {
		case (id_DownlinkNASTransport) {
			return im.value_.downlinkNASTransport.protocolIEs[0].value_.aMF_UE_NGAP_ID;
			}
		case (id_InitialContextSetup) {
			return im.value_.initialContextSetupRequest.protocolIEs[0].value_.aMF_UE_NGAP_ID;
			}
		case (id_UEContextRelease) {
			return im.value_.uEContextReleaseCommand.protocolIEs[0].value_.uE_NGAP_IDs.uE_NGAP_ID_pair.aMF_UE_NGAP_ID;
			}
		case (id_PDUSessionResourceSetup) {
			return im.value_.pDUSessionResourceSetupRequest.protocolIEs[0].value_.aMF_UE_NGAP_ID;
			}
		case (id_PDUSessionResourceModify) {
			return im.value_.pDUSessionResourceModifyRequest.protocolIEs[0].value_.aMF_UE_NGAP_ID;
			}
		case (id_PDUSessionResourceRelease) {
			return im.value_.pDUSessionResourceReleaseCommand.protocolIEs[0].value_.aMF_UE_NGAP_ID;
			}
		case (id_HandoverResourceAllocation) {
			return im.value_.handoverRequest.protocolIEs[0].value_.aMF_UE_NGAP_ID;
			}
		case (id_HandoverNotification) {
			return im.value_.HandoverNotify.protocolIEs[0].value_.aMF_UE_NGAP_ID;
			}
		case (id_HandoverCancel) {
			return im.value_.HandoverCancel.protocolIEs[0].value_.aMF_UE_NGAP_ID;
			}
		/* TODO */
		}
	} else if (ischosen(ngap.successfulOutcome)) {
		var SuccessfulOutcome so := ngap.successfulOutcome;
		select (so.procedureCode) {
		case (id_PathSwitchRequest) {
			return so.value_.PathSwitchRequestAcknowledge.protocolIEs[0].value_.aMF_UE_NGAP_ID;
			}
		case (id_HandoverResourceAllocation) {
			return so.value_.HandoverRequestAcknowledge.protocolIEs[0].value_.aMF_UE_NGAP_ID;
			}
		case (id_HandoverPreparation) {
			return so.value_.HandoverCommand.protocolIEs[0].value_.aMF_UE_NGAP_ID;
			}
		case (id_HandoverCancel) {
			return so.value_.HandoverCancelAcknowledge.protocolIEs[0].value_.aMF_UE_NGAP_ID;
			}
		case (?) {
			return omit;
			/* TODO */
			}
		/* TODO */
		}
	} else if (ischosen(ngap.unsuccessfulOutcome)) {
		var UnsuccessfulOutcome uo := ngap.unsuccessfulOutcome;
		select (uo.procedureCode) {
		case (?) {
			return omit;
			/* TODO */
			/* return im.value_.UnsuccessfulOutcome.protocolIEs[0].value_.AMF_UE_NGAP_ID; */
			}
		/* TODO */
		}
	}
	return omit;
}

function f_NGAP_get_RAN_UE_NGAP_ID(NGAP_PDU ngap) return template (omit) RAN_UE_NGAP_ID
{
	if (ischosen(ngap.initiatingMessage)) {
		var InitiatingMessage im := ngap.initiatingMessage;
		select (im.procedureCode) {
		case (id_InitialUEMessage) {
			return im.value_.InitialUEMessage.protocolIEs[0].value_.RAN_UE_NGAP_ID;
			}
		case (id_DownlinkNASTransport) {
			return im.value_.downlinkNASTransport.protocolIEs[1].value_.RAN_UE_NGAP_ID;
			}
		case (id_InitialContextSetup) {
			return im.value_.initialContextSetupRequest.protocolIEs[1].value_.RAN_UE_NGAP_ID;
			}
		case (id_UEContextRelease) {
			return im.value_.uEContextReleaseCommand.protocolIEs[0].value_.uE_NGAP_IDs.uE_NGAP_ID_pair.rAN_UE_NGAP_ID;
			}
		case (id_PDUSessionResourceSetup) {
			return im.value_.pDUSessionResourceSetupRequest.protocolIEs[1].value_.RAN_UE_NGAP_ID;
			}
		case (id_PDUSessionResourceModify) {
			return im.value_.pDUSessionResourceModifyRequest.protocolIEs[1].value_.RAN_UE_NGAP_ID;
			}
		case (id_PDUSessionResourceRelease) {
			return im.value_.pDUSessionResourceReleaseCommand.protocolIEs[1].value_.rAN_UE_NGAP_ID;
			}
		case (id_PathSwitchRequest) {
			return im.value_.PathSwitchRequest.protocolIEs[0].value_.RAN_UE_NGAP_ID;
			}
		case (id_HandoverNotification) {
			return im.value_.HandoverNotify.protocolIEs[1].value_.RAN_UE_NGAP_ID;
			}
		case (id_HandoverCancel) {
			return im.value_.HandoverCancel.protocolIEs[1].value_.RAN_UE_NGAP_ID;
			}
		/* TODO */
		}
	} else if (ischosen(ngap.successfulOutcome)) {
		var SuccessfulOutcome so := ngap.successfulOutcome;
		select (so.procedureCode) {
		case (id_PathSwitchRequest) {
			return so.value_.PathSwitchRequestAcknowledge.protocolIEs[1].value_.rAN_UE_NGAP_ID;
			}
		case (id_HandoverResourceAllocation) {
			return so.value_.HandoverRequestAcknowledge.protocolIEs[1].value_.rAN_UE_NGAP_ID;
			}
		case (id_HandoverPreparation) {
			return so.value_.HandoverCommand.protocolIEs[1].value_.rAN_UE_NGAP_ID;
			}
		case (id_HandoverCancel) {
			return so.value_.HandoverCancelAcknowledge.protocolIEs[1].value_.rAN_UE_NGAP_ID;
			}
		case (?) {
			return omit;
			/* TODO */
			/* return im.value_.SuccessfulOutcome.protocolIEs[0].value_.RAN_UE_NGAP_ID; */
			}
		/* TODO */
		}
	} else if (ischosen(ngap.unsuccessfulOutcome)) {
		var UnsuccessfulOutcome uo := ngap.unsuccessfulOutcome;
		select (uo.procedureCode) {
		case (?) {
			return omit;
			/* TODO */
			/* return im.value_.UnsuccessfulOutcome.protocolIEs[0].value_.RAN_UE_NGAP_ID; */
			}
		/* TODO */
		}
	}
	return omit;
}

function f_NGAP_get_NAS_PDU(NGAP_PDU ngap) return template (omit) NAS_PDU
{
	var integer i, j;

	if (ischosen(ngap.initiatingMessage)) {
		var InitiatingMessage im := ngap.initiatingMessage;
		select (im.procedureCode) {
		case (id_DownlinkNASTransport) {
			var DownlinkNASTransport msg := im.value_.DownlinkNASTransport;
			for (i := 0; i < lengthof(msg.protocolIEs); i := i+1) {
				if (msg.protocolIEs[i].id == id_NAS_PDU) {
					return msg.protocolIEs[i].value_.NAS_PDU;
				}
			}
			}
		case (id_UplinkNASTransport) {
			var UplinkNASTransport msg := im.value_.UplinkNASTransport;
			for (i := 0; i < lengthof(msg.protocolIEs); i := i+1) {
				if (msg.protocolIEs[i].id == id_NAS_PDU) {
					return msg.protocolIEs[i].value_.NAS_PDU;
				}
			}
			}
		case (id_InitialUEMessage) {
			var InitialUEMessage msg := im.value_.InitialUEMessage;
			for (i := 0; i < lengthof(msg.protocolIEs); i := i+1) {
				if (msg.protocolIEs[i].id == id_NAS_PDU) {
					return msg.protocolIEs[i].value_.NAS_PDU;
				}
			}
			return omit;
		}
		case (id_InitialContextSetup) {
			var InitialContextSetupRequest msg := im.value_.initialContextSetupRequest;
			for (i := 0; i < lengthof(msg.protocolIEs); i := i+1) {
				if (msg.protocolIEs[i].id == id_NAS_PDU) {
					return msg.protocolIEs[i].value_.NAS_PDU;
				}
			}
			for (i := 0; i < lengthof(msg.protocolIEs); i := i+1) {
				if (msg.protocolIEs[i].id == id_PDUSessionResourceSetupListCxtReq) {
					var PDUSessionResourceSetupListCxtReq req_li := msg.protocolIEs[i].value_.pDUSessionResourceSetupListCxtReq;
					for (j := 0; j < lengthof(req_li); j := j+1) {
						if (ispresent(req_li[j].nAS_PDU)) {
							return req_li[j].nAS_PDU;
						}
						/* FIXME: we should be returning req_li[j].pDUSessionResourceSetupRequestTransfer too... */
					}
				}
			}
			return omit;
		}
		case (id_PDUSessionResourceSetup) {
			var PDUSessionResourceSetupRequest msg := im.value_.pDUSessionResourceSetupRequest;
			for (i := 0; i < lengthof(msg.protocolIEs); i := i+1) {
				if (msg.protocolIEs[i].id == id_NAS_PDU) {
					return msg.protocolIEs[i].value_.NAS_PDU;
				}
			}
			return omit;
		}
		case (id_PDUSessionResourceModify) {
			var PDUSessionResourceModifyRequest msg := im.value_.pDUSessionResourceModifyRequest;
			for (i := 0; i < lengthof(msg.protocolIEs); i := i+1) {
				if (msg.protocolIEs[i].id == id_PDUSessionResourceModifyListModReq) {
					var PDUSessionResourceModifyListModReq req_li := msg.protocolIEs[i].value_.pDUSessionResourceModifyListModReq;
					for (j := 0; j < lengthof(req_li); j := j+1) {
						return req_li[j].nAS_PDU;
						/* FIXME: we should be returning req_li[j].pDUSessionResourceModifyRequestTransfer too... */
					}
				}
			}
			return omit;
		}
		case (id_PDUSessionResourceRelease) {
			var PDUSessionResourceReleaseCommand msg := im.value_.PDUSessionResourceReleaseCommand;
			for (i := 0; i < lengthof(msg.protocolIEs); i := i+1) {
				if (msg.protocolIEs[i].id == id_NAS_PDU) {
					return msg.protocolIEs[i].value_.NAS_PDU;
				}
			}
			return omit;
		}
		}
	}
	return omit;
}

}
