/**
 *  @author   ETSI
 *  @version  $URL$
 *            $Id$
 *  @desc     This module implements _one_ generic synchronization mechanism
 *            for TTCN-3 test cases with one or more test components.
 *            Key concept is here that one test component acts as a
 *            synchronization server which listens and triggers one or more
 *            synchronization clients. It is recomended to use the MTC always as
 *            the synchronization server but in theory also a PTC can act as such
 *            a server.<br><br>
 *            This synchronization is used by calling a function on
 *            the server test component to wait for a desired amount of clients
 *            to notify the server that they have reached a specific synchronization
 *            point. Each client test component must call another
 *            function to perform this notification.<br><br>
 *            In the event that a client is not able to reach a synchronization
 *            point the server sends out a signal to all clients to abort the
 *            test case. This signal is a STOP message which can be caught by
 *            a test component default which in turn can then run a proper
 *            shut down behavior based on the current state of the test
 *            component. <br><br>
 *            Note that this synchronization mechanism can also be used
 *            in a special mode called "self synchronization" when a test case
 *            only has one test component. Here, the test component in essence
 *            acts as a server and client at the same time. The main benefit of
 *            using self synchoronization is that the same shutdown mechanisms
 *            can also be reused fomr the multi component test cases. <br><br>
 *            This module contains a lot of TTCN-3 definitions. It has been
 *            structured into tree main groups to help the user to identify
 *            quickly relevant TTCN-3 definitions. For rookie users of this
 *            module basicUserRelevantDefinitions should offer all the needed
 *            definitions. Advanced users can consider use of definitions in
 *            advancedUserRelevantDefinitions. Finally, internalDefinitions
 *            are definitions which are required for the module to work
 *            properly but do not need to be used in your code. Remember that
 *            the main motiviation of this sychronization module is to offer
 *            are _simple_ user interface. Practice has shown that when writing
 *            actual test component behavior _only a handful_ of functions
 *            usually wind up being used! Also check the synchronization examples
 *            module for example uses of this synchronization mechanism.<br><br>
 *            The invocation of the sync functions is also closely tied
 *            to the verdict control functions which should also be reviewed
 *            prior to using this module. <br><br>
 *            This module has been derived from EtsiCommon_Synchronization
 *            which was created in ETSIs STF256/276. It has been kept
 *            intentionally separate to avoid conflicts with future ETSI
 *            test suite releases.
 *  @see      LibCommon_Sync.basicUserRelevantDefinitions
 *  @see      LibCommon_Sync.advancedUserRelevantDefinitions
 *  @remark   End users should be aware that any changes made to the  in
 *            definitions this module may be overwritten in future releases.
 *            End users are encouraged to contact the distributers of this
 *            module regarding their modifications or additions so that future
 *            updates will include your changes.
 *  @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.
 *
 */
module LibCommon_Sync {

  //Common
  import from LibCommon_BasicTypesAndValues all;
  import from LibCommon_AbstractData all;
  import from LibCommon_VerdictControl all;

