/**
 *    @author   ETSI / 
 *    @version  $URL$
 *              $Id$
 *    @desc     This module provides functions used in NGAP.
 *    @copyright   ETSI Copyright Notification
 *                 No part may be reproduced except as authorized by written permission.
 *                 The copyright and the foregoing restriction extend to reproduction in all media.
 *                 All rights reserved.
 *    @see      ETSI TS  / 3GPP TS
 */
module LibNGAP_Steps {

    // LibCommon
    import from LibCommon_Sync all;
    import from LibCommon_VerdictControl all;
    import from LibCommon_BasicTypesAndValues all;

    // LibNGAP
    import from NGAP_CommonDataTypes language "ASN.1:1997" all;
    import from NGAP_PDU_Descriptions language "ASN.1:1997" all;
    import from NGAP_IEs language "ASN.1:1997" all;

    import from LibNGAP_TypesAndValues all;
    import from LibNGAP_Interface all;
    import from LibNGAP_Pixits all;
    import from LibNGAP_Templates all;

    /**
     * @desc Common functions description
     */
    group commonFunctions {

    } // End of group commonFunctions

    /**
     * @desc Receive functions description
     */
    group receivePDU {

        /**
         *  @desc    This is a test step that assign common NGAP
         *  @param   p_PDU Extract the message payload from the NGAP PDU
         */
        function f_NGAPPDU_Get(
                               inout NGAP_PDU p_PDU
        ) runs on NGAPComponent {

            vc_recvNGAP_PDU := p_PDU;

            if (ischosen(p_PDU.initiatingMessage)) {
                // Nothing to do
            }
            if (ischosen(p_PDU.successfulOutcome)) {
                // Nothing to do
            }
            if (ischosen(p_PDU.unsuccessfulOutcome)) {
                 // Nothing to do
            }
        } // End of function f_NGAPPDU_Get

        /**
         * @desc Receive NGAP PDU from protocol port
         * @param p_PDU template of the message to be received
         */
        function f_recv_NGAP_PDU(
                                 in template NGAP_PDU p_PDU
        ) runs on NGAPComponent {
            var NGAP_PDU v_PDU;

            log(">>> f_recv_NGAP_PDU", p_PDU);
            tc_wait.start;
            alt {
                [] N2_gNBaMF_P.receive(p_PDU) -> value v_PDU {
                    log("f_recv_NGAP_PDU: Got it", v_PDU);
                    tc_wait.stop;
                    f_NGAPPDU_Get(v_PDU)
                }
                [] tc_wait.timeout {
                    setverdict(inconc,"*** " & __SCOPE__ & ": INCONC: Message was not received in due time. ***");
                    //Stop the component in case of timeout
                    all timer.stop;
                    f_componentStop();
                }
            }

        } // End of function f_recv_NGAP_PDU

        /**
         * @desc Receive NGAP PDU with InitiatingMessage payload from protocol port
         * @param p_initiatingMessage Receive template for InitiatingMessage message
         */
        function f_recv_NGAP_initiatingMessage(
                                               template (present) InitiatingMessage p_initiatingMessage := ?
        ) runs on NGAPComponent {
            f_recv_NGAP_PDU( { initiatingMessage := p_initiatingMessage })
        } // End of function f_recv_NGAP_initiatingMessage

        /**
         * @desc Receive NGAP PDU with SuccessfulOutcome payload from protocol port
         * @param p_successfulOutcome Receive template for SuccessfulOutcome message
         */
        function f_recv_NGAP_successfulOutcome(
                                               template (present) SuccessfulOutcome p_successfulOutcome := ?
        ) runs on NGAPComponent {
            f_recv_NGAP_PDU( {successfulOutcome := p_successfulOutcome})
        } // End of f_recv_NGAP_successfulOutcome

        /**
         * @desc Receive NGAP PDU with UnsuccessfulOutcome payload from protocol port
         * @param p_unsuccessfulOutcome Receive template for UnsuccessfulOutcome message
         */
        function f_recv_NGAP_unsuccessfulOutcome(
                                                 template (present) UnsuccessfulOutcome p_unsuccessfulOutcome := ?
        ) runs on NGAPComponent {
            f_recv_NGAP_PDU( {unsuccessfulOutcome := p_unsuccessfulOutcome})
        } // End of function f_recv_NGAP_unsuccessfulOutcome


    } // End of group receivePDU

