module TestCodec_Btp {

  // LibCommon
  import from LibCommon_BasicTypesAndValues all;
  import from LibCommon_DataStrings all;

  // LibItsBtp
  import from LibItsBtp_TypesAndValues all;
  import from LibItsBtp_Templates all;
  import from LibItsBtp_TestSystem all;
  import from LibItsBtp_EncdecDeclarations all;

  // TestCodec
  import from TestCodec_TestAndSystem all;

  group LibItsBtp_testCases {

    group LibItsBtp_DummyTemplates {

      template (value) BtpPacket m_btpA_Without_Payload (
							 template (value) BtpPortId  p_destPort,
							 template (value) BtpPortId  p_sourcePort
							 ):= {
      header := { 
	btpAHeader := {
	  destinationPort := p_destPort, 
	  sourcePort := p_sourcePort
	}
      }, 
      payload := omit 
      }

      template BtpPacket m_btpA_With_Payload ( 
					      in template (value) BtpPortId  p_destPort, 
					      in template (value) BtpPortId  p_sourcePort, 
					      in template BtpRawPayload p_rawPayload 
					       ) := { 
      header := { 
	btpAHeader := {
	  destinationPort := p_destPort, 
	  sourcePort := p_sourcePort
	}
      }, 
      payload :=p_rawPayload
      }

      template BtpPacket mw_btpA_With_Payload ( 
					       in template (present) BtpPortId  p_destPort, 
					       in template (present) BtpPortId  p_sourcePort, 
					       in template BtpRawPayload p_rawPayload 
						) := { 
      header := { 
	btpAHeader := {
	  destinationPort := p_destPort, 
	  sourcePort := p_sourcePort
	}
      }, 
      payload := p_rawPayload
      }

      template (value) BtpPacket m_btpB_Without_Payload (
							 template (value) BtpPortId  p_destPort,
							 template (value) BtpPortId  p_destinationPortInfo
							 ):= {
      header := { 
	btpBHeader := {
	  destinationPort := p_destPort, 
	  destinationPortInfo := p_destinationPortInfo
	}
      }, 
      payload := omit
      }

      template BtpPacket m_btpB_With_Payload ( 
					       in template (value) BtpPortId  p_destPort, 
					       in template (value) BtpPortId  p_destinationPortInfo, 
					       in template (value) BtpRawPayload p_rawPayload 
						) := { 
      header := { 
	btpBHeader := {
	  destinationPort := p_destPort, 
	  destinationPortInfo := p_destinationPortInfo
	}
      }, 
      payload := p_rawPayload
      }

    } // End of group LibItsBtp_DummyTemplates

    group LibItsBtp_testCases {

      testcase tc_Btp_A_Without_Payload() runs on TCType system TCType {
	TestBtpPacket(
		      m_btpA_Without_Payload ( 
					   1234,
					   0 
					    ),
		      true,
		      oct2bit('04D20000'O)
		      );
      }
	
      testcase tc_Btp_A() runs on TCType system TCType {
	TestBtpPacket(
		      m_btpA_With_Payload ( 
					   1234,
					   0,
					   'CAFEDECA'O 
					    ),
		      true,
		      oct2bit('04D20000CAFEDECA'O)
		      );
      }
	
      testcase tc_Btp_B() runs on TCType system TCType {
	TestBtpPacket(
		      m_btpB_With_Payload ( 
					   1234,
					   4567,
					   'CAFEDECA'O 
					    ),
		      true,
		      oct2bit('04D211D7CAFEDECA'O)
		      );
      }
	
      testcase tc_BtpReq_A() runs on TCType system TCType {
	TestBtpReq(
		   BtpReq:{msgOut := m_btpA_With_Payload ( 
							  1234,
							  0,
							  'CAFEDECA'O 
							   )
		     },
		   true,
		   oct2bit('04D20000CAFEDECA'O)
		   );
      }
	
	/*testcase tc_Btp_A() runs on TCType system TCType {
	TestBtpPacket(
		      m_btpA (
			      BtpPayload:{decodedPayload := omit, rawPayload := '0102030405'O } ), 
		      true, 
		      oct2bit('000000000102030405'O));
		      }}*/

    } // End of group LibItsBtp_testCases

    group testBtpPort {
            
      /**
       * @desc validate BtpReq
       * @verdict Pass on success, Fail otherwise
       */
      testcase tc_Btp_Port() runs on ItsBtp system ItsBtpSystem {
	var BtpReq v_btpReq;
	
	map(self:btpPort, system:btpPort);
        
      v_btpReq := valueof(
			  BtpReq : { msgOut := m_btpA_With_Payload ( 
								 1234,
								 0,
								 'CAFEDECA'O 
								  )
			    }
			  );                
	btpPort.send(v_btpReq);
	tc_ac.start;
	alt {
	  [] btpPort.receive(BtpInd : { msgIn := ? }) {
	    setverdict(pass);
	  }
	  [] tc_ac.timeout {
	    setverdict(fail, "Expected message not received1");
	  }
	}
                
	unmap(self:btpPort, system:btpPort);
                
      }
            
    } // End of group testBtpPort 
        
  } // End of group LibItsBtp_testCases

  group encdec_functions {

    function TestBtpPacket(
			   in template (value) BtpPacket p_btpPacket,
			   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 BtpPacket v_decMsg;
      var integer v_res := 0;

      // Encode template
      log("Encode template ", valueof(p_btpPacket));
    v_encMsg := encvalue(p_btpPacket);
      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_btpPacket)) {
	    setverdict(pass);
	  } else {
	    setverdict(fail);
	  }
	}
	case (1) {
	  setverdict(fail, "Decoding failed.");
	}
	case (2) {
	  setverdict(fail, "Not enough bits.");
	}
	}
      }

    } // End of function TestBtpPacket

    function TestBtpReq(
			in template (value) BtpReq p_btpReq,
			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 BtpReq v_decMsg;
      var integer v_res := 0;

      // Encode template
      log("Encode template ", valueof(p_btpReq));
    v_encMsg := encvalue(p_btpReq);
      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_btpReq)) {
	    setverdict(pass);
	  } else {
	    setverdict(fail);
	  }
	}
	case (1) {
	  setverdict(fail, "Decoding failed.");
	}
	case (2) {
	  setverdict(fail, "Not enough bits.");
	}
	}
      }

    } // End of function TestBtpReq

    function TestBtpInd(
			in template (value) BtpInd p_btpInd,
			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 BtpInd v_decMsg;
      var integer v_res := 0;

      // Encode template
      log("Encode template ", valueof(p_btpInd));
    v_encMsg := encvalue(p_btpInd);
      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_btpInd)) {
	    setverdict(pass);
	  } else {
	    setverdict(fail);
	  }
	}
	case (1) {
	  setverdict(fail, "Decoding failed.");
	}
	case (2) {
	  setverdict(fail, "Not enough bits.");
	}
	}
      }

    } // End of function TestBtpInd

  } // End of group encdec_functions 

} // End of module TestCodec_Btp
