module BSSGP_Emulation {
	import from NS_Types all;
	import from NS_Emulation all;
	import from BSSGP_Types all;
	import from BSSGP_Helper_Functions all;
	import from IPL4asp_Types all;

	type record BssgpStatusIndication {
		Nsei		nsei,
		BssgpBvci	bvci,
		BvcState	state
	}

	template BssgpStatusIndication t_BssgpStsInd(Nsei nsei, BssgpBvci bvci, BvcState state) := {
		nsei := nsei,
		bvci := bvci,
		state := state
	}

	type enumerated BvcState {
		BVC_S_BLOCKED,
		BVC_S_UNBLOCKED
	};

	/* port from our (internal) point of view */
	type port BSSGP_SP_PT message {
		in	BssgpPdu;
		out	BssgpPdu,
			NsStatusIndication,
			BssgpStatusIndication,
			ASP_Event;
	} with { extension "internal" };

	/* port from the user point of view */
	type port BSSGP_PT message {
		in	ASP_Event,
			NsStatusIndication,
			BssgpStatusIndication,
			BssgpPdu;
		out	BssgpPdu;
	} with { extension "internal" };

	function BssgpStart() runs on BSSGP_CT {
		f_init();
		f_ScanEvents();
	}

	private function f_init() runs on BSSGP_CT {
		/* Connect the UDP socket */
		f_change_state(BVC_S_BLOCKED);
	}

	type component BSSGP_CT {
		/* UDP port towards the bottom (IUT) */
		port NS_PT BSCP;
		/* NS-User SAP towards the user */
		port BSSGP_SP_PT BSSGP_SP;

		var BvcState g_ptp_bvc_state := BVC_S_BLOCKED;
		timer g_T1 := 15.0;
		timer g_T2 := 60.0;
	}

	modulepar {
		Nsvci mp_nsei := 2342;
		Nsvci mp_bvci := 2342;
		BssgpCellId mp_cellid := { ra_id := { lai := { mcc_mnc := '234F04'H, lac := 200}, rac := 0 }, cell_id := 20960 };
	};

	function f_BnsUdReq(template BssgpPdu pdu) return NsUnitdataRequest {
		var NsUnitdataRequest udr := {
			bvci := mp_bvci,
			nsei := mp_nsei,
			/* for some weird reason we get "Dynamic test case error: Text encoder: Encoding an
			 * unbound integer value." when trying to send the reocrd rather than the octetstring */
			//sdu := omit,
			//bssgp := valueof(pdu)
			sdu := f_BSSGP_compact_len(enc_BssgpPdu(valueof(pdu))),
			bssgp := omit
		}
		return udr;
	}

	function f_BnsUdInd(template BssgpPdu pdu) return template NsUnitdataIndication {
		var template NsUnitdataIndication udi := {
			bvci := mp_bvci,
			nsei := mp_nsei,
			sdu := *,
			bssgp := pdu
		}
		return udi;
	}

	private function f_change_state(BvcState new_state) runs on BSSGP_CT {
		log("BSSGP State Transition: ", g_ptp_bvc_state, " -> ", new_state);
		g_ptp_bvc_state := new_state;
		BSSGP_SP.send(t_BssgpStsInd(mp_nsei, mp_bvci, g_ptp_bvc_state));
	}

	private function f_sendReset() runs on BSSGP_CT {
		var BssgpPdu pdu := valueof(t_BVC_RESET(BSSGP_CAUSE_OM_INTERVENTION, mp_bvci, mp_cellid));
		log("PDU: ", pdu);
		log("ENC: ", enc_BssgpPdu(pdu));

		BSCP.send(f_BnsUdReq(pdu));
		g_T2.start;
		//f_change_state(BVC_S_WAIT_RESET);
	}

	private function f_sendUnblock() runs on BSSGP_CT {
		BSCP.send(f_BnsUdReq(t_BVC_UNBLOCK(mp_bvci)));
		g_T1.start;
	}

	private function f_sendBlock(BssgpCause cause) runs on BSSGP_CT {
		BSCP.send(f_BnsUdReq(t_BVC_BLOCK(mp_bvci, cause)));
		g_T1.start;
	}