    /**
     * @desc Send functions description
     */
    group sendPDU {

        /**
         *  @desc    This is a test step that assign common NGAP
         *  @param p_PDU The NGAP protocol message to set up
         */
        function f_NGAPPDU_Set(
                               inout template (value) NGAP_PDU p_PDU
        ) runs on NGAPComponent {

            if (ischosen(p_PDU.initiatingMessage)) {
                vc_sendNGAP_PDU:=valueof(p_PDU);
            }
            if (ischosen(p_PDU.successfulOutcome)) {
                vc_sendNGAP_PDU:=valueof(p_PDU);
            }
            if (ischosen(p_PDU.unsuccessfulOutcome)) {
                 vc_sendNGAP_PDU:=valueof(p_PDU);
            }

        } // End of function f_NGAPPDU_Set

        /**
         * @desc Send NGAP PDU to protocol port
         * @param p_PDU template value message to be send
         */
        function f_send_NGAP_PDU(
                                 in template (value) NGAP_PDU p_PDU
        ) runs on NGAPComponent {
            log(">>> f_send_NGAP_PDU: ", p_PDU)
            f_NGAPPDU_Set(p_PDU);
            log("f_send_NGAP_PDU: vc_sendNGAP_PDU: ", vc_sendNGAP_PDU)
            N2_gNBaMF_P.send(p_PDU);
        } // End of function f_send_NGAPPDU

        /**
         * @desc Send NGAP PDU with InitiatingMessage payload from protocol port
         * @param p_initiatingMessage Send value template for InitiatingMessage message
         */
        function f_send_NGAP_initiatingMessage(
                                               in template (value) InitiatingMessage p_initiatingMessage,
                                               in template (value) Criticality p_criticality := reject
        ) runs on NGAPComponent {
            f_send_NGAP_PDU( {initiatingMessage := p_initiatingMessage})
        } // End of function f_send_NGAP_initiatingMessage

        /**
         * @desc Send NGAP PDU with SuccessfulOutcome payload from protocol port
         * @param p_successfulOutcome Send value template for SuccessfulOutcome message
         */
        function f_send_NGAP_successfulOutcome(
                                               in template (value) SuccessfulOutcome p_successfulOutcome
        ) runs on NGAPComponent {
            f_send_NGAP_PDU( {successfulOutcome := p_successfulOutcome})
        } // End of function f_send_NGAP_successfulOutcome

        /**
         * @desc Send NGAP PDU with UnsuccessfulOutcome payload from protocol port
         * @param p_unsuccessfulOutcome Send value template for UnsuccessfulOutcome message
         */
        function f_send_NGAP_unsuccessfulOutcome(
                                                 in template (value) UnsuccessfulOutcome p_unsuccessfulOutcome
        ) runs on NGAPComponent {
            f_send_NGAP_PDU( {unsuccessfulOutcome := p_unsuccessfulOutcome})
        } // End of function f_send_NGAP_unsuccessfulOutcome 

    } // End of group sendPDU

    /**
     * @desc Setup full procedure functions
     * @see ETSI TS 
     */
    group fullProcedures {
    } // End of group fullProcedures

    group externalFunctions {
    } // End of group externalFunctions

    group preambles {

        group preamble_NGAP{

            /**
             * @desc 
             * @verdict 
             */
            function f_preambleNGAP_MME()
            runs on NGAPComponent {
                // Nothing to do
            } // End of function f_preambleNGAP_MME

            /**
             * @desc 
             * @verdict 
             */
            function f_preambleNGAP_eNB()
            runs on NGAPComponent {
                // Nothing to do
            } // End of function f_preambleNGAP_eNB

        } // End of group preamble_NGAP

    } // End of group preambles