  group basicUserRelevantDefinitions {

    group importantSyncTypeDefinitions {

      group compTypeRelated {

        /**
         * @desc  This type is used to be the base of any synchronization
         *        behavior which is to be executed on a sync server
         *        component. The test component which acts as a
         *        sync server in a test case must NOT directly use
         *        this component type in its runs on clause!
         *        Note that server synchronization functions may be
         *        invoked by a test component as long as its
         *        component type is type compatible to this component
         *        type definition!
         */
        type component BaseSyncComp {
          port  SyncPort syncPort;
          timer tc_sync := PX_TSYNC_TIME_LIMIT;
        }

        /**
         * @desc  This type is used to define any synchronization
         *        behavior which is to be executed on a sync server
         *        component. The test component which acts as a
         *        sync server in a test case may  - but does
         *        not have to - directly use this component type its
         *        runs on clause.
         *        Note that server synchronization functions may be
         *        invoked by a test component as long as its
         *        component type is type compatible to this component
         *        type definition!
         */
        type component ServerSyncComp extends BaseSyncComp {
          timer tc_shutDown := PX_TSHUT_DOWN_TIME_LIMIT;
        }

        /**
         * @desc  This type is used to define any synchronization
         *        behavior which is to be executed on a sync client
         *        component. The test component(s) which act as a
         *        sync client in a test case may  - but do not have
         *        to - directly use this component type their runs
         *        on clause.
         *        Note that server synchronization functions may be
         *        invoked by a test component as long as its
         *        component type is type compatible to this component
         *        type definition!
         */
        type component ClientSyncComp extends BaseSyncComp {
          var StringStack v_stateStack:= c_initStringStack;
          var TestcaseStep vc_testcaseStep := e_preamble;
        }

        /**
         * @desc  This type is used to define any synchronization
         *        behavior which is relevant to non-concurrent test
         *        cases.
         *        Note that self synchronization functions may be
         *        invoked by a test component as long as its
         *        component type is type compatible to this component
         *        type definition!
         *        Note also that this type is type compatible to the
         *        ClientSyncComp type so that shutdown altsteps from
         *        concurrent test cases can also be reused in single
         *        component test cases!
         * @see   LibCommon_Sync.ClientSyncComp
         */
        type component SelfSyncComp extends ClientSyncComp {
          port SyncPort syncSendPort;
        }

        /**
         * @desc  This port type must be imported into test suites
         *        when defining test component types which are
         *        type compatible to a synchronization component
         *        type
         * @see   LibCommon_Sync.SelfSyncComp
         * @see   LibCommon_Sync.ServerSyncComp
         * @see   LibCommon_Sync.ClientSyncComp
         */
        type port SyncPort message {
          inout SyncCmd
        } with {
          extension "internal"
        }


        /**
         * @desc Describes in which step of execution is the testcase
         */
        type enumerated TestcaseStep {
            e_preamble,
            e_testBody,
            e_postamble
        }

      } // end compTypeRelated

      group standardSyncPointNames {
        const charstring c_prDone := "preambleDone";
        const charstring c_poDone := "postambleDone";
        const charstring c_tbDone := "testBodyDone";
        const charstring c_initDone := "initDone";
      }

    } // end group importantSyncTypeDefinitions

    group syncCompTestConfiguration {

      /**
       *  @desc   Calls self connect function if invoking
       *         component is the MTC or otherwise connects the client
       *         the server. This function allows to implement preambles
       *         in a way that they can be used by test components
       *         in both non-concurrent as well as concurrent test
       *         cases!
       * @remark This function should _not_ be called if the MTC
       *         acts as a client (and not a server) in a concurrent
       *         test case. In this case f_connect4ClientSync
       *         should be used instead.
       * @see    LibCommon_Sync.f_connect4SelfSync
       * @see    LibCommon_Sync.f_connect4ClientSync
       */
      function f_connect4SelfOrClientSync()
      runs on SelfSyncComp {
        if ( self == mtc ) {
          f_connect4SelfSync();
        } else {
          f_connect4ClientSync();
        }
      }

      /**
       * @desc   Calls self connect function if the invoking
       *         component is the MTC or otherwise disconnects the client
       *         from the server. This function allows to implement
       *         postambles in a way that they can be used in both
       *         non-concurrent as well as concurrent test cases.
       * @remark This function should _not_ be called if the MTC
       *         acts as a client (and not a server) in a concurrent
       *         test case. In this case f_disconnect4ClientSync
       *         should be used instead.
       * @see    LibCommon_Sync.f_disconnect4SelfSync
       * @see    LibCommon_Sync.f_disconnect4ClientSync
       */
      function f_disconnect4SelfOrClientSync()
      runs on SelfSyncComp {
        if ( self == mtc ) {
          f_disconnect4SelfSync();
        } else {
          f_disconnect4ClientSync();
        }
      }

    } // end group syncCompTestConfiguration

    group syncFunctions {

      /**
       * @desc   Implements synchronization of 2 clients from server side
       *         on one or more synchronization points.
       *         If problem occurs, then server sends STOP to all clients.
       *         Waits for PX_TSYNC_TIME_LIMIT to let clients
       *         finish executing their behavior until this
       *         synchronization point. After passing all synchronization
       *         points successfuly the server waits for all clients
       *         to stop.
       *         See f_serverSyncClientsTimed for overwriting this
       *         the timing constraint!
       *         This function sets the server component verdict.
       * @remark The use of this function requires prior connection  of
       *         the server sync ports!
       * @see    LibCommon_Sync.f_connect4SelfOrClientSync
       * @see    LibCommon_Sync.PX_TSYNC_TIME_LIMIT
       * @see    LibCommon_Sync.f_serverSyncClientsTimed
       * @see    LibCommon_Sync.f_serverWaitForAllClientsToStop
       * @param  p_syncPointIds list of synchronization point name/ids
       */
      function f_serverSync2ClientsAndStop( in SyncPointList p_syncPointIds )
      runs on ServerSyncComp {
          f_serverSyncNClientsAndStop(2, p_syncPointIds);
      }

      /**
       * @desc   Implements synchronization of 3 clients from server side
       *         on one or more synchronization points.
       *         If problem occurs, then server sends STOP to all clients.
       *         Waits for PX_TSYNC_TIME_LIMIT to let clients
       *         finish executing their behavior until this
       *         synchronization point. After passing all synchronization
       *         points successfuly the server waits for all clients
       *         to stop.
       *         See f_serverSyncClientsTimed for overwriting this
       *         the timing constraint!
       *         This function sets the server component verdict.
       * @remark The use of this function requires prior connection  of
       *         the server sync ports!
       * @see    LibCommon_Sync.f_connect4SelfOrClientSync
       * @see    LibCommon_Sync.PX_TSYNC_TIME_LIMIT
       * @see    LibCommon_Sync.f_serverSyncClientsTimed
       * @see    LibCommon_Sync.f_serverWaitForAllClientsToStop
       * @param  p_syncPointIds list of synchronization point name/ids
       */
      function f_serverSync3ClientsAndStop( in SyncPointList p_syncPointIds )
      runs on ServerSyncComp {
          f_serverSyncNClientsAndStop(3, p_syncPointIds);
      }

      /**
       * @desc   Implements synchronization of 4 clients from server side
       *         on one or more synchronization points.
       *         If problem occurs, then server sends STOP to all clients.
       *         Waits for PX_TSYNC_TIME_LIMIT to let clients
       *         finish executing their behavior until this
       *         synchronization point. After passing all synchronization
       *         points successfuly the server waits for all clients
       *         to stop.
       *         See f_serverSyncClientsTimed for overwriting this
       *         the timing constraint!
       *         This function sets the server component verdict.
       * @remark The use of this function requires prior connection  of
       *         the server sync ports!
       * @see    LibCommon_Sync.f_connect4SelfOrClientSync
       * @see    LibCommon_Sync.PX_TSYNC_TIME_LIMIT
       * @see    LibCommon_Sync.f_serverSyncClientsTimed
       * @see    LibCommon_Sync.f_serverWaitForAllClientsToStop
       * @param  p_syncPointIds list of synchronization point name/ids
       */
      function f_serverSync4ClientsAndStop( in SyncPointList p_syncPointIds )
      runs on ServerSyncComp {
          f_serverSyncNClientsAndStop(4, p_syncPointIds);
      }

      /**
       * @desc   Implements synchronization of N clients from server side
       *         on one or more synchronization points.
       *         If problem occurs, then server sends STOP to all clients.
       *         Waits for PX_TSYNC_TIME_LIMIT to let clients
       *         finish executing their behavior until this
       *         synchronization point. After passing all synchronization
       *         points successfuly the server waits for all clients
       *         to stop.
       *         See f_serverSyncClientsTimed for overwriting this
       *         the timing constraint!
       *         This function sets the server component verdict.
       * @remark The use of this function requires prior connection  of
       *         the server sync ports!
       * @see    LibCommon_Sync.f_connect4SelfOrClientSync
       * @see    LibCommon_Sync.PX_TSYNC_TIME_LIMIT
       * @see    LibCommon_Sync.f_serverSyncClientsTimed
       * @see    LibCommon_Sync.f_serverWaitForAllClientsToStop
       * @param  p_numClients number of synchronization clients
       * @param  p_syncPointIds list of synchronization point name/ids
       */
      function f_serverSyncNClientsAndStop (
      	in UInt p_numClients,
      	in SyncPointList p_syncPointIds )
      runs on ServerSyncComp {
        var integer i, v_noOfSyncIds := sizeof(p_syncPointIds);
        for ( i := 0; i < v_noOfSyncIds; i := i+1 ) {
          f_serverSyncClientsTimed (
          	p_numClients,
          	valueof(p_syncPointIds[i]),
          	PX_TSYNC_TIME_LIMIT );
        }
        f_serverWaitForAllClientsToStop();
      }

      /**
       * @desc   Implements synchronization of 2 clients and 1 UT from server side
       *         on one or more synchronization points.
       *         If problem occurs, then server sends STOP to all clients.
       *         Waits for PX_TSYNC_TIME_LIMIT to let clients
       *         finish executing their behavior until this
       *         synchronization point. After passing all synchronization
       *         points successfuly the server waits for all clients
       *         to stop.
       *         See f_serverSyncClientsTimed for overwriting this
       *         the timing constraint!
       *         This function sets the server component verdict.
       * @remark The use of this function requires prior connection  of
       *         the server sync ports!
       * @see    LibCommon_Sync.f_connect4SelfOrClientSync
       * @see    LibCommon_Sync.PX_TSYNC_TIME_LIMIT
       * @see    LibCommon_Sync.f_serverSyncClientsTimed
       * @see    LibCommon_Sync.f_serverWaitForAllClientsToStop
       * @param  p_syncPointIds list of synchronization point name/ids
       */
      function f_serverSync2ClientsUtAndStop( in SyncPointList p_syncPointIds )
      runs on ServerSyncComp {
        var integer i, v_noOfSyncIds := sizeof(p_syncPointIds);
        for ( i := 0; i < v_noOfSyncIds; i := i+1 ) {
          f_serverSyncClientsTimed(3,valueof(p_syncPointIds[i]), PX_TSYNC_TIME_LIMIT);
        }
        f_serverWaitForAllClientsToStop();
      }

      /**
       * @desc   Calls either self synchronization function if
       *         invoking component is the MTC, otherwise
       *         calls client synchronization. After that it
       *         sets the verdict based on the specified return code.
       *         This function allows to implement TTCN-3 functions
       *         in a way that they can be used in both non-concurrent
       *         as well as concurrent test cases.
       * @remark This function should _not_ be called if the MTC
       *         acts as a client (and not a server) in a concurrent
       *         test case. In this case f_clientSyncAndVerdict
       *         should be used instead.
       * @param  p_syncPoint Synchronization point name/id
       * @param  p_ret Current behavior execution status
       * @see    LibCommon_Sync.f_clientSyncAndVerdict
       * @see    LibCommon_VerdictControl.f_setVerdict
       */
      function f_selfOrClientSyncAndVerdict( in charstring p_syncPoint,
                           in FncRetCode p_ret)
      runs on SelfSyncComp {
        if ( self == mtc ) {
          // then assume we are running non-conurrent test case
          f_selfSyncAndVerdict(p_syncPoint, p_ret);
        } else {
          f_clientSyncAndVerdict(p_syncPoint, p_ret);
        }
      }

      /**
       * @desc   Calls either self synchronization function if
       *         invoking component is the MTC, otherwise
       *         calls client synchronization. After that it
       *         sets a preamble specific verdict based on the
       *         specified return code.
       *         This function allows to implement TTCN-3 functions
       *         in a way that they can be used in both non-concurrent
       *         as well as concurrent test cases.
       * @remark This function should _not_ be called if the MTC
       *         acts as a client (and not a server) in a concurrent
       *         test case. In this case f_clientSyncAndVerdictPreamble
       *         should be used instead.
       * @param  p_syncPoint Synchronization point name/id
       * @param  p_ret Current behavior execution status
       * @see    LibCommon_Sync.f_clientSyncAndVerdict
       * @see    LibCommon_VerdictControl.f_setVerdictPreamble
       */
      function f_selfOrClientSyncAndVerdictPreamble( in charstring p_syncPoint,
                             in FncRetCode p_ret)
      runs on SelfSyncComp {
        if ( self == mtc ) {
          // then assume we are running non-conurrent test case
          f_selfSyncAndVerdictPreamble(p_syncPoint, p_ret);
        } else {
          f_clientSyncAndVerdictPreamble(p_syncPoint, p_ret);
        }
      }

      /**
       * @desc   Calls either self synchronization function if
       *         invoking component is the MTC, otherwise
       *         calls client synchronization. After that it
       *         sets a preamble specific verdict based on the
       *         specified return code.
       *         This function allows to implement TTCN-3 functions
       *         in a way that they can be used in both non-concurrent
       *         as well as concurrent test cases.
       * @remark This function should _not_ be called if the MTC
       *         acts as a client (and not a server) in a concurrent
       *         test case. In this case f_clientSyncAndVerdictTestBody
       *         should be used instead.
       * @param  p_syncPoint Synchronization point name/id
       * @param  p_ret Current behavior execution status
       * @see    LibCommon_Sync.f_clientSyncAndVerdict
       * @see    LibCommon_VerdictControl.f_setVerdictPreamble
       */
      function f_selfOrClientSyncAndVerdictTestBody( in charstring p_syncPoint,
                             in FncRetCode p_ret)
      runs on SelfSyncComp {
        if ( self == mtc ) {
          // then assume we are running non-conurrent test case
          f_selfSyncAndVerdictTestBody(p_syncPoint, p_ret);
        } else {
          f_clientSyncAndVerdictTestBody(p_syncPoint, p_ret);
        }
      }

      /**
       * @desc   Function kept for backward compatibility
       * @see    f_selfOrClientSyncAndVerdictPreamble
       *
       */
      function f_selfOrClientSyncAndVerdictPR( in charstring p_syncPoint,
                             in FncRetCode p_ret)
      runs on SelfSyncComp {
          f_selfOrClientSyncAndVerdictPreamble(p_syncPoint, p_ret);
      }

    } // end group syncFunctions

    group syncCompStateHandling {

      /**
       *
       * @desc   This function updates the state (stack) of a
       *         sync client or self sync component. This stack is
       *         key in the shutdown handling of test components.
       *         It adds the new state name to the top of the
       *         sync component stack of states.
       *         The state will only be added in case of a current
       *         execution status of e_success.
       * @param  p_newSyncCompState Name of state which was attempted to be reached.
       * @param  p_ret Current behavior execution status
       * @remark If the state of component changes this function must be
       *         _at least_ called from your test suite prior to f_selfSync
       *         or f_clientSync which is the only definite place for the
       *         shutdown default invocation!
       * @see    LibCommon_Sync.a_dummyShutDown
       * @see    LibCommon_Sync.f_selfSync
       * @see    LibCommon_Sync.f_clientSync
       */
      function f_addSyncCompState(in charstring p_newSyncCompState,
                    in FncRetCode p_ret)
      runs on ClientSyncComp {
        if ( p_ret == e_success ) {
          if ( f_isItemOnStringStack(v_stateStack,p_newSyncCompState) ) {
              log("**** f_addSyncCompState: WARNING: Attempt to add state which is already on sync state stack! No additition done.****");
          } else {
              f_pushStringStack(v_stateStack,p_newSyncCompState);
          }
        }
      } // end function f_addSyncCompState

      /**
       *
       * @desc   This function returns the top state on the sync
       *         state stack of a sync client or self sync
       *         component and removes it from the stack
       *         This function cna be used, e.g., in a while
       *         statement within a postamble or shutdown
       *         implementation
       * @param  p_state State on top of the state stack.
       * @return false if state stack is empty, true otherwise
       * @see    LibCommon_Sync.a_dummyShutDown
       */
      function f_getTopSyncCompState( out charstring p_state )
      runs on ClientSyncComp
      return boolean {
        if ( not f_peekStringStackTop(v_stateStack,p_state) ) {
          p_state := "IDLE";
          return false;
        }
        f_popStringStack(v_stateStack);
        return true;
      } // end function f_getTopSyncCompState

      /*
       * @desc  This function removes the last state on the state stack
       *        of a sync client or self sync component.
       *        This stack is key in the shutdown handling of test
       *        components.
       * @see   LibCommon_Sync.a_dummyShutDown
       */
      function f_popSyncCompState()
      runs on ClientSyncComp {
        f_popStringStack(v_stateStack);
      } // end function f_popSyncCompState

      /**
       *
       * @desc   This function returns the top state on the sync state
       *         stack of a sync client or self sync component. It
       *         does not remove it from the stack
       *         This stack is key in the shutdown handling of test
       *         components.
       * @param  p_state  State on top of the state stack.
       * @return false if state stack is empty, true otherwise
       * @see    LibCommon_Sync.a_dummyShutDown
       */
      function f_peekTopSyncCompState(out charstring p_state)
      runs on ClientSyncComp
      return boolean {
        return f_peekStringStackTop(v_stateStack,p_state);
      } // end function f_peekTopSyncCompState

      /**
       * @desc  This function checks if the sync state stack
       *        of a sync client or self sync component is empty.
       *        This stack is key in the shutdown handling of test
       *        components.
       * @see   LibCommon_Sync.a_dummyShutDown
       */
      function f_isSyncCompStateStackEmpty()
      runs on ClientSyncComp
      return boolean {
        return f_isStringStackEmpty(v_stateStack);
      } // end function f_isSyncCompStateStackEmpty

    } // end group syncCompStateHandling

    group shutDownAltsteps {

      /**
       * @desc   This is an example of a shutdown altstep which can be
       *         used as a "template" for a interface specific shutdown
       *         altstep or possily as a first temporary solution in
       *         test case development.<br><br>
       *         This altstep shall be activated as a default as the
       *         first statement in each test case function which drives
       *         an interface, i.e., in MTC behavior of single component
       *         and in each client behavior of multi component test
       *         cases.<br>
       *         The required behavior from this altstep is to:<br><br>
       *           1) expect the STOP either via the test component
       *              syncPort<br><br>
       *           2) upon its arrival it should shut down the SUT
       *              gracefully based on the current component state<br><br>
       *         The current component state should have been
       *         previously kept uptodate from a test suite via the
       *         f_addSyncCompState function. This default will then be
       *         (automatically) invoked either from within f_selfSync
       *         or f_clientSync.<br>
       *         Note that shutdown defaults can be written as
       *         _interface specific_ - they do not need to be test case
       *         or test component specific! See another example of a
       *         shutdown altstep in the sync module.
       * @see    LibCommon_Sync.f_addSyncCompState
       * @see    LibCommon_Sync.f_selfSync
       * @see    LibCommon_Sync.f_clientSync
       * @see    LibCommon_SyncExamples.a_exampleShutDown
       * @remark Your application specific shutdown altstep
       *         implementation(s) should _not_ be defined in this
       *         module but as part of your test suite or application specific
       *         modules.
       */
      altstep a_dummyShutDown()
      runs on SelfSyncComp {
        []  syncPort.receive(m_syncServerStop){
            var charstring v_state := "";
            tc_sync.stop;
            log("**** a_dummyShutDown: Test component received STOP signal from sync server - going to IDLE state ****");
            while ( f_getTopSyncCompState(v_state) ) {
              if ( v_state == "x" ) {
                // then do something
              } else if ( v_state == "y" ) {
                // then do something else
              }
            } // end while
            f_disconnect4SelfOrClientSync();
            // unmap/disconnect more if needed
            log("**** a_dummyShutDown: -> Test component stopping itself now! ****") ;
            stop ;
          }
      } // end altstep a_dummyShutDown

      /**
       * @desc Shutdown alstep in case the sync server is requesting shutdown.
       *
       * @remark User shall stop the component
       */
      altstep a_shutdown()
      runs on BaseSyncComp {
        []  syncPort.receive(m_syncServerStop){
            tc_sync.stop ;
            log("**** a_shutdown: Test component received STOP signal from MTC **** ");
          }
      }

    } // end group shutDownAltsteps

  } // end group basicUserRelevantDefinitions

