module TestCodec_DENM {
    
  // LibIts
  import from ITS_Container language "ASN.1:1997" all;
  import from DENM_PDU_Descriptions language "ASN.1:1997"all;
    
  // LibItsCommon
  import from LibItsCommon_Functions all;
  import from LibItsCommon_ASN1_NamedNumbers all;
    
  // LibItsDenm
  import from LibItsDenm_TypesAndValues all;
  import from LibItsDenm_TestSystem all;
  import from LibItsDenm_Templates all;
  import from LibItsDenm_Functions all;
    
  // TestCodec
  import from TestCodec_TestAndSystem all;
    
  group LibItsDenm_testCases {
        
    group testDenmPrimitiveMessages {
            
      testcase tc_DenmReq() runs on TCType system TCType {
        var template (value) SituationContainer v_situation := m_situation(LibItsCommon_ASN1_NamedNumbers.CauseCodeType_vehicleBreakdown_, LibItsCommon_ASN1_NamedNumbers.VehicleBreakdownSubCauseCode_unavailable_);
	
        TestDenmReq(
                    m_denmReq(
                              m_denmPdu(
                                        m_denm(
                                               m_denmMgmtCon(
                                                             m_tsActionId,
                                                             -, -, -,
                                                             441022343072,
                                                             441022343072
                                                             ),
                                               v_situation,
                                               m_denmLocation_zeroDelta
                                               )
                                        )
                              ),
                    true,
                    oct2bit('01010001B207C60000D90380000CD5DF5CF4033577D73D04FA46CAE6F7E4630001001000186A0000180B600001BFFFEFFFFB19C00000'O)
                    );
      }
      
      testcase tc_DenmInd() runs on TCType system TCType {
        TestDenmInd(
                   mw_denmInd(
                              mw_denmPdu(
                                         mw_denm
                                         )
                            ), 
                   '01010001B207C60000D90380000CD5DF5CF4033577D73D04FA46CAE6F7E4630001001000186A0000180B600001BFFFEFFFFB19C000000102030405060708090a0b0c00000000000000000000000000000000000000000000000000000000000000000a0a0a0a'O
                   );
      }
      
    } // End of group testDenmPrimitiveMessages
        
    group testDenmUpperTester {

      /**
       * @desc Validate template GeoNetworking/UtDenmInitialize
       * @verdict Pass on success, Fail otherwise
       */
      testcase tc_Denm_UtDenmInitialize() runs on TCType system TCType {
        var bitstring v_encMsg;
        var UtDenmInitialize v_decMsg;
        var integer v_res := 0;
        var template (value) UtDenmInitialize m_utDenmInitialize := { '0809AABBCCDDEEFF'O };
        var bitstring v_expEncMsg := oct2bit('000809AABBCCDDEEFF'O);
    
        // Encode template
        log("Encode template ", valueof(m_utDenmInitialize));
      v_encMsg := encvalue(m_utDenmInitialize);
        log("Encoded message:  ", bit2oct(v_encMsg));
        // Check result
        if (not isbound(v_encMsg)) {
          setverdict(fail, "Encoding failed!");
          stop;
        }
        if (not match(v_encMsg, v_expEncMsg)) {
          log("Expected message: ", bit2oct(valueof(v_expEncMsg)));
          setverdict(fail, "Encoding failed, not the expected result!");
          stop;
        }
        setverdict(pass, "Encoding passed.");
      } // End of tc_Denm_UtDenmInitialize

      /**
       * @desc Validate template Denm/UtDenmChangePosition
       * @verdict Pass on success, Fail otherwise
       */
      testcase tc_Denm_UtDenmChangePosition() runs on TCType system TCType {
        var bitstring v_encMsg;
        var UtDenmInitialize v_decMsg;
        var integer v_res := 0;
        var template (value) UtDenmChangePosition m_utDenmChangePosition := { 1234, 5678, 9876 };
        var bitstring v_expEncMsg := oct2bit('02000004D20000162E00002694'O);
    
        // Encode template
        log("Encode template ", valueof(m_utDenmChangePosition));
      v_encMsg := encvalue(m_utDenmChangePosition);
        log("Encoded message:  ", bit2oct(v_encMsg));
        // Check result
        if (not isbound(v_encMsg)) {
          setverdict(fail, "Encoding failed!");
          stop;
        }
        if (not match(v_encMsg, v_expEncMsg)) {
          log("Expected message: ", bit2oct(valueof(v_expEncMsg)));
          setverdict(fail, "Encoding failed, not the expected result!");
          stop;
        }
        setverdict(pass, "Encoding passed.");
      } // End of tc_Denm_UtDenmChangePosition
      
      /**
       * @desc Validate template Denm/UtDenmChangePseudonym
       * @verdict Pass on success, Fail otherwise
       */
      testcase tc_Denm_UtDenmChangePseudonym() runs on TCType system TCType {
        var bitstring v_encMsg;
        var UtDenmChangePseudonym v_decMsg;
        var integer v_res := 0;
        var template (value) UtDenmChangePseudonym m_utDenmChangePseudonym := { };
        var bitstring v_expEncMsg := oct2bit('04'O);
    
        // Encode template
        log("Encode template ", valueof(m_utDenmChangePseudonym));
      v_encMsg := encvalue(m_utDenmChangePseudonym);
        log("Encoded message:  ", bit2oct(v_encMsg));
        // Check result
        if (not isbound(v_encMsg)) {
          setverdict(fail, "Encoding failed!");
          stop;
        }
        if (not match(v_encMsg, v_expEncMsg)) {
          log("Expected message: ", bit2oct(valueof(v_expEncMsg)));
          setverdict(fail, "Encoding failed, not the expected result!");
          stop;
        }
        setverdict(pass, "Encoding passed.");
      } // End of tc_Denm_UtDenmChangePseudonym

      /**
       * @desc Validate template Denm/UtDenmTrigger
       * @verdict Pass on success, Fail otherwise
       */
      testcase tc_Denm_UtDenmTrigger_1() runs on TCType system TCType {
        var bitstring v_encMsg;
        var UtDenmTrigger v_decMsg;
        var integer v_res := 0;
        var bitstring v_expEncMsg := oct2bit('1090005E28CBC883000002000000005B0000000000000000'O);
        var template (value) SituationContainer v_situation := m_situation(LibItsCommon_ASN1_NamedNumbers.CauseCodeType_vehicleBreakdown_, LibItsCommon_ASN1_NamedNumbers.VehicleBreakdownSubCauseCode_unavailable_);
        var template (value) UtDenmTrigger v_trigger := m_utTriggerEvent(v_situation);
    
        // Encode template
        v_trigger.detectionTime := 404411369603;
        log("Encode template ", valueof(v_trigger));
        v_encMsg := encvalue(v_trigger);
        log("Encoded message:  ", bit2oct(v_encMsg));
        // Check result
        if (not isbound(v_encMsg)) {
          setverdict(fail, "Encoding failed!");
          stop;
        }
        if (not match(v_encMsg, v_expEncMsg)) {
          log("Expected message: ", bit2oct(valueof(v_expEncMsg)));
          setverdict(fail, "Encoding failed, not the expected result!");
          stop;
        }
        setverdict(pass, "Encoding passed.");
      } // End of tc_Denm_UtDenmTrigger_1

      /**
       * @desc Validate template Denm/UtDenmTrigger
       * @verdict Pass on success, Fail otherwise
       */
      testcase tc_Denm_UtDenmTrigger_2() runs on TCType system TCType {
        var bitstring v_encMsg;
        var UtDenmTrigger v_decMsg;
        var integer v_res := 0;
        var bitstring v_expEncMsg := oct2bit('10D6005E28CBC88300000A000005005B000000000107D000'O);
        var template (value) SituationContainer v_situation := m_situation(LibItsCommon_ASN1_NamedNumbers.CauseCodeType_vehicleBreakdown_, LibItsCommon_ASN1_NamedNumbers.VehicleBreakdownSubCauseCode_unavailable_);
        var template (value) UtDenmTrigger v_trigger := m_utTriggerEvent(v_situation, 10, 5, 2000, 1);
        
        // Encode template
        v_trigger.detectionTime := 404411369603;
        log("Encode template ", valueof(v_trigger));
        v_encMsg := encvalue(v_trigger);
        log("Encoded message:  ", bit2oct(v_encMsg));
        // Check result
        if (not isbound(v_encMsg)) {
          setverdict(fail, "Encoding failed!");
          stop;
        }
        if (not match(v_encMsg, v_expEncMsg)) {
          log("Expected message: ", bit2oct(valueof(v_expEncMsg)));
          setverdict(fail, "Encoding failed, not the expected result!");
          stop;
        }
        setverdict(pass, "Encoding passed.");
      } // End of tc_Denm_UtDenmTrigger_2

      /**
       * @desc Validate template Denm/UtDenmUpdate
       * @verdict Pass on success, Fail otherwise
       */
      testcase tc_Denm_UtDenmUpdate_1() runs on TCType system TCType {
        var bitstring v_encMsg;
        var UtDenmUpdate v_decMsg;
        var integer v_res := 0;
        var bitstring v_expEncMsg := oct2bit('12400001B207000A005E28CBC883000000005B0000000000000000'O);
        var template (value) SituationContainer v_situation := m_situation(LibItsCommon_ASN1_NamedNumbers.CauseCodeType_vehicleBreakdown_, LibItsCommon_ASN1_NamedNumbers.VehicleBreakdownSubCauseCode_unavailable_);
        var template (value) UtDenmUpdate v_update := m_utUpdateEvent(m_tsActionId(10), v_situation);
        
        // Encode template
        v_update.detectionTime := 404411369603;
        log("Encode template ", valueof(v_update));
        v_encMsg := encvalue(v_update);
        log("Encoded message:  ", bit2oct(v_encMsg));
        // Check result
        if (not isbound(v_encMsg)) {
          setverdict(fail, "Encoding failed!");
          stop;
        }
        if (not match(v_encMsg, v_expEncMsg)) {
          log("Expected message: ", bit2oct(valueof(v_expEncMsg)));
          setverdict(fail, "Encoding failed, not the expected result!");
          stop;
        }
        setverdict(pass, "Encoding passed.");
      } // End of tc_Denm_UtDenmUpdate_1

      /**
       * @desc Validate template Denm/UtDenmUpdate
       * @verdict Pass on success, Fail otherwise
       */
      testcase tc_Denm_UtDenmUpdate_2() runs on TCType system TCType {
        var bitstring v_encMsg;
        var UtDenmUpdate v_decMsg;
        var integer v_res := 0;
        var bitstring v_expEncMsg := oct2bit('12060001B207000A005E28CBC88300000000000000000040002000'O);
        var template (value) UtDenmUpdate v_update := m_utUpdateEvent(
                                                                      m_tsActionId(10),
                                                                      -, -, -, -, -, -,
                                                                      32, 64
                                                                      );
        
        // Encode template
        v_update.detectionTime := 404411369603;
        log("Encode template ", valueof(v_update));
        v_encMsg := encvalue(v_update);
        log("Encoded message:  ", bit2oct(v_encMsg));
        // Check result
        if (not isbound(v_encMsg)) {
          setverdict(fail, "Encoding failed!");
          stop;
        }
        if (not match(v_encMsg, v_expEncMsg)) {
          log("Expected message: ", bit2oct(valueof(v_expEncMsg)));
          setverdict(fail, "Encoding failed, not the expected result!");
          stop;
        }
        setverdict(pass, "Encoding passed.");
      } // End of tc_Denm_UtDenmUpdate_2

      /**
       * @desc Validate decoding of Denm/UtDenmTriggerResult
       * @verdict Pass on success, Fail otherwise
       */
      testcase tc_Denm_UtDenmTriggerResult() runs on TCType system TCType {
        var bitstring v_binary := oct2bit('11017f383ea50003'O);
        var UtDenmResults v_decMsg;
        var integer v_res := 0;
        var template (value) UtDenmResults v_expDecMsg := { utDenmTriggerResult := { true, { 2134392485, 3 } } };
        
        // Decode template
        v_res := decvalue(v_binary, v_decMsg);
        log("Decoded message: ", v_decMsg);
        select (v_res) {
        case (0) {
          if(match(v_decMsg, v_expDecMsg)) {
            setverdict(pass);
          } else {
            setverdict(fail);
          }
        }
        case (1) {
          setverdict(fail, "Decoding failed.");
        }
        case (2) {
          setverdict(fail, "Not enough bits.");
        }
        }
      } // End of tc_Denm_UtDenmTriggerResult

      /**
       * @desc Validate decoding of Denm/UtDenmUpdateResult
       * @verdict Pass on success, Fail otherwise
       */
      testcase tc_Denm_UtDenmUpdateResult() runs on TCType system TCType {
        var bitstring v_binary := oct2bit('13010000000590D0'O);
        var UtDenmResults v_decMsg;
        var integer v_res := 0;
        var template (value) UtDenmResults v_expDecMsg := { utDenmUpdateResult := { true, { 5, 37072 } } };
        
        // Decode template
        v_res := decvalue(v_binary, v_decMsg);
        log("Decoded message: ", v_decMsg);
        select (v_res) {
        case (0) {
          if(match(v_decMsg, v_expDecMsg)) {
            setverdict(pass);
          } else {
            setverdict(fail);
          }
        }
        case (1) {
          setverdict(fail, "Decoding failed.");
        }
        case (2) {
          setverdict(fail, "Not enough bits.");
        }
        }
      } // End of tc_Denm_UtDenmUpdateResult

      /**
       * @desc Validate decoding of Denm/UtDenmEventInd
       * @verdict Pass on success, Fail otherwise
       */
      testcase tc_Denm_UtDenmEventInd_1() runs on TCType system TCType {
        var bitstring v_binary := oct2bit('170036010100008235c70000411a81130a3007329ee28c001555b35a4e9006b49d200ffffffe10186a0f0000081405b000009ffff7fffd8ce0'O);
        var UtDenmEventInd v_decMsg;
        var integer v_res := 0;
        var template (present) UtDenmEventInd v_expDecMsg;
        
        v_expDecMsg := { denMsg :=
                         mw_denmPdu(
                                    mw_denm,
                                    mw_anyStationId, 
                                    LibItsCommon_ASN1_NamedNumbers.ItsPduHeader_protocolVersion_currentVersion_, 
                                    LibItsCommon_ASN1_NamedNumbers.ItsPduHeader_messageID_denm_
                                    )
        };
        // Decode template
        v_res := decvalue(v_binary, v_decMsg);
        log("Decoded message: ", v_decMsg);
        select (v_res) {
        case (0) {
          if(match(v_decMsg, v_expDecMsg)) {
            setverdict(pass);
          } else {
            setverdict(fail);
          }
        }
        case (1) {
          setverdict(fail, "Decoding failed.");
        }
        case (2) {
          setverdict(fail, "Not enough bits.");
        }
        }
      } // End of tc_Denm_UtDenmEventInd_1

      /**
       * @desc Validate decoding of Denm/UtDenmEventInd
       * @verdict Pass on success, Fail otherwise
       */
      testcase tc_Denm_UtDenmEventInd_2() runs on TCType system TCType {
        var bitstring v_binary := oct2bit('17007c0101000027bbe7800013dd80008bd45e6156c2f5196d52e4f9aaef1716df9ed064064000186a0f4aa3003e70f200c0028329211cf6338105cc41e42c6700014f6e73b72ec670ffeebf80ac670ffc93f8fcc670ff843f9c4c670ff7ebfab8c670269d6311d7c961eb8b63388400009eec000800009eec000c5f1af822'O);
        var UtDenmEventInd v_decMsg;
        var integer v_res := 0;
        var template (present) UtDenmEventInd v_expDecMsg;
        var template (value) SituationContainer v_situation := m_situation(LibItsCommon_ASN1_NamedNumbers.CauseCodeType_vehicleBreakdown_, LibItsCommon_ASN1_NamedNumbers.VehicleBreakdownSubCauseCode_unavailable_);

        v_expDecMsg := { denMsg :=
                         mw_denmPdu(
                                    mw_denm(
                                            mw_denmMgmtCon(
                                                           m_actionId(
                                                                        1,
                                                                        10171
                                                                        )
                                                           )
                                            ),
                                    10171
                                    )
        };
        //log("v_expDecMsg: ", v_expDecMsg);
        
        // Decode template
        v_res := decvalue(v_binary, v_decMsg);
        log("Decoded message: ", v_decMsg);
        select (v_res) {
        case (0) {
          if(match(v_decMsg, v_expDecMsg)) {
            setverdict(fail);
          } else {
            setverdict(pass, "Mismatch found, stationType mismatch");
          }
        }
        case (1) {
          setverdict(fail, "Decoding failed.");
        }
        case (2) {
          setverdict(fail, "Not enough bits.");
        }
        }
      } // End of tc_Denm_UtDenmEventInd_2

    } // End of group testDenmUpperTester
    
    group testDenmPort {
            
      /**
       * @desc validate DenmReq
       * @verdict Pass on success, Fail otherwise
       */
      testcase tc_Denm_Port() runs on ItsDenm system ItsDenmSystem {
        var DenmReq v_denmReq;
        var boolean v_got_denm := false;
        var template (value) SituationContainer v_situation := m_situation(LibItsCommon_ASN1_NamedNumbers.CauseCodeType_vehicleBreakdown_, LibItsCommon_ASN1_NamedNumbers.VehicleBreakdownSubCauseCode_unavailable_);
		
        map(self:denmPort, system:denmPort);
        
      v_denmReq := valueof(
                           m_denmReq(
                                     m_denmPdu(
                                               m_denm(
                                                      m_denmMgmtCon(
                                                                    m_tsActionId,
                                                                    -, -, -,
                                                                    f_getCurrentTime(),
                                                                    f_getCurrentTime()
                                                                    ),
                                                      v_situation,
                                                      m_denmLocation_zeroDelta
                                                      ))
                                     )
                           );
        denmPort.send(v_denmReq);
        tc_ac.start;
        alt {
          [v_got_denm == false] denmPort.receive(DenmInd : ?) {
            v_got_denm := true;
            setverdict(pass);
          }
          [] tc_ac.timeout {
            setverdict(fail, "Expected message not received1");
          }
        }
                
        unmap(self:denmPort, system:denmPort);
	
      } // End of testcase tc_Denm_Port
            
      /**
       * @desc Generate DENM according to the DENM port settings
       * @verdict Pass on success, Fail otherwise
       */
      testcase tc_Denm_Port_1() runs on ItsDenm system ItsDenmSystem {
        var DenmReq v_denmReq;
        var template (value) SituationContainer v_situation := m_situation(LibItsCommon_ASN1_NamedNumbers.CauseCodeType_vehicleBreakdown_, LibItsCommon_ASN1_NamedNumbers.VehicleBreakdownSubCauseCode_unavailable_);
        timer tc_send := 0.5;
        
        map(self:denmPort, system:denmPort);
        
      v_denmReq := valueof(
                           m_denmReq(
                                     m_denmPdu(
                                               m_denm(
                                                      m_denmMgmtCon(
                                                                    m_tsActionId,
                                                                    -, -, -,
                                                                    f_getCurrentTime(),
                                                                    f_getCurrentTime()
                                                                    ),
                                                      v_situation,
                                                      m_denmLocation_zeroDelta
                                                      ))
                                     )
                           );
        denmPort.send(v_denmReq);
        tc_ac.start;
        tc_send.start;
        alt {
          [] tc_send.timeout {
      v_denmReq := valueof(
                           m_denmReq(
                                     m_denmPdu(
                                               m_denm(
                                                      m_denmMgmtCon(
                                                                    m_tsActionId,
                                                                    -, -, -,
                                                                    f_getCurrentTime(),
                                                                    f_getCurrentTime()
                                                                    ),
                                                      v_situation,
                                                      m_denmLocation_zeroDelta
                                                      ))
                                     )
                           );
            denmPort.send(v_denmReq);
            tc_send.start;
            repeat;
          }
          [] tc_ac.timeout {
            tc_send.stop;
            setverdict(pass);
          }
        }
                
        unmap(self:denmPort, system:denmPort);
        
      } // End of testcase tc_Denm_Port_1
            
      /**
       * @desc validate DenmReq
       * @verdict Pass on success, Fail otherwise
       */
      testcase tc_Denm_Port_utPort() runs on ItsDenm system ItsDenmSystem {
        var DenmReq v_denmReq;
        var template (value) SituationContainer v_situation := m_situation(LibItsCommon_ASN1_NamedNumbers.CauseCodeType_vehicleBreakdown_, LibItsCommon_ASN1_NamedNumbers.VehicleBreakdownSubCauseCode_unavailable_);
	
	
        map(self:utPort, system:utPort);
        map(self:denmPort, system:denmPort);
        
        f_utInitializeIut(m_denmInitialize);
                
      v_denmReq := valueof(
                           m_denmReq(
                                     m_denmPdu(
                                               m_denm(
                                                      m_denmMgmtCon(
                                                                    m_tsActionId,
                                                                    -, -, -,
                                                                    f_getCurrentTime(),
                                                                    f_getCurrentTime()
                                                                    ),
                                                      v_situation,
                                                      m_denmLocation_zeroDelta
                                                      ))
                                     )
                           );
        denmPort.send(v_denmReq);
        tc_ac.start;
        alt {
          [] denmPort.receive(DenmInd : ?) {
            setverdict(pass);
          }
          [] tc_ac.timeout {
            setverdict(fail, "Expected message not received1");
          }
        }
                
        unmap(self:denmPort, system:denmPort);
        unmap(self:utPort, system:utPort);
	
      } // End of testcase tc_Denm_Port_utPort
            
    } // End of group testDenmPort 
        
  } // End of group LibItsDenm_testCases
    