    group postambles {

        group postamble_NGAP{

            /**
             * @desc 
             * @verdict 
             */
            function f_postambleNGAP_gNB()
            runs on NGAPComponent {
                // Nothing to do
            } // End of function f_postambleNGAP_gNB

            /**
             * @desc 
             * @verdict 
             */
            function f_postambleNGAP_AMF()
            runs on NGAPComponent {
                // Nothing to do
            } // End of function f_postambleNGAP_AMF

        } // End of group postamble_NGAP

    } // End of group postambles

    /**
     * @desc Global 'altstep' statements description
     */
    group globalSteps {

        /**
         *  @desc    This is a test step that init NGAP component
         */
        function f_NGAP_Init_Component()
        runs on NGAPComponent {
            // Nothing to do
        } // End of function  f_NGAP_Init_Component

        /**
         * @desc Component termination
         */
        function f_NGAP_terminate_component()
        runs on NGAPComponent {

            log("component terminated - forced!");
            deactivate;
            stop;
        } // End of function f_NGAP_terminate_component

        /**
         * @desc Component termination
         */
        function f_componentStop()
        runs on NGAPComponent {

            syncPort.send(m_syncClientStop);
            N2_gNBaMF_P.clear;
            stop;
        } // End of function f_componentStop

        /**
         * @desc Original copied from older LibCommon_VerdictControl
         */
        function f_getVerdict() // FIXME Are you sure we really need it???
        return FncRetCode {

            var FncRetCode v_ret := e_error;
            if (getverdict == pass or getverdict == none) {
                v_ret := e_success;
            }
            return v_ret;
        } // End of function 

    } // End of group globalSteps

    /**
     * @desc Default 'altstep' statements description
     */
    group defaultsTestStep {

        /**
         * @desc 
         * @verdict 
         */
        altstep a_defaultNGAP()
        runs on NGAPComponent {
            [] any timer.timeout {
                all timer.stop;
                if (vc_serverStop==false) {
                    f_selfOrClientSyncAndVerdict("error", e_timeout);
                }
                else {
                    stop;
                }
            }
            [] N2_gNBaMF_P.receive (NGAP_PDU:{initiatingMessage := ?}) -> value vc_recvNGAP_PDUDefault {
                repeat;
            }
            [] N2_gNBaMF_P.receive (NGAP_PDU:{successfulOutcome := ?}) -> value vc_recvNGAP_PDUDefault {
                repeat;
            }
            [] N2_gNBaMF_P.receive (NGAP_PDU:{unsuccessfulOutcome := ?}) -> value vc_recvNGAP_PDUDefault {
                repeat;
            }
            [] N2_gNBaMF_P.receive (NGAP_PDU:?) -> value vc_recvNGAP_PDUDefault {
                if (vc_serverStop==false) {
                    f_selfOrClientSyncAndVerdict("error", e_error);
                }
                else {
                    stop;
                }
            }
            [] N2_gNBaMF_P.receive {
                if (vc_serverStop==false) {
                    f_selfOrClientSyncAndVerdict("error", e_error);
                }
                else {
                    stop;
                }
            }
            [] a_shutdown() {
                // Process temination on error
                log("*** a_defaultNGAP() : Process temination on error ***");
                // Terminate component execution
                stop;
            }
        } // End of altstep a_defaultNGAP

        altstep a_defaultNGAP_MME()
        runs on NGAPComponent {
            [] any timer.timeout {
                all timer.stop;
                if (vc_serverStop==false) {
                    f_selfOrClientSyncAndVerdict("error", e_timeout);
                }
                else {
                    stop;
                }
            }
            // Note: possible unscollicited messages should be filtered
        } // End of altstep a_defaultNGAP_MME

        altstep a_defaultNGAP_eNB()
        runs on NGAPComponent {
            [] any timer.timeout {
                all timer.stop;
                if (vc_serverStop==false) {
                    f_selfOrClientSyncAndVerdict("error", e_timeout);
                }
                else {
                    stop;
                }
            }
            // Note: possible unscollicited messages should be filtered
        } // End of altstep a_defaultNGAP_eNB

    } // End of group defaultsTestStep

} // End of module LibNGAP_Steps
