#pragma once

#include "codec.hh"
#include "params.hh"

class Base_Type;
class TTCN_Typedescriptor_t;
class TTCN_Buffer;

namespace LibItsGeoNetworking__TypesAndValues {
  class GeoNetworkingPdu;
  class GnNonSecuredPacket;
  class HeaderTST;
  class ExtendedHeader;
  class DecodedPayload;
};

namespace LibItsSecurity__TypesAndValues {
  class SecuredMessage;
};

struct encoding_context {
  unsigned char basic_header;
  unsigned char next_header;
  unsigned char header_type;
  unsigned int  length_position;
  unsigned int  length;

  encoding_context() { reset(); }
  void reset() { basic_header = 0xff; next_header = 0xff; header_type = 0xff; length_position = -1; length = -1; }
};
//typedef struct encoding_context encoding_context;

struct decoding_context {
  unsigned char              next_header;
  unsigned char              header_type;
  unsigned char              header_sub_type;
  unsigned char              traffic_class;
  unsigned int               lifetime;
  unsigned int               length;
  std::string                payload;

  decoding_context() : payload() { reset(); }
  void reset() { next_header = 0xff; header_type = 0xff; header_sub_type = 0xff; lifetime = 0; length = -1; payload.clear(); }
};
//typedef struct decoding_context decoding_context;

class geonetworking_codec : public codec<LibItsGeoNetworking__TypesAndValues::GeoNetworkingPdu, LibItsGeoNetworking__TypesAndValues::GeoNetworkingPdu> {

  encoding_context _ec;
  decoding_context _dc;

  int encode_ (const Base_Type& type, const TTCN_Typedescriptor_t& field_descriptor, TTCN_Buffer& encoding_buffer);
  int encode_extendedHeader(const LibItsGeoNetworking__TypesAndValues::ExtendedHeader& u, TTCN_Buffer& encoding_buffer);

  int decode_ (Base_Type& type, const TTCN_Typedescriptor_t& field_descriptor, TTCN_Buffer& decoding_buffer);
  int decode_headerTST(LibItsGeoNetworking__TypesAndValues::HeaderTST& u, TTCN_Buffer& decoding_buffer);
  int decode_extendedHeader(LibItsGeoNetworking__TypesAndValues::ExtendedHeader& u, TTCN_Buffer& decodin_buffer);

public:
  explicit geonetworking_codec() : codec<LibItsGeoNetworking__TypesAndValues::GeoNetworkingPdu, LibItsGeoNetworking__TypesAndValues::GeoNetworkingPdu>(), _ec(), _dc() { };
  virtual ~geonetworking_codec() { };
  
  virtual int encode (const LibItsGeoNetworking__TypesAndValues::GeoNetworkingPdu& msg, OCTETSTRING& data);
  virtual int decode (const OCTETSTRING& data, LibItsGeoNetworking__TypesAndValues::GeoNetworkingPdu& msg, params* params = NULL);
  
  int encode (const LibItsGeoNetworking__TypesAndValues::GnNonSecuredPacket& p_gnNonSecuredPacket, OCTETSTRING& data); // TODO Duplicate code with virtual encode, to be enhanced
}; // End of class geonetworking_codec