  group encdec_functions {
        
    function TestDenmReq(
                         in template (value) DenmReq p_denmReq,
                         in boolean p_decode := true, 
                         in template (omit) bitstring p_expEncMsg := omit 
                         ) runs on TCType {
      var bitstring v_encMsg;
      var template (omit) TestRecord v_tr := { bs := p_expEncMsg };
      var DenmReq v_decMsg;
      var integer v_res := 0;
    
      // Encode template
      log("Encode template ", valueof(p_denmReq));
    v_encMsg := encvalue(p_denmReq);
      log("Encoded message:  ", bit2oct(v_encMsg));
      // Check result
      if (not isbound(v_encMsg)) {
        setverdict(fail, "Encoding failed!");
        stop;
      }
      if (ispresent(v_tr.bs)) {
        if (not match(v_encMsg, p_expEncMsg)) {
          log("Expected message: ", bit2oct(valueof(p_expEncMsg)));
          setverdict(fail, "Encoding failed, not the expected result!");
          stop;
        }
      }
      setverdict(pass, "Encoding passed.");
    
      // Check decoding
      if (p_decode == true) {
        v_res := decvalue(v_encMsg, v_decMsg);
        log("Decoded message: ", v_decMsg);
        select (v_res) {
        case (0) {
          if(match(v_decMsg, p_denmReq)) {
            setverdict(pass);
          } else {
            setverdict(fail);
          }
        }
        case (1) {
          setverdict(fail, "Decoding failed.");
        }
        case (2) {
          setverdict(fail, "Not enough bits.");
        }
        }
      }
      
    } // End of function TestDenmReq
    
    function TestDenmInd(
                         in template DenmInd p_camInd,
                         in octetstring p_expEncMsg 
                         ) runs on TCType {
      var bitstring v_encMsg := oct2bit(p_expEncMsg);
      var DenmInd v_decMsg;
      var integer v_res := 0;
      
      // Check decoding
      v_res := decvalue(v_encMsg, v_decMsg);
      select (v_res) {
      case (0) {
        log("v_decMsg: ", v_decMsg);
        if(match(valueof(v_decMsg), p_camInd)) {
          setverdict(pass);
        } else {
          setverdict(fail);
        }
      }
      case (1) {
        setverdict(fail, "Decoding failed.");
      }
      case (2) {
        setverdict(fail, "Not enough bits.");
      }
      } // End of 'select' statement
      
    } // End of function TestDenmInd
    
  } // End of group encdec_functions
  
  control {
    execute(tc_DenmReq());
    execute(tc_DenmInd());
    execute(tc_Denm_Port());
    execute(tc_Denm_Port_utPort());
    execute(tc_Denm_UtDenmInitialize());
    execute(tc_Denm_UtDenmChangePosition());
    execute(tc_Denm_UtDenmChangePseudonym());
    execute(tc_Denm_UtDenmTrigger_1());
    execute(tc_Denm_UtDenmTrigger_2());
    execute(tc_Denm_UtDenmUpdate_1());
    execute(tc_Denm_UtDenmUpdate_2());
    execute(tc_Denm_UtDenmEventInd_1());
    execute(tc_Denm_UtDenmEventInd_2());
    execute(tc_Denm_UtDenmTriggerResult());
    execute(tc_Denm_UtDenmUpdateResult());
  }
  
} // End of module TestCodec_DENM 
