/******************************************************************************
 * Copyright (c) 2000-2021 Ericsson Telecom AB
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
 *
 * Contributors:
 *   Balasko, Jeno
 *   Szabados, Kristof
 *
 ******************************************************************************/
module TimplicitEnc
{
  type record MyPDU {
    integer i,
    float f
  } with { encode "RAW"; variant "" }

  type record Errorneous_PDU {
     integer fi optional,
     octetstring fo optional
  }
  with {
     encode "RAW";
     variant (fo) "PRESENCE(fi=1)"
  };


  type port PCOType message
  {
    inout octetstring;
    inout charstring;
  }
  with
  {
    extension "provider"
  }

  type boolean Bool with { encode "TEXT" variant "TEXT_CODING(length=5)" }

  function f_encode_int(in integer i, out charstring cs)
  {
    cs := int2str(i);
  }
  with
  {
    extension "prototype(fast)"
  }

  function f_encode_float(in float f) return charstring
  {
    return float2str(f);
  }
  with
  {
    extension "prototype(convert)"
  }

  type port UserPort message
  {
    inout charstring;
    inout MyPDU;
    out integer, boolean, float, bitstring, octetstring;
  }
  with
  {
    extension "user PCOType
      in  ( charstring  -> charstring : simple;
            octetstring -> MyPDU : decode(RAW) errorbehavior(ALL:WARNING),
                           - : discard )
      out ( charstring  -> charstring : simple;
            integer     -> charstring : function(f_encode_int);
            Bool        -> charstring : encode(TEXT);
            float       -> charstring : function(f_encode_float);
            octetstring -> -:discard;
            MyPDU       -> octetstring : encode(RAW);
            bitstring   -> charstring : function(f_encode_bitstr)
      )"
  }

  type port UserPort2 message
  {
    inout charstring;
    out Errorneous_PDU, octetstring;
  }
  with
  {
    extension "user PCOType
      in  ( charstring     -> charstring : simple;
            octetstring -> - : discard )
      out ( charstring     -> charstring : simple;
            octetstring    -> - : discard;
            Errorneous_PDU -> octetstring : encode(RAW) errorbehavior (ALL:WARNING)
      )"
  }


  function f_encode_bitstr(in bitstring bs := ''B) return charstring
  {
    return "Bit string = " & bit2str(bs);
  }
  with
  {
    extension "prototype(convert)"
  }

  type component MTCType
  {
    port PCOType MyPCO;
  }

  type component MyComp extends MTCType
  {
    port UserPort P;
  }

  type component MyComp2 extends MTCType
  {
    port UserPort2 P2;
  }

  external function decode_MyPDU(in octetstring os, out MyPDU pdu) return integer
  with {
  extension "prototype(backtrack)"
  extension "decode(RAW)"
  extension "errorbehavior(ALL:WARNING)"
  }


  function f_PReceiveCharstring(charstring p_message, float p_time) runs on MyComp
  {
  	timer t := p_time;

  	t.start;

	alt
	{
  	[] P.receive(p_message)
  	  {
  	   t.stop;
  	   setverdict(pass);
  	  }
  	[] P.receive
  	  {
  	   t.stop;
  	   setverdict(fail);
  	  }
  	[] t.timeout
  	  {
  	  	setverdict(fail);
  	  }
  	}
  }

  function f_PReceiveNone(float p_time) runs on MyComp
  {
  	timer t := p_time;
  	t.start;

  	alt{
    [] P.receive
      {
      	t.stop;
      	setverdict(fail);
      }
    [] t.timeout
      {
        setverdict(pass);
      }
    }
  }

  testcase ImplicitMsgEnc1() runs on MyComp system MTCType
  {
    var MyPDU mypdu := {i := 10, f := 3.14};

    map(mtc:P, system:MyPCO);

    //the TLV of first octetstring has error -> the
    //octetstring needs to be discarded.
    //see user_map for more details
    f_PReceiveNone(1.0);

    P.send("Hello, world!");
    f_PReceiveCharstring("Hello, world!", 1.0);
    P.send(123);
    f_PReceiveCharstring("123", 1.0);
    P.send(false);
    f_PReceiveCharstring("false", 1.0);
    P.send(true);
    f_PReceiveCharstring("true", 1.0);
    P.send(3.14);
    f_PReceiveCharstring("3.140000", 1.0);
    P.send(mypdu);
    P.receive(MyPDU: ?) -> value mypdu;



   //octetstring to send must be discarded
    P.send('ABCDEF'O);
    f_PReceiveNone(1.0);

    P.send('1010101010'B);
    f_PReceiveCharstring("Bit string = 1010101010", 1.0);

//	f_PReceiveCharstring("Hello, TTCN-3!", 4.0);

    unmap(mtc:P, system:MyPCO);
  }

  testcase ImplicitMsgEnc2() runs on MyComp2 system MTCType
  {
    var Errorneous_PDU myErrPDU := {fi := omit, fo := 'AA'O};
    timer t := 1.0;

    map(mtc:P2, system:MyPCO);

    P2.send(myErrPDU);
    t.start;
    alt{
      [] P2.receive {t.stop; setverdict(fail);}
      [] t.timeout {setverdict(pass)}
    }

    unmap(mtc:P2, system:MyPCO);
  }

  control
  {
    execute(ImplicitMsgEnc1());
    execute(ImplicitMsgEnc2());
  }
}
