/******************************************************************************
 * Copyright (c) ETSI 2017.
 *
 * This file is subject to copyrights owned by ETSI. Non-exclusive permission
 * is hereby granted, free of charge, to copy, reproduce and amend this file
 * under the following conditions: It is provided "as is", without warranty of any
 * kind, expressed or implied.
 * 
 * ETSI shall never be liable for any claim, damages, or other liability arising
 * from its use or inability of use.This permission does not apply to any documentation
 * associated with this file for which ETSI keeps all rights reserved. The present
 * copyright notice shall be included in all copies of whole or part of this
 * file and shall not imply any sub-license right.
 *
 * Modified by: Adrien Kirjak
 *
 ** @version  0.0.1
 ** @purpose  1:22.3.1, Ensure that the IUT correctly handles broadcast/multicast procedure call 
 ** @verdict  pass accept, ttcn3verdict:pass
 *****************************************************************/

module Sem_220301_CallOperation_006 {

    type charstring address;
    const address c_server1Addr := "server1Addr";
    const address c_server2Addr := "server2Addr";

    /**
    * @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_220301_CallOperation_006(in integer p_par1, out integer p_par2, inout integer p_par3) return integer;

    template p_Sem_220301_CallOperation_006 s_returnTemplate := {
        p_par1 := 0, // p_par1 := -, core dump
        p_par2 := 4, 
        p_par3 := 5
    }

    template p_Sem_220301_CallOperation_006 s_wrongTemplate := {
        p_par1 := 0, // p_par1 := -, core dump
        p_par2 := 2,
        p_par3 := 3
    }

    template p_Sem_220301_CallOperation_006 s_callTemplate := {
        p_par1 := 1,
        p_par2 := 0, // p_par2 := -, core dump
        p_par3 := 3
    }

    type port remotePort procedure {
        inout p_Sem_220301_CallOperation_006;
    } with {extension "internal"}

    type component GeneralComp {
        port remotePort PCO;
    }

    function f_ClientQuery() runs on GeneralComp {
        var integer v_zero:=0;
        var integer v_one:=1;
        timer t_timer:=5.0;
 
        //  validate broadcast calling
        PCO.call(p_Sem_220301_CallOperation_006:s_callTemplate, nowait) to all component;
        t_timer.start;
        
        alt {
            //check that we get a reply from first server
            [] PCO.getreply(p_Sem_220301_CallOperation_006:s_returnTemplate value 1) from c_server1Addr {
                alt {
                    //check that we get a reply from second server
                    [] PCO.getreply(p_Sem_220301_CallOperation_006:s_returnTemplate value 1) from c_server2Addr {
                        setverdict(pass);
                    }
                    [] t_timer.timeout {
                        setverdict(fail);
                    }
                }
            }
            [] t_timer.timeout {
                setverdict(fail);
            }
        }
    }
    
    template p_Sem_220301_CallOperation_006 s_acceptTemplate := {
        p_par1 := ?,
        p_par2 := ?,
        p_par3 := ?
    };

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

        t_timeout.start;

        alt {
            [] PCO.getcall(p_Sem_220301_CallOperation_006:s_acceptTemplate) -> param(v_par1, v_par3) sender v_clientAddress {
                PCO.reply(p_Sem_220301_CallOperation_006:{p_par1 := 0, p_par2 := v_par1+v_par3, p_par3 := v_par1+v_par3+1} value v_par1) to v_clientAddress; // p_par1 := -, core dump
                repeat;
            }
            [] t_timeout.timeout {
                setverdict(fail);
            }
        }
  
    }

    testcase TC_Sem_220301_CallOperation_006() runs on GeneralComp system GeneralComp {
        var GeneralComp server := GeneralComp.create("RemoteProcedure Service") alive;
        var GeneralComp server2 := GeneralComp.create("RemoteProcedure Service2") alive;
        var GeneralComp client := GeneralComp.create("RemoteProcedure Client") alive;

        connect(server:PCO, client:PCO);
        connect(server2:PCO, client:PCO);

        // set server address and start operation
        server.start(f_ServerResponses());
        server2.start(f_ServerResponses());
       
        client.start(f_ClientQuery());

        alt {
            [] client.done {
                server.stop;
                server2.stop;
            }
        }

        alt {
            [] all component.done {}
        }

        disconnect(server:PCO, client:PCO);
        disconnect(server2:PCO, client:PCO);
    }

    control{
        execute(TC_Sem_220301_CallOperation_006());
    }

}