	altstep as_allstate() runs on BSSGP_CT {
		var NsUnitdataIndication udi;
		var NsStatusIndication nsi;
		var ASP_Event evt;

		/* Respond to BLOCK for wrong NSVCI */
		[] BSCP.receive(f_BnsUdInd(t_BVC_BLOCK(?, ?))) -> value udi {
			log("Rx BVC-BLOCK for unknown BVCI");
			/* FIXME */
		}

		/* Respond to RESET with correct NSEI/NSVCI */
		[] BSCP.receive(f_BnsUdInd(t_BVC_RESET(?, mp_bvci, mp_cellid))) -> value udi {
			f_change_state(BVC_S_UNBLOCKED);
			BSCP.send(f_BnsUdReq(t_BVC_RESET_ACK(mp_bvci, mp_cellid)));
		}

		/* Respond to RESET with wrong NSEI/NSVCI */
		[] BSCP.receive(f_BnsUdInd(t_BVC_RESET(?, ?, ?))) -> value udi {
			log("Rx BVC-RESET for unknown BVCI");
			/* FIXME */
		}

		/* default case of handling unknown PDUs */
		[] BSCP.receive(f_BnsUdInd(?)) -> value udi {
			log("Rx Unexpected BSSGP PDU ", udi.bssgp," in state ", g_ptp_bvc_state);
			BSCP.send(f_BnsUdReq(t_BSSGP_STATUS({
						t_BSSGP_IE_Cause(BSSGP_CAUSE_PDU_NOT_COMPATIBLE_WITH_PROTOCOL_STATE),
						t_BSSGP_IE_Bvci(mp_bvci), t_BSSGP_IE_PDU(udi.bssgp)})));
		}
		/* Forwarding of ASP_Event and NsStatusIndication to user */
		[] BSCP.receive(ASP_Event:?) -> value evt { BSSGP_SP.send(evt); }
		[] BSCP.receive(NsStatusIndication:?) -> value nsi { 
			/* if we just became NS-unblocked, send a BCC-RESET */
			if (nsi.old_state != NSE_S_ALIVE_UNBLOCKED and nsi.new_state == NSE_S_ALIVE_UNBLOCKED) {
				f_sendReset();
			}
			BSSGP_SP.send(nsi);
		}
	}

	private function f_ScanEvents() runs on BSSGP_CT {
		var NsUnitdataIndication udi;
		var BssgpPdu bs_pdu;
		var default d;

		d := activate(as_allstate());

		while (true) {
		if (g_ptp_bvc_state == BVC_S_BLOCKED) {
			alt {
				[] g_T1.timeout {
					f_sendUnblock();
				}
				[] BSCP.receive(f_BnsUdInd(t_BVC_UNBLOCK_ACK(mp_bvci))) {
					g_T1.stop;
					f_change_state(BVC_S_UNBLOCKED);
				}
			}
		} else if (g_ptp_bvc_state == BVC_S_UNBLOCKED) {
			alt {
				/* bogus unblock, just respond with ACK */
				[] BSCP.receive(f_BnsUdInd(t_BVC_UNBLOCK(mp_bvci))) -> value udi {
					BSCP.send(f_BnsUdReq(t_BVC_UNBLOCK_ACK(mp_bvci)));
				}
				/* Respond to BLOCK with BLOCK-ACK + change state */
				[] BSCP.receive(f_BnsUdInd(t_BVC_BLOCK(mp_bvci, ?))) -> value udi {
					BSCP.send(f_BnsUdReq(t_BVC_BLOCK_ACK(mp_bvci)));
					g_T1.stop;
					f_change_state(BVC_S_BLOCKED);
				}
				[] g_T1.timeout {
					f_sendBlock(BSSGP_CAUSE_OM_INTERVENTION);
				}
				[] BSCP.receive(f_BnsUdInd(t_BVC_BLOCK_ACK(mp_bvci))) -> value udi {
					g_T1.stop;
					f_change_state(BVC_S_BLOCKED);
				}
				[] BSCP.receive(f_BnsUdInd(t_BVC_RESET_ACK(mp_bvci, mp_cellid))) -> value udi {
					g_T2.stop;
					f_change_state(BVC_S_UNBLOCKED);
				}
				/* BSSGP-UNITDATA PDUs from network to NS-UNITDATA.ind to user */
				[] BSCP.receive(f_BnsUdInd(tr_BSSGP_type(DL_UNITDATA))) -> value udi {
					BSSGP_SP.send(udi.bssgp);
				}
				[] BSCP.receive(f_BnsUdInd(tr_BSSGP_type(UL_UNITDATA))) -> value udi {
					BSSGP_SP.send(udi.bssgp);
				}
				/* pass virtually any PDU from user to NS-UNITDATA PDU on network */
				[] BSSGP_SP.receive(BssgpPdu:?) -> value bs_pdu {
					BSCP.send(f_BnsUdReq(bs_pdu));
				}

			}
		}

		} /* while */
		//deactivate(d);
	}
}
