/*****************************************************************
 ** @author   STF 433
 ** @version  0.0.1
 ** @purpose  1:22.3.2, Ensure that the getcall operation can be correctly restricted to a certain client
 ** @verdict  pass accept, ttcn3verdict:pass
 *****************************************************************/

module Sem_220302_GetcallOperation_004 {

    type charstring address;
    const address c_client1Addr := "client1Addr";
    const address c_client2Addr := "client2Addr";

    /**
    * @desc testing of inline return template for remote procedure call
    * @param p_par1 only input parameter
    * @param p_par2 must have value 4 at return
    * @param p_par3 must have value 5 at return
    * @return must return value 1
    */
    signature p_Sem_220302_GetcallOperation_004(in integer p_par1, out integer p_par2, inout integer p_par3) return integer;


    template p_Sem_220302_GetcallOperation_004 s_returnTemplate := {
        p_par1 := -,
        p_par2 := 4,
        p_par3 := 5
    }

    template p_Sem_220302_GetcallOperation_004 s_wrongTemplate := {
        p_par1 := -,
        p_par2 := 2,
        p_par3 := 3
    }

    template p_Sem_220302_GetcallOperation_004 s_callTemplate := {
        p_par1 := 1,
        p_par2 := -,
        p_par3 := 3
    }

    type port remotePort procedure {
        inout p_Sem_220302_GetcallOperation_004;
    }

    type component GeneralComp {
        port remotePort PCO;
        var GeneralComp v_myAddress;
    }

    function f_ClientQuery(GeneralComp p_myAddress) runs on GeneralComp {
        var integer v_zero:=0;
        var integer v_one:=1;
        var boolean first:=true;
		v_myAddress := p_myAddress;

        PCO.call(p_Sem_220302_GetcallOperation_004:s_callTemplate, 3.0) {

            [first] PCO.getreply(p_Sem_220302_GetcallOperation_004:s_returnTemplate value 1) {
                first:=false;
                setverdict(fail);  //receiving a reply is not expected for client2 query
            }
            [] PCO.catch (timeout) {
                setverdict(pass);
            }
        }
    }

    function f_ServerResponses(GeneralComp p_clientAddress) runs on GeneralComp {
        var GeneralComp v_clientAddress;
        var integer v_par1;
        var integer v_par3;
        timer t_timeout:=30.0;

        template p_Sem_220302_GetcallOperation_004 s_acceptTemplate := {
            p_par1 := ?,
            p_par2 := ?,
            p_par3 := ?
        };


        t_timeout.start;

     alt {
      [] PCO.getcall(p_Sem_220302_GetcallOperation_004:s_acceptTemplate) from p_clientAddress -> param(v_par1, - , v_par3) sender v_clientAddress {
          PCO.reply(p_Sem_220302_GetcallOperation_004:{p_par1 := -, p_par2 := v_par1+v_par3, p_par3 := v_par1+v_par3+1} value v_par1) to v_clientAddress;  	//procedure return values are sent
		  repeat;
	  }
      [] t_timeout.timeout {
        setverdict(fail);
      }
     }

    }


    function f_setAddress(GeneralComp p_myAddress) runs on GeneralComp {
        v_myAddress := p_myAddress;
    }

    testcase TC_Sem_220302_GetcallOperation_004() runs on GeneralComp system GeneralComp {
        var GeneralComp server := GeneralComp.create("RemoteProcedure Service");
        var GeneralComp client := GeneralComp.create("RemoteProcedure Client");
        var GeneralComp client2 := GeneralComp.create("RemoteProcedure Client");
        // map the PTCs to the system port
        connect(server:PCO, client:PCO);
        connect(server:PCO, client2:PCO);

       server.start(f_ServerResponses(client));
       client.start(f_setAddress(client));
       client2.start(f_ClientQuery(client));

        interleave {
            [] client.done {}
            [] client2.done {}
        }
        server.stop;

        all component.done;

        disconnect(server:PCO);
    }

    control{
        execute(TC_Sem_220302_GetcallOperation_004());
    }

}