  group advancedUserRelevantDefinitions {

    group serverRelated {

      /**
       * @desc   Implements synchronization of "n" clients from server
       *         side. If a problem occurs, then server sends STOP to
       *         all clients. Waits for PX_TSYNC_TIME_LIMIT to let
       *         clients finish executing their behavior until this
       *         synchronization point. See f_serverSyncClientsTimed for
       *         overwriting this later timing constraint!
       *         This function sets the server component verdict.
       * @remark The use of this function requires prior connection  of
       *         the server sync port!
       * @see    LibCommon_Sync.f_connect4SelfOrClientSync
       * @see    LibCommon_Sync.PX_TSYNC_TIME_LIMIT
       * @see    LibCommon_Sync.f_serverSyncClientsTimed
       * @param  p_noOfClients number of clients to be synchronized
       * @param  p_syncId synchronization point name/id
       */
      function f_serverSyncClients( in UInt p_noOfClients, in charstring p_syncId )
      runs on ServerSyncComp {
        f_serverSyncClientsTimed(p_noOfClients,p_syncId, PX_TSYNC_TIME_LIMIT);
      }

      /**
       * @desc   Implements synchronization of "n" clients from server
       *         side including intermediate synchronization.
       *         If a problem occurs, then server sends STOP to
       *         all clients. Waits for PX_TSYNC_TIME_LIMIT to let
       *         clients finish executing their behavior until this
       *         synchronization point. See f_serverSyncClientsTimed for
       *         overwriting this later timing constraint!
       *         This function sets the server component verdict.
       * @remark The use of this function requires prior connection  of
       *         the server sync port!
       * @see    LibCommon_Sync.f_connect4SelfOrClientSync
       * @see    LibCommon_Sync.PX_TSYNC_TIME_LIMIT
       * @see    LibCommon_Sync.f_serverSyncClientsTimed
       * @param  p_noOfClients number of clients to be synchronized
       * @param  p_syncId synchronization point name/id
       */
      function f_serverSyncClientsIntermediateSync( in UInt p_noOfClients, in charstring p_syncId, in UInt p_NoOfClientIntermediate, in template (present) charstring p_syncIdIntermediate )
      runs on ServerSyncComp {
          f_serverSyncClientsTimedIntermediateSync(p_noOfClients,p_syncId, p_NoOfClientIntermediate, p_syncIdIntermediate, PX_TSYNC_TIME_LIMIT);
      }

      /**
       * @desc   Handles synchronization of clients from server side.
       *         If problem occurs, then server sends STOP to all clients.
       *         This function sets the server verdict.
       * @remark The use of this function requires prior connection of
       *         the server sync ports!
       * @param  p_NoOfClients number of clients to be synchronized
       * @param  p_syncId synchronization point name/id
       * @param  p_execTimeLimit time limit given to all clients to finish the execution
       *         of their behavior up to this synchronization point
       * @see    LibCommon_Sync.f_connect4SelfOrClientSync
       */
      function f_serverSyncClientsTimed(in UInt     p_NoOfClients,
                        in charstring   p_syncId,
                        float       p_execTimeLimit )
      runs on ServerSyncComp {
          f_serverSyncClientsTimedIntermediateSync(p_NoOfClients, p_syncId, 0, ?, p_execTimeLimit )
      } // end function f_serverSyncClientsTimed

      /** @desc Handles synchronization of clients from server side including
       *      intermediate synchronization.
       *      If problem occurs, then server sends STOP to all clients.
       *      This function sets the server verdict.
       * @remark  The use of this function requires prior connection of
       *      the server sync ports!
       * @param   p_NoOfClients number of clients to be synchronized
       * @param   p_syncId synchronization point name/id
       * @param   p_execTimeLimit time limit given to all clients to finish the execution
       *      of their behavior up to this synchronization point
       * @see   LibCommon_Sync.f_connect4SelfOrClientSync
       * @return  execution status
       */
      function f_serverSyncClientsTimedIntermediateSync(  in UInt     p_NoOfClients,
                        in charstring   p_syncId, in UInt p_NoOfClientIntermediate, in template (present) charstring p_syncIdIntermediate,
                        float       p_execTimeLimit )
      runs on ServerSyncComp {

        var integer v_noOfRecvdSyncMsgs := 0, v_noOfRecvdSyncMsgsIntermediate := 0;
        var boolean v_stopClients := false;
        var ClientSyncCompList v_clientRefs := {}, v_clientRefsIntermediate := {};
        var ClientSyncComp v_clientRef;

        if ( p_syncId == c_prDone ) {
          log("**** f_serverSyncClientsTimed: Sync server now starting PREAMBLE synchronization ... ****") ;
        } else if ( p_syncId == c_tbDone ) {
          log("**** f_serverSyncClientsTimed: Sync server now starting TEST BODY synchronization ... ****") ;
        } else if ( p_syncId == c_initDone ) {
          log("**** f_serverSyncClientsTimed: Sync server now starting UPPER TESTER synchronization ... ****") ;
        } else {
          log("**** f_serverSyncClientsTimed: Sync server now starting handling of " & p_syncId  & " synchronization point ... ****") ;
        }
        tc_sync.start(p_execTimeLimit) ;
        alt{
          [v_noOfRecvdSyncMsgsIntermediate != p_NoOfClientIntermediate]  syncPort.receive(m_syncClientReady(p_syncIdIntermediate)) -> sender v_clientRef {
              if(not f_isPresentInArray(v_clientRef, v_clientRefsIntermediate)) {
                  v_clientRefsIntermediate[v_noOfRecvdSyncMsgsIntermediate] := v_clientRef;
                  v_noOfRecvdSyncMsgsIntermediate := v_noOfRecvdSyncMsgsIntermediate + 1;
                  if (v_noOfRecvdSyncMsgsIntermediate == p_NoOfClientIntermediate) {
                      f_serverSendToAllClients(v_clientRefsIntermediate, m_syncServerReady(p_syncIdIntermediate));
                  }
              }
              repeat;
            }
          []  syncPort.receive(m_syncClientReady(p_syncId)) -> sender v_clientRef {
              log("**** f_serverSyncClientsTimed: Sync server received READY signal from a client - server will wait for all clients to reach this synchronization point ****");
              if(not f_isPresentInArray(v_clientRef, v_clientRefs)) {
                  v_clientRefs[v_noOfRecvdSyncMsgs] := v_clientRef;
                  v_noOfRecvdSyncMsgs := v_noOfRecvdSyncMsgs + 1;
              }
              if ( v_noOfRecvdSyncMsgs != p_NoOfClients ) { repeat; }
            }
          []  syncPort.receive(m_syncClientStop) -> sender v_clientRef {
              log("**** f_serverSyncClientsTimed: Sync server received STOP signal from a client - server will wait for all clients to reach their next synchronization point and then stop them! ****") ;
              v_stopClients := true;
              if(not f_isPresentInArray(v_clientRef, v_clientRefs)) {
                  v_clientRefs[v_noOfRecvdSyncMsgs] := v_clientRef;
                  v_noOfRecvdSyncMsgs := v_noOfRecvdSyncMsgs + 1;
              }
              if ( v_noOfRecvdSyncMsgs != p_NoOfClients ) { repeat; }

            }
          []  syncPort.receive(m_syncClientReady(?)) -> sender v_clientRef {
              log("**** f_serverSyncClientsTimed: Sync server received client sync message with incorrect synchronization point id which is currently not handled - server will stop all clients! ****") ;
              v_stopClients := true;
              if(not f_isPresentInArray(v_clientRef, v_clientRefs)) {
                  v_clientRefs[v_noOfRecvdSyncMsgs] := v_clientRef;
              }
          }
          []  syncPort.receive(SyncCmd :? ) {
              log("**** f_serverSyncClientsTimed: Sync server received (invalid) sync message from other sync server - server will stop all clients! ****") ;
              v_stopClients := true; }
          []  any port.receive {
              // leave it to be ok to receive anything else
              // in case that the user has added any non-sync ports to
              // his/her server component type definition!
              repeat;
              }
          []  tc_sync.timeout{
              log("**** f_serverSyncClientsTimed: A client is not responding within specified time limit - sync server is sending stop to all clients! ****");
              v_stopClients := true; }
        } //end alt
        if (v_noOfRecvdSyncMsgsIntermediate != p_NoOfClientIntermediate) {
            v_stopClients := true;
        }
        tc_sync.stop ;
        if ( v_stopClients ) {
          setverdict(inconc);
          // then send out STOP sync msg
          f_serverSendToAllClients(v_clientRefs, m_syncServerStop);
          f_serverWaitForAllClientsToShutDown(); // function will never return!
        } else {
          setverdict(pass);
          // then send out READY sync msg
          f_serverSendToAllClients(v_clientRefs, m_syncServerReady(p_syncId));
          if ( p_syncId == c_prDone ) {
            log("**** f_serverSyncClientsTimed: Sync server successfully passed PREAMBLE synchronization point. ****") ;
          } else if ( p_syncId == c_tbDone ) {
            log("**** f_serverSyncClientsTimed: Sync server successfully passed TEST BODY synchronization point. ****") ;
          } else {
            log("**** f_serverSyncClientsTimed: Sync server successfully passed synchronization point. ****") ;
          }
        }
      } // end function f_serverSyncClientsTimedIntermediateSync

      /**
       * @desc  This function is intended only for use on the sync
       *        server component in concurrent TTCN-3 test cases.
       *        It waits for all components to finish execution within
       *        the PX_TSYNC_TIME_LIMIT. If a timeout occurs
       *        the server will stop all clients.
       *        This function sets the server component verdict.
       */
      function f_serverWaitForAllClientsToStop()
      runs on ServerSyncComp {
        tc_sync.start;
        alt {
          [] all component.done {
              tc_sync.stop;
              log("**** f_serverWaitForAllClientsToStop: All sync clients have finished their execution. Sync server now terminating test case. ****") ;
            }
          [] tc_sync.timeout {
              log("**** f_serverWaitForAllClientsToStop: Not all sync clients have finshed execution within the sync time limit. Sync server will stop test case! ****") ;
              stop;
            }
        } // end alt
        setverdict(pass);
      } // end function f_serverWaitForAllClientsToStop

    } // end group serverRelated

    group clientRelated {

      /**
       * @desc  This function creates the connection needed to
       *        execute client synchronization functions
       * @see   LibCommon_Sync.f_clientSync
       * @see   LibCommon_Sync.f_clientSendStop
       */
      function f_connect4ClientSync()
      runs on ClientSyncComp {
        connect(self:syncPort, mtc:syncPort);
      }// end function f_connect4ClientSync

      /**
       * @desc  This function removes the connection needed
       *        to execute client synchronization functions
       * @see   LibCommon_Sync.f_clientSync
       * @see   LibCommon_Sync.f_clientSendStop
       */
      function f_disconnect4ClientSync()
      runs on ClientSyncComp {
        disconnect(self:syncPort, mtc:syncPort);
      }// end function f_disconnect4ClientSync

      /**
       * @desc   This function combines client verdict setting with its
       *         synchronization for use,e.g, after or within a
       *         test body implementation.
       *         Note that such premables can _not_ be reused in non-
       *         concurrent test cases. This can be achieved by using
       *         the f_selfOrClientSyncAndVerdict function instead.
       *         This function sets the client component verdict.
       * @param  p_syncId Synchronization point name/id
       * @param  p_ret Current behavior execution status
       * @remark The use of this function requires prior connection
       *         of the client sync port!
       * @see    LibCommon_Sync.f_connect4ClientSync
       * @see    LibCommon_Sync.f_connect4SelfOrClientSync
       * @see    LibCommon_VerdictControl.f_setVerdict
       * @see    LibCommon_Sync.f_selfOrClientSyncAndVerdict
       */
      function f_clientSyncAndVerdict(in charstring p_syncId,
                      in FncRetCode p_ret)
      runs on ClientSyncComp {
        if(vc_testcaseStep == e_preamble) {
            f_clientSyncAndVerdictPreamble(p_syncId, p_ret);
        } else if(vc_testcaseStep == e_testBody) {
            f_clientSyncAndVerdictTestBody(p_syncId, p_ret);
        }
        else {
            f_clientSyncAndVerdictPostamble(p_syncId, p_ret);
        }
      }

      /**
       * @desc   This function combines client verdict setting with its
       *         synchronization for use after or within a preamble
       *         implementation.
       *         Note that such preambles can _not_ be reused in non-
       *         concurrent test cases.
       *         This function sets the client component verdict.
       * @remark The use of this function requires prior connection
       *         of the client sync port!
       * @see    LibCommon_Sync.f_connect4ClientSync
       * @see    LibCommon_Sync.f_connect4SelfOrClientSync
       * @see    LibCommon_VerdictControl.f_setVerdictPreamble
       * @param  p_syncId Synchronization point name/id
       * @param  p_ret Current behavior execution status
       */
      function f_clientSyncAndVerdictPreamble(in charstring p_syncId ,
                          FncRetCode p_ret)
      runs on ClientSyncComp {
        f_setVerdictPreamble(p_ret);
        f_clientSync(p_syncId,p_ret);
        vc_testcaseStep := e_testBody;
      }

      /**
       * @desc   This function combines client verdict setting with its
       *         synchronization for use,e.g, after or within a
       *         test body implementation.
       *         Note that such premables can _not_ be reused in non-
       *         concurrent test cases. This can be achieved by using
       *         the f_selfOrClientSyncAndVerdict function instead.
       *         This function sets the client component verdict.
       * @param  p_syncId Synchronization point name/id
       * @param  p_ret Current behavior execution status
       * @remark The use of this function requires prior connection
       *         of the client sync port!
       * @see    LibCommon_Sync.f_connect4ClientSync
       * @see    LibCommon_Sync.f_connect4SelfOrClientSync
       * @see    LibCommon_VerdictControl.f_setVerdict
       * @see    LibCommon_Sync.f_selfOrClientSyncAndVerdict
       */
      function f_clientSyncAndVerdictTestBody(in charstring p_syncId,
                      in FncRetCode p_ret)
      runs on ClientSyncComp {
        f_setVerdict(p_ret);
        f_clientSync(p_syncId,p_ret);
        vc_testcaseStep := e_postamble;
      }

      /**
       * @desc   This function combines client verdict setting with its
       *         synchronization for use after or within a
       *         postamble implementation.
       *         Note that such prostambles can _not_ be reused in non-
       *         concurrent test cases.
       *         This function sets the client component verdict.
       * @remark The use of this function requires prior connection
       *         of the client sync port!
       * @see    LibCommon_Sync.f_connect4ClientSync
       * @see    LibCommon_Sync.f_connect4SelfOrClientSync
       * @see    LibCommon_VerdictControl.f_setVerdictPostamble
       * @param  p_syncId Synchronization point name/id
       * @param  p_ret Current behavior execution status
       */
      function f_clientSyncAndVerdictPostamble(in charstring p_syncId ,
                           in FncRetCode p_ret)
      runs on ClientSyncComp {
        f_setVerdictPostamble(p_ret);
        f_clientSync(p_syncId,p_ret);
      }

      /**
       * @desc   This function handles synchronization of a sync client
       *         with the server. In case of successful execution it sends
       *         a READY message to the server and waits the READY back.
       *         The time used for waiting is defined by PX_TSYNC_TIME_LIMIT.
       *         In case of a non successful execution status it
       *         sends a STOP message to the server.
       *         In both cases the receipt of a STOP message or no
       *         response from the server it will trigger the shutdown
       *         default (if activated).
       *         This function will set only the client verdict to INCONC
       *         (and stop its execution) if no STOP response is received
       *         from the server within the PX_TSYNC_TIME_LIMIT
       *         or if no shutdown default is activated. In all other
       *         cases the client verdict is NOT set.
       * @param  p_syncId Synchronization point name/id
       * @param  p_ret Current behavior execution status
       * @remark The use of this function requires prior connection
       *         of the client sync port!
       * @see    LibCommon_Sync.f_connect4ClientSync
       * @see    LibCommon_Sync.f_connect4SelfOrClientSync
       * @see    LibCommon_Sync.PX_TSYNC_TIME_LIMIT
       * @see    LibCommon_Sync.a_dummyShutDown
       * @see    LibCommon_Sync.f_clientSendStop
       * @return Updated execution status
       */
      function f_clientSync(  in charstring p_syncId ,
                  in FncRetCode p_ret )
      runs on ClientSyncComp
      return FncRetCode{

        if (p_ret == e_success){
          syncPort.send(m_syncClientReady(p_syncId));
          tc_sync.start;
          alt{
            [] syncPort.receive(m_syncServerReady(p_syncId)){
                tc_sync.stop ; }
            [] tc_sync.timeout{
                log("**** f_clientSync: Sync client did not receive message from sync server within the specified time limit - sync client will ask sync server to stop test case! ****") ;
                f_clientSendStop(); } // function will not return!
          } //end alt
        } //end if
        else {
          log("**** f_clientSync: Execution status indicates that execution of test component behavior was not successful - sync client will ask sync server to stop test case! ****") ;
          f_clientSendStop(); // function will not return!
        }
        if ( p_syncId == c_prDone ) {
          log("**** f_clientSync: Sync client successfully passed PREAMBLE synchronization point. ****") ;
        } else if ( p_syncId == c_tbDone ) {
          log("**** f_clientSync: Sync client successfully passed TEST BODY synchronization point. ****") ;
        } else {
          log("**** f_clientSync: Sync client successfully passed synchronization point. ****") ;
        }
        return e_success ;

      } // end function f_clientSync

      /**
       * @desc   This function can be used to request the shutdown a
       *         multi component test case _prior_ to reaching a
       *         synchronization point. It sends a STOP message to
       *         the sync server and awaits then the STOP from the server
       *         which will trigger the shutdown default (if activated).
       *         This function will set the server verdict to INCONC (and
       *         stop the test case) if no shutdown default is activated.
       *         This function will set only the client verdict to INCONC
       *         (and stop its execution) if no STOP response is received
       *         from the server within the PX_TSYNC_TIME_LIMIT
       *         or if no shutdown default is activated. In all other
       *         cases the client verdict is NOT set.
       * @remark The use of this function requires prior connection
       *         of the client sync port!
       * @see    LibCommon_Sync.f_connect4ClientSync
       * @see    LibCommon_Sync.f_connect4SelfOrClientSync
       * @see    LibCommon_Sync.PX_TSYNC_TIME_LIMIT
       * @see    LibCommon_Sync.a_dummyShutDown
       */
      function f_clientSendStop()
      runs on ClientSyncComp {
        log("**** f_clientSendStop: Sync client requesting from server to stop test case (including itself). ****") ;
        syncPort.send(m_syncClientStop) ;
        tc_sync.start;
        alt{
          [] tc_sync.timeout{
              log("**** f_clientSendStop: Stopping sync client without shutdown - either no shutdown default active or no stop received from server. ****") ;
              setverdict(inconc);
              stop ;
             }
        }//end alt
        tc_sync.stop;
        stop; // stop here if shutdown default does not stop
      }

    } // end group clientRelated

  } // end group advancedUserRelevantDefinitions

  group otherSyncModuleDefinitions {

    group syncModuleparams {
      /**
       *
       * @desc  Default time limit for a sync client to reach a
       *        synchronization point
       */
      modulepar float PX_TSYNC_TIME_LIMIT := 120.0;

      /*
       * @desc  Default time limit for a sync client to finish
       *        its execution of the shutdown default
       */
      modulepar float PX_TSHUT_DOWN_TIME_LIMIT := 120.0;
    }

    group otherSyncTypes {

      type record of charstring SyncPointList;

      type record of ClientSyncComp ClientSyncCompList;

    } // end group otherSyncTypes

    group otherSelfSyncRelatedDefinitions {

      /**
       * @desc  This function creates the connection needed to
       *        execute self sync functions
       * @see   LibCommon_Sync.f_selfSync
       * @see   LibCommon_Sync.f_selfSyncStop
       */
      function f_connect4SelfSync()
      runs on SelfSyncComp {
        connect(self:syncSendPort, self:syncPort);
      }// end function f_connect4SelfSync

      /**
       * @desc  This function removes the connection needed
       *        to execute self sync functions
       * @see   LibCommon_Sync.f_selfSync
       * @see   LibCommon_Sync.f_selfSyncStop
       */
      function f_disconnect4SelfSync()
      runs on SelfSyncComp {
        disconnect(self:syncSendPort, self:syncPort);
      }// end function f_disconnect4SelfSync

      /**
       * @desc  This function combines MTC verdict setting with self
       *        synchronization for use in the preamble / test body / postamble
       * @param p_syncId Synchronization point name/id
       * @param p_ret Current behavior execution status
       * @see   LibCommon_VerdictControl.f_setVerdict
       * @see   LibCommon_Sync.f_selfSync
       * @see   LibCommon_Sync.a_dummyShutDown
       */
      function f_selfSyncAndVerdict(  in charstring p_syncId,
                      in FncRetCode p_ret )
      runs on SelfSyncComp {
        if(vc_testcaseStep == e_preamble) {
            f_selfSyncAndVerdictPreamble(p_syncId, p_ret);
        } else if(vc_testcaseStep == e_testBody) {
            f_selfSyncAndVerdictTestBody(p_syncId, p_ret);
        }
        else {
            f_selfSyncAndVerdictPostamble(p_syncId, p_ret);
        }
      }

      /**
       * @desc  This function combines MTC verdict setting with self
       *        synchronization for use after the preamble.
       * @param p_syncId Synchronization point name/id
       * @param p_ret Current behavior execution status
       * @see   LibCommon_VerdictControl.f_setVerdictPreamble
       * @see   LibCommon_Sync.f_selfSync
       */
      function f_selfSyncAndVerdictPreamble(  in charstring p_syncId,
                          in FncRetCode p_ret )
      runs on SelfSyncComp {
        f_setVerdictPreOrPostamble(p_ret);
        f_selfSync(p_syncId,p_ret);
        vc_testcaseStep := e_testBody;
      }

      /**
       * @desc  This function combines MTC verdict setting with self
       *        synchronization for use after the test body.
       * @param p_syncId Synchronization point name/id
       * @param p_ret Current behavior execution status
       * @see   LibCommon_VerdictControl.f_setVerdict
       * @see   LibCommon_Sync.f_selfSync
       */
      function f_selfSyncAndVerdictTestBody(  in charstring p_syncId,
                          in FncRetCode p_ret )
      runs on SelfSyncComp {
        f_setVerdict(p_ret);
        f_selfSync(p_syncId,p_ret);
        vc_testcaseStep := e_postamble;
      }

      /**
       * @desc  This function combines MTC verdict setting with self
       *        synchronization for use after the postamble.
       * @param p_syncId Synchronization point name/id
       * @param p_ret Current behavior execution status
       * @see   LibCommon_VerdictControl.f_setVerdictPostamble
       * @see   LibCommon_Sync.f_selfSync
       */
      function f_selfSyncAndVerdictPostamble( in charstring p_syncId ,
                          in FncRetCode p_ret )
      runs on SelfSyncComp {
        f_setVerdictPreOrPostamble(p_ret);
        f_selfSync(p_syncId,p_ret);
      }

      /**
       * @desc   This function synchronizes a MTC with itself. In case
       *         of a non successful execution status it sends a STOP
       *         message to itself and invokes that way the
       *         shutdown default (if activated).
       *         This function will set the server verdict to INCONC (and
       *         stop the test case) if no shutdown default is activated.
       *         Otherwise no verdict is set.
       * @remark Sync ports should be connected prior to the invocation
       *         of this function!
       * @param  p_syncId Synchronization point name/id
       * @param  p_ret Current behavior execution status
       * @return Updated execution status
       * @see    LibCommon_Sync.f_connect4SelfSync
       * @see    LibCommon_Sync.a_dummyShutDown
       */
      function f_selfSync(  in charstring p_syncId ,
                  in FncRetCode p_ret )
      runs on SelfSyncComp
      return FncRetCode{
        if (p_ret != e_success){
          f_selfSyncStop() ; // function will not return!
        }
        if ( p_syncId == c_prDone ) {
          log("**** f_selfSync: Successfully passed PREAMBLE synchronization point. ****") ;
        } else if ( p_syncId == c_tbDone ) {
          log("**** f_selfSync: Successfully passed TEST BODY synchronization point. ****") ;
        } else {
          log("**** f_selfSync: Successfully passed synchronization point. ****") ;
        }
        return e_success ;
      }// end function f_selfSync

      /**
       * @desc   This function can be used to shut down a test case _prior_
       *         to reaching a synchronization point. it sends a STOP
       *         message to itself and invokes that way the
       *         shutdown default (if activated).
       *         This function will set the server verdict to INCONC (and
       *         stop the test case) if no shutdown default is activated.
       *         Otherwise no verdict is set.
       * @remark  Sync ports should be connected prior to the invocation
       *          of this function!
       * @see     LibCommon_Sync.f_connect4SelfSync
       */
      function f_selfSyncStop()
      runs on SelfSyncComp {

        log("**** f_selfSyncStop: MTC requests to stop test case (itself). ****") ;
        syncSendPort.send(m_syncServerStop) ; // this MUST be _server_ for the default to catch!
        tc_sync.start(PX_TSYNC_TIME_LIMIT);
        alt{
          [] tc_sync.timeout{
              log("**** f_selfSyncStop: Stopping MTC without shutdown - either no shutdown default active or missing syncPort connection ****") ;
              setverdict(inconc);
              stop ;
             }
        }//end alt
        tc_sync.stop;
        stop; // if shutdown default is not activated or if it does not stop
      } // end function f_selfSyncStop

    } // end group otherSelfSyncRelatedDefinitions

    /**
     *
     * @desc The sychronization protocol is conceptually based on
     *       named synchronization. Each synchronization point
     *       has it own specific synchronization message. This
     *       makes each synchronization unique, and allows, e.g., to
     *       ensure that a server synchronizes only clients which have
     *       reached the same synchronization point.
     */
    group syncProtocolDefinition {

      type union SyncCmd {
        ClientReady clientReady,
        ServerReady serverReady,
        ClientStop  clientStop,
        ServerStop  serverStop
      }

      type record ClientReady {
        charstring syncPointId
      }

      type record ServerReady {
        charstring syncPointId
      }

      type record ClientStop {}

      type record ServerStop {}

    } // end group syncProtocolDefinition

    group syncMessages {
      template SyncCmd m_syncClientReady( template (present) charstring p_syncId ) := {
        clientReady := { p_syncId }
      }

      template SyncCmd m_syncServerReady( template (present) charstring p_syncId ) := {
        serverReady := { p_syncId }
      }

      template SyncCmd m_syncClientStop := {
        clientStop := {}
      }

      template SyncCmd m_syncServerStop := {
        serverStop := {}
      }

    } // end group syncMessages

    group otherSyncFunctions {

      /**
       * @desc  Makes server send a sync message to all known clients
       * @param p_clientRefs List of client references to which the message is to be send
       * @param p_syncCmd The actual synchronization message to be sent out
       */
      function f_serverSendToAllClients(  in ClientSyncCompList p_clientRefs,
                        in template (value) SyncCmd p_syncCmd)
      runs on ServerSyncComp {
        var integer i:=0;
        for (i:=0; i< sizeof(p_clientRefs); i:=i+1 ){
          syncPort.send(p_syncCmd) to valueof(p_clientRefs[i]);
        }
      } // end function f_serverSendToAllClients

      /**
       * @desc  This function is intended only for use on server in concurrent
       *        TTCN-3 test cases. It waits for all components to shut down
       *        within the PX_TSHUT_DOWN_TIME_LIMIT. If a timeout occurs
       *        it aborts the test case (no matter how far clients got with their
       *        shutdown).
       *        This function sets the server verdict.
       */
      function f_serverWaitForAllClientsToShutDown()
      runs on ServerSyncComp {

        tc_shutDown.start(PX_TSHUT_DOWN_TIME_LIMIT);
        alt {
          [] syncPort.receive {
          	// clients may still try to send some sync message
          }
          [] all component.done {
            tc_shutDown.stop;
            log("**** f_serverWaitForAllClientsToShutDown: All components have properly shut down. Sync server will now terminate the test case. ****") ;
          }
          [] tc_shutDown.timeout {
            log("**** f_serverWaitForAllClientsToShutDown: Not all clients have properly shutdown within the shut down time limit. Sync server will now terminate test case! ****") ;
          }
        } // end alt
        // cover case that shut down default is NOT activated
        setverdict(inconc);
        //mtc.stop;
        syncPort.send(m_syncServerStop) to self; // this MUST be _server_ for the default to catch!
        tc_sync.start(PX_TSYNC_TIME_LIMIT);
        alt{
          [] tc_sync.timeout{
            log("**** f_selfSyncStop: Stopping MTC without shutdown - either no shutdown default active or missing syncPort connection ****") ;
            setverdict(inconc);
            stop ;
          }
        }//end alt
        tc_sync.stop;
        stop; // if shutdown default is not activated or if it does not stop
      } // end function f_serverWaitForAllClientsToShutDown

		function f_isPresentInArray(in ClientSyncComp p_clientRef, in ClientSyncCompList p_clientRefs)
		return boolean {
			var integer i;
			for(i:=0; i < sizeof(p_clientRefs); i:=i+1) {
				if(p_clientRefs[i] == p_clientRef) {
					return true;
				}
			}
			return false;
		}
    } // end group otherSyncFunctions

  } // end group otherSyncDefinitions

} // end module LibCommon_Sync
