#include "LibSip_SIPTypesAndValues.hh"
#include "LibSip_Common.hh"

#include "sip_codec_message_body.hh"
#include "loggers.hh"

#include "converter.hh"

#include "urn_ietf_params_xml_ns_pidf.hh"

#ifdef WIN32
#undef osip_malloc
#undef osip_free
#define osip_malloc(S) malloc(S)
#define osip_free(P) { if (P!=NULL) { free(P);} }
#endif

int sip_codec_message_body::encode (const LibSip__MessageBodyTypes::MessageBody& msg, OCTETSTRING& data)
{
  loggers::get_instance().log_msg(">>> sip_codec_message_body::encode: ", msg);

  TRACE_INITIALIZE(TRACE_LEVEL7, NULL);
  OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, ">>> sip_codec_request::encode\n"));

  if (msg.ischosen(LibSip__MessageBodyTypes::MessageBody::ALT_sdpMessageBody)) {
    const LibSip__SDPTypes::SDP__Message& sdp = msg.sdpMessageBody();
    sdp_message_t* sdp_body = nullptr;
    if (encode_sdp(sdp, &sdp_body) == -1) {
      loggers::get_instance().warning("sip_codec_message_body::encode: Failed to encode SDP message");
      return -1;
    }
    char* buff = nullptr;
    ::sdp_message_to_str(sdp_body, &buff);
    if (buff != nullptr) {
      data = char2oct(CHARSTRING(buff));
      osip_free(buff);
      sdp_message_free(sdp_body);
    }
  } else if (msg.ischosen(LibSip__MessageBodyTypes::MessageBody::ALT_textplain)) {
    data = char2oct(msg.textplain());
  } else {
    loggers::get_instance().warning("sip_codec_message_body::encode: Unsupported variant");
    return -1;
  }

  loggers::get_instance().log_msg("<<< sip_codec_message_body::encode: ", data);
  return 0;
}

int sip_codec_message_body::decode (const OCTETSTRING& data, LibSip__MessageBodyTypes::MessageBody& msg, params* p_params)
{
  loggers::get_instance().log(">>> sip_codec_message_body::decode");

  TRACE_INITIALIZE(TRACE_LEVEL7, NULL);
  OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, ">>> sip_codec_request::decode\n"));
  loggers::get_instance().error("sip_codec_message_body::decode: Not implemented yet");
  return -1;
}

int sip_codec_message_body::encode_message_body(const LibSip__MessageBodyTypes::MessageBody& p_message_body, osip_message_t* p_sip_message)
{ // TODO Rename into encode_message
  loggers::get_instance().log_msg(">>> sip_codec_message_body::encode_message_body: ", p_message_body);

  osip_content_length* content_length = ::osip_message_get_content_length(p_sip_message);
  loggers::get_instance().log("sip_codec_message_body::encode_message_body: content_length= %s", content_length->value);
  if (p_message_body.ischosen(LibSip__MessageBodyTypes::MessageBody::ALT_sdpMessageBody)) {
    const LibSip__SDPTypes::SDP__Message& sdp = p_message_body.sdpMessageBody();
    sdp_message_t* sdp_body = nullptr;
    if (encode_sdp(sdp, &sdp_body) == -1) {
      loggers::get_instance().warning("sip_codec_message_body::encode_message_body: Failed to decode SDP message");
      return -1;
    }
    char* buff = nullptr;
    ::sdp_message_to_str(sdp_body, &buff);
    if (buff != nullptr) {
      ::osip_message_set_body(p_sip_message, buff, strlen(buff));
      osip_free(buff);
      sdp_message_free(sdp_body);
    }
  } else if (p_message_body.ischosen(LibSip__MessageBodyTypes::MessageBody::ALT_textplain)) {
    const CHARSTRING& text = p_message_body.textplain();
    ::osip_message_set_body(p_sip_message, static_cast<const char*>(text), text.lengthof());
  } else if (p_message_body.ischosen(LibSip__MessageBodyTypes::MessageBody::ALT_mimeMessageBody)) {
    ::osip_message_set_mime_version(p_sip_message, "2.0");
    const LibSip__MessageBodyTypes::MIME__Message& mime = p_message_body.mimeMessageBody();
    const LibSip__MessageBodyTypes::MimeEncapsulatedList& l = mime.mimeEncapsulatedList();
    int pos = 0;
    while (pos < l.lengthof()) {
      const LibSip__MessageBodyTypes::MIME__Encapsulated__Part& p = l[pos];
      loggers::get_instance().log_msg("sip_codec_message_body::encode_message_body: p: ", p);
      const LibSip__MessageBodyTypes::MIME__Encapsulated__Parts& ps = p.mime__encapsulated__part();
      if (ps.ischosen(LibSip__MessageBodyTypes::MIME__Encapsulated__Parts::ALT_sdpMessageBody)) {
        const LibSip__SDPTypes::SDP__Message& sdp = ps.sdpMessageBody();
        sdp_message_t* sdp_body = nullptr;
        if (encode_sdp(sdp, &sdp_body) == -1) {
          loggers::get_instance().warning("sip_codec_message_body::encode_message_body: Failed to encode SDP message");
          return -1;
        }
        char* buff = nullptr;
        ::sdp_message_to_str(sdp_body, &buff);
        if (buff != nullptr) {
          loggers::get_instance().log("sip_codec_message_body::encode_message_body: sdp encoded value: %s", buff);
          loggers::get_instance().log("sip_codec_message_body::encode_message_body: body list size: %d", ::osip_list_size(&p_sip_message->bodies));
          if (::osip_message_set_body(p_sip_message, buff, strlen(buff)) != 0) {
            loggers::get_instance().warning("sip_codec_message_body::encode_message_body: Failed to encode SDP message");
            osip_free(buff);
            sdp_message_free(sdp_body);
            return -1;
          }
          loggers::get_instance().log("sip_codec_message_body::encode_message_body: new body list size: %d", ::osip_list_size(&p_sip_message->bodies));
          osip_free(buff);
          sdp_message_free(sdp_body);
          // Retrive the new created body and add content type
          osip_body_t* body = nullptr;
          if (::osip_message_get_body(p_sip_message, ::osip_list_size(&p_sip_message->bodies) - 1, &body) != ::osip_list_size(&p_sip_message->bodies) - 1) {
            loggers::get_instance().warning("sip_codec_message_body::encode_message_body: Failed to set XML body content-type");
            return -1;
          }
          const char* ct = static_cast<const char*>(p.content__type());
          loggers::get_instance().log("sip_codec_message_body::encode_message_body: content-type: %s", ct);
          if (ct != nullptr) {
            ::osip_body_set_contenttype(body, ct);
          } else { // Use a default value
            ::osip_body_set_contenttype(body, "application/sdp");
          }
        }
      } else if (ps.ischosen(LibSip__MessageBodyTypes::MIME__Encapsulated__Parts::ALT_xmlBody)) {
        const LibSip__XMLTypes::XmlBody& xml = ps.xmlBody();
        osip_body_t* body;
        if (encode_xml(xml, &body) == -1) {
          loggers::get_instance().warning("sip_codec_message_body::encode_message_body: Failed to encode XML message");
          return -1;
        }
        loggers::get_instance().log("sip_codec_message_body::encode_message_body: xml encoded value: %s", body->body);
        loggers::get_instance().log("sip_codec_message_body::encode_message_body: body list size: %d", ::osip_list_size(&p_sip_message->bodies));
        if (::osip_message_set_body(p_sip_message, body->body, body->length) != 0) {
          loggers::get_instance().warning("sip_codec_message_body::encode_message_body: Failed to encode XML message");
          osip_body_free(body);
          return -1;
        }
        loggers::get_instance().log("sip_codec_message_body::encode_message_body: new body list size: %d", ::osip_list_size(&p_sip_message->bodies));
        osip_body_free(body);
        // Retrive the new created body and add content type
        body = nullptr;
        loggers::get_instance().log("sip_codec_message_body::encode_message_body: get item #%d", ::osip_list_size(&p_sip_message->bodies) - 1);
        if (::osip_message_get_body(p_sip_message, ::osip_list_size(&p_sip_message->bodies) - 1, &body) != ::osip_list_size(&p_sip_message->bodies) - 1) {
          loggers::get_instance().warning("sip_codec_message_body::encode_message_body: Failed to set content-type");
          return -1;
        }
        const char* ct = static_cast<const char*>(p.content__type());
        loggers::get_instance().log("sip_codec_message_body::encode_message_body: content-type: %s", ct);
        if (ct != nullptr) {
          ::osip_body_set_contenttype(body, ct);
        } else { // Use a default value
          ::osip_body_set_contenttype(body, "application/resource-lists+xml");
        }
      } else if (ps.ischosen(LibSip__MessageBodyTypes::MIME__Encapsulated__Parts::ALT_msdBody)) {
        loggers::get_instance().warning("sip_codec_message_body::encode_message_body: Unsupported decoding of ALT_msdBody");
      } else {
        loggers::get_instance().warning("sip_codec_message_body::encode_message_body: Unsupported decoding of encapulated parts");
      }
      pos += 1;
    } // End of 'while' statement
  } else {
    loggers::get_instance().warning("sip_codec_message_body::encode_message_body: Unsupported variant");
    return -1;
  }
  
  return 0;
} // End of method encode_message_body

int sip_codec_message_body::encode_sdp(const LibSip__SDPTypes::SDP__Message& p_sdp_message, sdp_message_t** p_sdp_body) {
  loggers::get_instance().log_msg(">>> sip_codec_message_body::encode_sdp: ", p_sdp_message);

  ::sdp_message_init(p_sdp_body);

  // Encode mandatory fields
  // Version
  INTEGER version = p_sdp_message.protocol__version();
  ::sdp_message_v_version_set(*p_sdp_body, (char*)::strdup(std::to_string(static_cast<const int>(version)).c_str()));
  LibSip__SDPTypes::SDP__Origin origin = p_sdp_message.origin();
  // Origin
  loggers::get_instance().log_msg("sip_codec_message_body::encode_sdp: origin: ", origin);
  ::sdp_message_o_origin_set(
                             *p_sdp_body,
                             (char*)::strdup(static_cast<const char*>(origin.user__name())),
                             (char*)::strdup(static_cast<const char*>(origin.session__id())),
                             (char*)::strdup(static_cast<const char*>(origin.session__version())),
                             (char*)::strdup(static_cast<const char*>(origin.net__type())),
                             (char*)::strdup(static_cast<const char*>(origin.addr__type())),
                             (char*)::strdup(static_cast<const char*>(origin.addr()))
                             );
  // Session name
  ::sdp_message_s_name_set(*p_sdp_body, (char*)::strdup(static_cast<const char*>(p_sdp_message.session__name())));
  // Time, t
  ::sdp_message_s_name_set(*p_sdp_body, (char*)::strdup(static_cast<const char*>(p_sdp_message.session__name())));
  loggers::get_instance().log_msg("sip_codec_message_body::encode_sdp: times: ", p_sdp_message.times());
  for (int i = 0; i < p_sdp_message.times().lengthof(); i++) {
    const LibSip__SDPTypes::SDP__time& time = p_sdp_message.times()[i];
    loggers::get_instance().log_msg("sip_codec_message_body::encode_sdp: time: ", time);
    ::sdp_message_t_time_descr_add(*p_sdp_body, (char*)::strdup(static_cast<const char*>(time.time__field().start__time())), (char*)::strdup(static_cast<const char*>(time.time__field().stop__time())));
    if (time.time__repeat().is_present()) {
      const LibSip__SDPTypes::SDP__repeat__list& l = static_cast<const OPTIONAL<LibSip__SDPTypes::SDP__repeat__list>&>(*time.time__repeat().get_opt_value());
      loggers::get_instance().log_msg("sip_codec_message_body::encode_sdp: l: ", l);
      for (int j = 0; j < l.lengthof(); j++) {
        const LibSip__SDPTypes::SDP__repeat& r = l[j];
        // TODO            r.repeat__interval();
        // TODO            r.active();
        for (int k = 0; k < r.offsets().lengthof(); k++) {
      	const LibSip__SDPTypes::SDP__typed__time& s = r.offsets()[k];
      	// TODO              ::sdp_message_r_repeat_add(p_sdp_body, k, char *value);
        } // End of 'for' statement
        // TODO        ::sdp_message_r_repeat_add(p_sdp_body, int pos_time_descr, char *value)
      } // End of 'for' statement
    }
  } // End of 'for' statement
  // Encode optional fields
  // email, e
  loggers::get_instance().log_msg("sip_codec_message_body::encode_sdp: emails: ", p_sdp_message.emails());
  if (p_sdp_message.emails().is_present()) {
    const LibSip__SDPTypes::SDP__email__list& l = static_cast<const LibSip__SDPTypes::SDP__email__list&>(*p_sdp_message.emails().get_opt_value());
    for (int j = 0; j < l.lengthof(); j++) {
      const LibSip__SDPTypes::SDP__contact& e = l[j];
      std::string str;
      if (e.disp__name().is_present()) {
        str = static_cast<const char*>(static_cast<const CHARSTRING&>(*e.disp__name().get_opt_value()));
        str += " ";
      }
      str += static_cast<const char*>(e.addr__or__phone());
      ::sdp_message_e_email_add(*p_sdp_body, ::strdup(str.c_str()));
    } // End of 'for' statement
  }
  // Information, i
  loggers::get_instance().log_msg("sip_codec_message_body::encode_sdp: information: ", p_sdp_message.information());
  if (p_sdp_message.information().is_present()) {
    ::sdp_message_i_info_set(*p_sdp_body, 0, ::strdup(static_cast<const CHARSTRING&>(*p_sdp_message.information().get_opt_value())));
  }
  // Media list, m
  loggers::get_instance().log_msg("sip_codec_message_body::encode_sdp: medias: ", p_sdp_message.media__list());
  if (p_sdp_message.media__list().is_present()) {
    const LibSip__SDPTypes::SDP__media__desc__list& l = static_cast<const LibSip__SDPTypes::SDP__media__desc__list&>(*p_sdp_message.media__list().get_opt_value());
    int i = 0;
    for ( ; i < l.lengthof(); i++) {
      const LibSip__SDPTypes::SDP__media__desc m = l[i];
      loggers::get_instance().log_msg("sip_codec_message_body::encode_sdp: media: ", m);
      // Media field
      if (m.media__field().ports().num__of__ports().is_present()) {
        int p = static_cast<const INTEGER&>(*m.media__field().ports().num__of__ports().get_opt_value());
        ::sdp_message_m_media_add(*p_sdp_body, (char*)::strdup(static_cast<const char*>(m.media__field().media())), (char*)::strdup(std::to_string(m.media__field().ports().port__number()).c_str()), (char*)::strdup(std::to_string(p).c_str()), (char*)::strdup(static_cast<const char*>(m.media__field().transport())));
      } else {
        ::sdp_message_m_media_add(*p_sdp_body, (char*)::strdup(static_cast<const char*>(m.media__field().media())), (char*)::strdup(std::to_string(m.media__field().ports().port__number()).c_str()), NULL, (char*)::strdup(static_cast<const char*>(m.media__field().transport())));
      }
      // Format list
      const LibSip__SDPTypes::SDP__fmt__list& fmts = m.media__field().fmts();
      std::string str;
      for (int j = 0; j < fmts.lengthof() - 1; j++) {
        str += static_cast<const char*>(fmts[j]);
        str += " ";
      } // End of 'for' statement
      str += static_cast<const char*>(fmts[fmts.lengthof() - 1]);
      // information
      if (m.information().is_present()) {
        str += " ";
        str += static_cast<const char*>(static_cast<const CHARSTRING&>(*m.information().get_opt_value()));
      }
      if (str.length() != 0) {
        ::sdp_message_m_payload_add(*p_sdp_body, i, (char*)::strdup(str.c_str()));
      }
      // Attribute list, a
      loggers::get_instance().log_msg("sip_codec_message_body::encode_sdp: attributes: ", m.attributes());
      if (m.attributes().is_present()) {
        const LibSip__SDPTypes::SDP__attribute__list& al = static_cast<const LibSip__SDPTypes::SDP__attribute__list&>(*m.attributes().get_opt_value());
        for (int k = 0; k < al.lengthof(); k++) {
          const LibSip__SDPTypes::SDP__attribute a = al[k];
          loggers::get_instance().log_msg("sip_codec_message_body::encode_sdp: attribute: ", a);
          if (a.ischosen(LibSip__SDPTypes::SDP__attribute::ALT_rtpmap)) {
            std::string str(static_cast<const char*>(a.rtpmap().payload__type()));
            str += " ";
            str += static_cast<const char*>(a.rtpmap().codec().encoding());
            str += "/";
            str += a.rtpmap().codec().clockrate();
            if (a.rtpmap().codec().parameters().is_present()) {
              str += "/";
              str += static_cast<const char*>(static_cast<const CHARSTRING&>(*a.rtpmap().codec().parameters().get_opt_value()));
            }
            loggers::get_instance().log("sip_codec_message_body::encode_sdp: attribute: media #%d: encode rtpmap:%s", i, str.c_str());
            ::sdp_message_a_attribute_add(*p_sdp_body, i, (char*)::strdup("rtpmap"), (char*)::strdup(str.c_str()));
          } else if (a.ischosen(LibSip__SDPTypes::SDP__attribute::ALT_fmtp)) {
            std::string str(static_cast<const char*>(a.fmtp().format()));
            str += " ";
            if (a.fmtp().params().ischosen(LibSip__SDPTypes::SDP__attribute__fmtp__format__specific__params::ALT_paramList)) {
              const LibSip__Common::SemicolonParam__List& sl = a.fmtp().params().paramList();
              for (int k = 0; k < sl.lengthof(); k++) {
                str += static_cast<const char*>(sl[k].id());
                if (sl[k].paramValue().is_present()) {
                  const LibSip__Common::GenValue& v = static_cast<const LibSip__Common::GenValue&>(*sl[k].paramValue().get_opt_value());
                  loggers::get_instance().log_msg("sip_codec_message_body::encode_sdp: attribute: fmtp: v: ", v);
                  str += "=";
                  if (v.ischosen(LibSip__Common::GenValue::ALT_tokenOrHost)) {
                    str += static_cast<const char*>(v.tokenOrHost());
                  } else {
                    str += static_cast<const char*>(v.quotedString());
                  }
                } // else, nothing to do
                str += ";";
              } // End of 'for' statement
            } else {
              str += static_cast<const char*>(a.fmtp().params().unstructured());
            }
            ::sdp_message_a_attribute_add(*p_sdp_body, i, (char*)::strdup("fmtp"), (char*)::strdup(str.c_str()));
          } else if (a.ischosen(LibSip__SDPTypes::SDP__attribute::ALT_curr)) {
            std::string str(static_cast<const char*>(a.curr().preconditionType()));
            str += " ";
            str += static_cast<const char*>(a.curr().statusType());
            str += " ";
            str += static_cast<const char*>(a.curr().direction());
            ::sdp_message_a_attribute_add(*p_sdp_body, i, (char*)::strdup("curr"), (char*)::strdup(str.c_str()));
          } else if (a.ischosen(LibSip__SDPTypes::SDP__attribute::ALT_des)) {
            std::string str(static_cast<const char*>(a.des().preconditionType()));
            str += " ";
            str += static_cast<const char*>(a.des().strength());
            str += " ";
            str += static_cast<const char*>(a.des().statusType());
            str += " ";
            str += static_cast<const char*>(a.des().direction());
            ::sdp_message_a_attribute_add(*p_sdp_body, i, (char*)::strdup("des"), (char*)::strdup(str.c_str()));
          } else if (a.ischosen(LibSip__SDPTypes::SDP__attribute::ALT_maxptime)) {
            ::sdp_message_a_attribute_add(*p_sdp_body, i, (char*)::strdup("maxptime"), (char*)::strdup(static_cast<const char*>(a.maxptime().attr__value())));
          } else if (a.ischosen(LibSip__SDPTypes::SDP__attribute::ALT_sendrecv)) {
            ::sdp_message_a_attribute_add(*p_sdp_body, i, (char*)::strdup("sendrecv"), nullptr);
          } else {
            loggers::get_instance().warning("sip_codec_message_body::encode_sdp: attribute not processed");
          }
        } // End of 'for' statement
      }
    } // End of 'for' statement
    ::sdp_message_endof_media(*p_sdp_body, i);
  }
  // Attribute list, a
  loggers::get_instance().log_msg("sip_codec_message_body::encode_sdp: attributes: ", p_sdp_message.attributes());
  if (p_sdp_message.attributes().is_present()) {
    const LibSip__SDPTypes::SDP__attribute__list& l = static_cast<const LibSip__SDPTypes::SDP__attribute__list&>(*p_sdp_message.attributes().get_opt_value());
    int i = 0;
    for ( ; i < l.lengthof(); i++) {
      const LibSip__SDPTypes::SDP__attribute a = l[i];
      loggers::get_instance().log_msg("sip_codec_message_body::encode_sdp: attribute: ", a);
      if (a.ischosen(LibSip__SDPTypes::SDP__attribute::ALT_rtpmap)) {
        std::string str(static_cast<const char*>(a.rtpmap().payload__type()));
        str += " ";
        str += static_cast<const char*>(a.rtpmap().codec().encoding());
        str += " ";
        str += a.rtpmap().codec().clockrate();
        if (a.rtpmap().codec().parameters().is_present()) {
          str += "/";
          str += static_cast<const char*>(static_cast<const CHARSTRING&>(*a.rtpmap().codec().parameters().get_opt_value()));
        }
        loggers::get_instance().log("sip_codec_message_body::encode_sdp: attribute: media #%d: encode rtpmap:%s", i, str.c_str());
        ::sdp_message_a_attribute_add(*p_sdp_body, 0, (char*)::strdup("rtpmap"), (char*)::strdup(str.c_str()));
      } else if (a.ischosen(LibSip__SDPTypes::SDP__attribute::ALT_fmtp)) {
        std::string str(static_cast<const char*>(a.fmtp().format()));
        str += " ";
        if (a.fmtp().params().ischosen(LibSip__SDPTypes::SDP__attribute__fmtp__format__specific__params::ALT_paramList)) {
          const LibSip__Common::SemicolonParam__List& sl = a.fmtp().params().paramList();
          for (int k = 0; k < sl.lengthof(); k++) {
            str += static_cast<const char*>(sl[k].id());
            if (sl[k].paramValue().is_present()) {
              const LibSip__Common::GenValue& v = static_cast<const LibSip__Common::GenValue&>(*sl[k].paramValue().get_opt_value());
              loggers::get_instance().log_msg("sip_codec_message_body::encode_sdp: attribute: fmtp: v: ", v);
              str += "=";
              if (v.ischosen(LibSip__Common::GenValue::ALT_tokenOrHost)) {
                str += static_cast<const char*>(v.tokenOrHost());
              } else {
                str += static_cast<const char*>(v.quotedString());
              }
            } // else, nothing to do
            str += ";";
          } // End of 'for' statement
        } else {
          str += static_cast<const char*>(a.fmtp().params().unstructured());
        }
        ::sdp_message_a_attribute_add(*p_sdp_body, 0, (char*)::strdup("fmtp"), (char*)::strdup(str.c_str()));
      } else if (a.ischosen(LibSip__SDPTypes::SDP__attribute::ALT_curr)) {
        std::string str(static_cast<const char*>(a.curr().preconditionType()));
        str += " ";
        str += static_cast<const char*>(a.curr().statusType());
        str += " ";
        str += static_cast<const char*>(a.curr().direction());
        ::sdp_message_a_attribute_add(*p_sdp_body, 0, (char*)::strdup("curr"), (char*)::strdup(str.c_str()));
      } else if (a.ischosen(LibSip__SDPTypes::SDP__attribute::ALT_des)) {
        std::string str(static_cast<const char*>(a.des().preconditionType()));
        str += " ";
        str += static_cast<const char*>(a.des().strength());
        str += " ";
        str += static_cast<const char*>(a.des().statusType());
        str += " ";
        str += static_cast<const char*>(a.des().direction());
        ::sdp_message_a_attribute_add(*p_sdp_body, 0, (char*)::strdup("des"), (char*)::strdup(str.c_str()));
      } else if (a.ischosen(LibSip__SDPTypes::SDP__attribute::ALT_maxptime)) {
        ::sdp_message_a_attribute_add(*p_sdp_body, 0, (char*)::strdup("maxptime"), (char*)::strdup(static_cast<const char*>(a.maxptime().attr__value())));
      } else if (a.ischosen(LibSip__SDPTypes::SDP__attribute::ALT_sendrecv)) {
        ::sdp_message_a_attribute_add(*p_sdp_body, 0, (char*)::strdup("sendrecv"), nullptr);
      } else {
        loggers::get_instance().warning("sip_codec_message_body::encode_sdp: attribute not processed");
      }
    } // End of 'for' statement
  }
  // Bandwith, b
  loggers::get_instance().log_msg("sip_codec_message_body::encode_sdp: Bandwidth: ", p_sdp_message.bandwidth());
  if (p_sdp_message.bandwidth().is_present()) {
    const LibSip__SDPTypes::SDP__bandwidth__list& l = static_cast<const LibSip__SDPTypes::SDP__bandwidth__list&>(*p_sdp_message.bandwidth().get_opt_value());
    int i = 0;
    for ( ; i < l.lengthof(); i++) {
      const LibSip__SDPTypes::SDP__bandwidth b = l[i];
      loggers::get_instance().log_msg("sip_codec_message_body::encode_sdp: bandwidth: ", b);
      ::sdp_message_b_bandwidth_add(*p_sdp_body, i, (char*)::strdup(static_cast<const char*>(b.modifier())), (char*)::strdup(std::to_string(b.bandwidth()).c_str()));
    } // End of 'for' statement
  }
  // Connection, c
  loggers::get_instance().log_msg("sip_codec_message_body::encode_sdp: Connection: ", p_sdp_message.connection());
  if (p_sdp_message.connection().is_present()) {
    const LibSip__SDPTypes::SDP__connection& c = static_cast<const LibSip__SDPTypes::SDP__connection&>(*p_sdp_message.connection().get_opt_value());
    ::sdp_message_c_connection_add(*p_sdp_body, 0, ::strdup(static_cast<const char*>(c.net__type())), ::strdup(static_cast<const char*>(c.addr__type())), ::strdup(static_cast<const char*>(c.conn__addr().addr())), nullptr, nullptr);
  }
  // TODO To be continued

  loggers::get_instance().log("<<< sip_codec_message_body::encode_sdp");
  return 0;
}

void sip_codec_message_body::decode_message_body(const osip_message_t* p_sip_message, OPTIONAL<LibSip__MessageBodyTypes::MessageBody>& p_message_body)
{ // TODO Rename into decode_message
  loggers::get_instance().log(">>> sip_codec_message_body::decode_message_body");

  osip_content_length* content_length = ::osip_message_get_content_length(p_sip_message);
  loggers::get_instance().log("sip_codec_message_body::decode_message_body: content_length= %s", content_length->value);
  if (strcmp((const char*)content_length->value, "0") == 0) {
    p_message_body.set_to_omit();
    return;
  }
  // TODO Align the body the content_length

  osip_content_type_t* content_type = ::osip_message_get_content_type(p_sip_message);
  osip_body_t* body;
  int result = ::osip_message_get_body(p_sip_message, 0, &body);
  if (result != 0) {
    loggers::get_instance().warning("sip_codec_message_body::decode_message_body: Failed to retrieve body");
    p_message_body.set_to_omit();
    return;
  }
  loggers::get_instance().log("sip_codec_message_body::decode_message_body: Body size: %d", body->length);
  loggers::get_instance().log("sip_codec_message_body::decode_message_body: Body content: %s", body->body);
  if (body->headers != nullptr) {
    loggers::get_instance().log("sip_codec_message_body::decode_message_body: Body headers size: %d", osip_list_size(body->headers));
  }
  if (body->content_type != nullptr) {
    loggers::get_instance().log("sip_codec_message_body::decode_message_body: Body content-type: '%s'/'%s'/%p", body->content_type->type, body->content_type->subtype, body->content_type->gen_params.node);
  }
  if (::osip_list_size(body->headers) != 0) {
    loggers::get_instance().log("sip_codec_message_body::decode_message_body: Body header is present");
    // TODO Process Content-ID and other headers
  }
  LibSip__MessageBodyTypes::MessageBody msg_body;
  if (content_type != nullptr) {
    loggers::get_instance().log("sip_codec_message_body::decode_message_body: content-type.type: '%s'/'%s'/%p", content_type->type, content_type->subtype, content_type->gen_params.node);
    if (std::string(content_type->type).compare("multipart") == 0) {
      const osip_list_t* p = &(p_sip_message->bodies);
      size_t size = osip_list_size(p);
      loggers::get_instance().log("sip_codec_message_body::decode_message_body: Multipart body size: %d\n", size);
      if (size == 0) {
        loggers::get_instance().warning("sip_codec_message_body::decode_message_body: Empty multipart content, fallback to textplain");
        msg_body.textplain() = CHARSTRING(body->body);
      } else {
        LibSip__MessageBodyTypes::MIME__Message mime;
        if (content_type->gen_params.node != nullptr) {
          mime.boundary() = CHARSTRING("boundary1"/*(const char*)content_type->gen_params.node->element*/); // TODO How to get the boundary name?
        } else {
          mime.boundary() = CHARSTRING("boundary1");
        }
        loggers::get_instance().log_msg("sip_codec_message_body::decode_message_body: Boundary: ", mime.boundary());
        LibSip__MessageBodyTypes::MimeEncapsulatedList& l = mime.mimeEncapsulatedList();
        size_t pos = 0;
        while (pos < size) {
          const osip_header_t* header = (const osip_header_t*)osip_list_get(p, pos);
          loggers::get_instance().log("sip_codec_message_body::decode_message_body: body content=%s", header->hname);
          if ((*header->hname == 'v') && (*(header->hname + 1) == '=') && (*(header->hname + 2) == '0')) { // SDP
            loggers::get_instance().log("sip_codec_message_body::decode_message_body: Decode SDP");
            LibSip__MessageBodyTypes::MIME__Encapsulated__Part p;
            p.content__type() = CHARSTRING("application/sdp");
            p.content__disposition().set_to_omit();
            p.content__id().set_to_omit();
            LibSip__SDPTypes::SDP__Message sdp_body;
            osip_body_t* body;
            ::osip_body_init(&body);
            body->body = ::strdup(header->hname); // TODO Check if strdup is needed
            body->length = strlen(header->hname);
            LibSip__MessageBodyTypes::MIME__Encapsulated__Parts& parts = p.mime__encapsulated__part();
            if (decode_sdp(body, sdp_body) == 0) {
              parts.sdpMessageBody() = sdp_body;
            } else {
              parts.msdBody() = char2oct(CHARSTRING(header->hname));
            }
            l[pos] = p;
          } else if ((*header->hname == '<') && (*(header->hname + 1) == '?') && (*(header->hname + 2) == 'x')) { // <?xml
              loggers::get_instance().log("sip_codec_message_body::decode_message_body: Decode XML");
              LibSip__MessageBodyTypes::MIME__Encapsulated__Part p;
              p.content__type() = CHARSTRING("application/resource-lists+xml");
              p.content__disposition().set_to_omit();
              p.content__id().set_to_omit();
              LibSip__XMLTypes::XmlBody xml_body;
              osip_body_t* body;
              ::osip_body_init(&body);
              body->body = header->hname;
              body->length = strlen(header->hname);
              LibSip__MessageBodyTypes::MIME__Encapsulated__Parts& parts = p.mime__encapsulated__part();
              if (decode_xml(body, xml_body) == 0) {
                parts.xmlBody() = xml_body;
              } else {
                parts.msdBody() = char2oct(CHARSTRING(header->hname));
              }
              l[pos] = p;
          } else {
            // TODO
            loggers::get_instance().error("sip_codec_message_body::decode_message_body: Not implemented yet");
          }
          pos += 1;
        } // End of 'while' statement
        msg_body.mimeMessageBody() = mime;
      }
    } else if ((std::string(content_type->type).compare("application") == 0) && (std::string(content_type->subtype).compare("sdp") == 0)) {
      LibSip__SDPTypes::SDP__Message sdp_body;
      if (decode_sdp(body, sdp_body) == 0) {
        // Set message body
        msg_body.sdpMessageBody() = sdp_body;
      } else {
        loggers::get_instance().warning("sip_codec_message_body::decode_message_body: sdp_message_parse failed, fallback to textplain");
        msg_body.textplain() = CHARSTRING(body->body);
      }
    } else {
      loggers::get_instance().warning("sip_codec_message_body::decode_message_body: Unsuported content-type, fallback to textplain");
      msg_body.textplain() = CHARSTRING(body->body);
    }
    p_message_body = OPTIONAL<LibSip__MessageBodyTypes::MessageBody>(msg_body);
  } else if ((body != nullptr) && (body->body != nullptr)) {
    msg_body.textplain() = CHARSTRING(body->body);
    p_message_body = OPTIONAL<LibSip__MessageBodyTypes::MessageBody>(msg_body);
  } else {
    p_message_body.set_to_omit();
  }
  
  loggers::get_instance().log_msg("<<< sip_codec_message_body::decode_message_body: ", p_message_body);
} // End of method decode_message_body

int sip_codec_message_body::decode_sdp(const osip_body_t* p_body, LibSip__SDPTypes::SDP__Message& p_sdp_header) {
  loggers::get_instance().log(">>> sip_codec_message_body::decode_sdp: %s", p_body->body);

  sdp_message_t* sdp = nullptr;
  ::sdp_message_init(&sdp);
  std::string s(p_body->body);
  s += "\r\n\r\n";
  if (::sdp_message_parse(sdp, s.c_str()/*p_body->body*/) == 0) {
    // Mandatroy fields
    // Version, v
    char *hvalue = ::sdp_message_v_version_get(sdp);
    if (hvalue != nullptr) {
      p_sdp_header.protocol__version() = std::stoi(hvalue);
    }
    // Origin, o
    p_sdp_header.origin() = LibSip__SDPTypes::SDP__Origin(
                                                        ::sdp_message_o_username_get(sdp),
                                                        ::sdp_message_o_sess_version_get(sdp),
                                                        ::sdp_message_o_sess_version_get(sdp),
                                                        ::sdp_message_o_nettype_get(sdp),
                                                        ::sdp_message_o_addrtype_get(sdp),
                                                        ::sdp_message_o_addr_get(sdp)
                                                        );
    // Session name, s
    if ((hvalue = ::sdp_message_s_name_get(sdp)) != nullptr) {
      p_sdp_header.session__name() = CHARSTRING(hvalue);
    }
    // Time, t
    int i = 0;
    if ((hvalue = ::sdp_message_t_start_time_get(sdp, i)) != nullptr) {
      LibSip__SDPTypes::SDP__time__list l;
      do {
        LibSip__SDPTypes::SDP__time t;
        LibSip__SDPTypes::SDP__time__field tf;
        tf.start__time() = CHARSTRING(hvalue);
        tf.stop__time() = CHARSTRING(sdp_message_t_stop_time_get(sdp, i));
        t.time__field() = tf;
        t.time__repeat().set_to_omit(); // TODO
        l[i] = t;
        i += 1;
      } while ((hvalue = ::sdp_message_t_start_time_get(sdp, i)) != nullptr);
      p_sdp_header.times() = l;
    } else {
      loggers::get_instance().warning("sip_codec_message_body::decode_sdp: No start time in sdp");
    }
    // Optional fields
    // Emails, e
    i = 0;
    if ((hvalue = ::sdp_message_e_email_get(sdp, i)) != nullptr) {
      LibSip__SDPTypes::SDP__email__list l;
      do {
        LibSip__SDPTypes::SDP__contact e;
        e.addr__or__phone() = CHARSTRING(hvalue);
        e.disp__name().set_to_omit(); // TODO To be refined
        l[i] = e;
        i += 1;
      } while ((hvalue = ::sdp_message_e_email_get(sdp, i)) != nullptr);
      p_sdp_header.emails() = OPTIONAL<LibSip__SDPTypes::SDP__email__list>(l);
    } else {
      loggers::get_instance().warning("sip_codec_message_body::decode_sdp: No emails in sdp");
      p_sdp_header.emails().set_to_omit();
    }
    // Information, i
    i = 0;
    if ((hvalue = ::sdp_message_i_info_get(sdp, i)) != nullptr) {
      p_sdp_header.information() = OPTIONAL<CHARSTRING>(CHARSTRING(hvalue));
    } else {
      loggers::get_instance().warning("sip_codec_message_body::decode_sdp: No information in sdp");
      p_sdp_header.information().set_to_omit();
    }
    // Media, m
    i = 0;
    if ((hvalue = ::sdp_message_m_media_get(sdp, i)) != nullptr) {
      LibSip__SDPTypes::SDP__media__desc__list l;
      do {
        loggers::get_instance().log("sip_codec_message_body::decode_sdp: Media='%s'", hvalue);
        // Media description
        LibSip__SDPTypes::SDP__media__field f;
        f.media() = CHARSTRING(hvalue);
        LibSip__SDPTypes::SDP__media__port p;
        hvalue = ::sdp_message_m_port_get(sdp, i);
        p.port__number() = std::stoi(hvalue);
        if ((hvalue = ::sdp_message_m_number_of_port_get(sdp, i)) == nullptr) {
          p.num__of__ports().set_to_omit();
        } else {
          p.num__of__ports() = OPTIONAL<INTEGER>(std::stoi(hvalue));
        }
        f.ports() = p;
        f.transport() = CHARSTRING(::sdp_message_m_proto_get(sdp, i));
        LibSip__SDPTypes::SDP__fmt__list fl;
        int j = 0;
        while ((hvalue = ::sdp_message_m_payload_get(sdp, i, j)) != nullptr) {
          fl[j++] = CHARSTRING(hvalue);
        } // End of 'for' statement
        f.fmts() = fl;
        LibSip__SDPTypes::SDP__media__desc m;
        m.media__field() = f;
        loggers::get_instance().log_msg("sip_codec_message_body::decode_sdp: m=", m);
        // TODO
        // Media attributes
        m.attributes().set_to_omit();
        m.bandwidth().set_to_omit();
        m.information().set_to_omit();
        m.connections().set_to_omit();
        m.key().set_to_omit();
        l[i] = m;
        i += 1;
      } while ((hvalue = ::sdp_message_m_media_get(sdp, i)) != nullptr);
      p_sdp_header.media__list() = OPTIONAL<LibSip__SDPTypes::SDP__media__desc__list>(l);
    } else {
      loggers::get_instance().warning("sip_codec_message_body::decode_sdp: No media in sdp");
      p_sdp_header.media__list().set_to_omit();
    }
    // Attributes, a
    i = 0;
    sdp_attribute_t* a;
    if ((a = ::sdp_message_attribute_get(sdp, 0, i)) != nullptr) {
      LibSip__SDPTypes::SDP__attribute__list l;
      int j = 0;
      do {
        loggers::get_instance().log("sip_codec_message_body::decode_sdp: Attributes#%d: '%s'='%s'", i, a->a_att_field, (a->a_att_value == nullptr) ? "(null)" : a->a_att_value);
        // Attribute description
        LibSip__SDPTypes::SDP__attribute f;
        if (strcmp(a->a_att_field, "rtpmap") == 0) {
          std::vector<std::string> output = converter::get_instance().split(a->a_att_value, " ");
          LibSip__SDPTypes::SDP__attribute__rtpmap__codec c;
          std::vector<std::string> o = converter::get_instance().split(output[1], "/");
          c.encoding() = CHARSTRING(o[0].c_str());
          c.clockrate() = CHARSTRING(o[1].c_str());
          if (o.size() == 3) {
            c.parameters() = OPTIONAL<CHARSTRING>(CHARSTRING(o[2].c_str()));
          } else {
            c.parameters().set_to_omit();
          }
          f.rtpmap() = LibSip__SDPTypes::SDP__attribute__rtpmap(CHARSTRING(output[0].c_str()), c);
        } else if (strcmp(a->a_att_field, "fmtp") == 0) {
          // fmtp'='114 mode-change-capability=2;max-red=0'
          std::vector<std::string> o = converter::get_instance().split(a->a_att_value, " ");
          LibSip__SDPTypes::SDP__attribute__fmtp fmtp;
          fmtp.format() =  CHARSTRING(o[0].c_str());
          LibSip__SDPTypes::SDP__attribute__fmtp__format__specific__params c;
          if (o[1].find(";") != std::string::npos) {
            loggers::get_instance().log("sip_codec_message_body::decode_sdp: Attributes#%d: param list='%s'", i, o[1].c_str());
            o = converter::get_instance().split(o[1], ";");
            LibSip__Common::SemicolonParam__List& sl = c.paramList();
            for (unsigned int k = 0; k < o.size(); k++) {
              loggers::get_instance().log("sip_codec_headers::decode_semi_colon_params: Process param: %s", o[k].c_str());
              size_t eq_pos = o[k].find("=");
              if (eq_pos == std::string::npos) {
                sl[k] = LibSip__Common::GenericParam(CHARSTRING(o[k].c_str()), OPTIONAL<LibSip__Common::GenValue>(OMIT_VALUE));
              } else {
                loggers::get_instance().log("sip_codec_headers::decode_semi_colon_params: substrs: %s - %s", o[k].substr(0, eq_pos).c_str(), o[k].substr(eq_pos + 1).c_str());
                LibSip__Common::GenValue g;
                g.tokenOrHost() = CHARSTRING(o[k].substr(eq_pos + 1).c_str());
                sl[k] = LibSip__Common::GenericParam(CHARSTRING(o[k].substr(0, eq_pos).c_str()), g);
              }
            } // End of 'for'statement
          } else {
            c.unstructured() = CHARSTRING(o[1].c_str());
          }
          fmtp.params() = c;
          f.fmtp() = fmtp;
        } else if (strcmp(a->a_att_field, "curr") == 0) {
          std::vector<std::string> o = converter::get_instance().split(a->a_att_value, " ");
          if (o.size() == 3) {
            LibSip__SDPTypes::SDP__attribute__curr c;
            c.preconditionType() = CHARSTRING(o[0].c_str());
            c.statusType() = CHARSTRING(o[1].c_str());
            c.direction() = CHARSTRING(o[2].c_str());
            f.curr() = c;
          } else {
            loggers::get_instance().warning("sip_codec_message_body::decode_sdp: Wrong formatted curr SDP");
            f.curr().set_to_omit();
          }
        } else if (strcmp(a->a_att_field, "des") == 0) {
          std::vector<std::string> o = converter::get_instance().split(a->a_att_value, " ");
          if (o.size() == 4) {
            LibSip__SDPTypes::SDP__attribute__des c;
            c.preconditionType() = CHARSTRING(o[0].c_str());
            c.strength() = CHARSTRING(o[1].c_str());
            c.statusType() = CHARSTRING(o[2].c_str());
            c.direction() = CHARSTRING(o[3].c_str());
            f.des() = c;
          } else {
            loggers::get_instance().warning("sip_codec_message_body::decode_sdp: Wrong formatted des SDP");
            f.des().set_to_omit();
          }
        } else if (strcmp(a->a_att_field, "sendrecv") == 0) {
          f.sendrecv() = LibSip__SDPTypes::SDP__attribute__sendrecv(NULL_VALUE);
        } else if (strcmp(a->a_att_field, "maxptime") == 0) {
          LibSip__SDPTypes::SDP__attribute__maxptime m;
          f.maxptime() = LibSip__SDPTypes::SDP__attribute__maxptime(CHARSTRING((const char*)a->a_att_value));
        } else {
          loggers::get_instance().warning("sip_codec_message_body::decode_sdp: Unprocessed attributes#%d: '%s'='%s'", i, a->a_att_field, a->a_att_value);
        }
        loggers::get_instance().log_msg("sip_codec_message_body::decode_sdp: f: ", f);
        if (f.is_bound()) {
          l[j++] = f;
        }
        i += 1;
      } while ((a = ::sdp_message_attribute_get(sdp, 0, i)) != nullptr);
      loggers::get_instance().log_msg("sip_codec_message_body::decode_sdp: After Attribute loop: ", l);
      if (j == 0) { // Empty list
        p_sdp_header.attributes().set_to_omit();
      } else {
        p_sdp_header.attributes() = OPTIONAL<LibSip__SDPTypes::SDP__attribute__list>(l);
      }
    } else {
      loggers::get_instance().warning("sip_codec_message_body::decode_sdp: No attributes in sdp");
      p_sdp_header.attributes().set_to_omit();
    }
    // Bandwith, b
    i = 0;
    sdp_bandwidth_t* b;
    if ((b = ::sdp_message_bandwidth_get(sdp, 0, i)) != nullptr) {
      LibSip__SDPTypes::SDP__bandwidth__list l;
      do {
        loggers::get_instance().log("sip_codec_message_body::decode_sdp: Bandwidths#%d: '%s'='%s'", i, b->b_bwtype, b->b_bandwidth);
        LibSip__SDPTypes::SDP__bandwidth a(b->b_bwtype, INTEGER(std::stoi(b->b_bandwidth)));
        loggers::get_instance().log_msg("sip_codec_message_body::decode_sdp_sdp: Bandwith: ", a);
        l[i] = a;
        i += 1;
      } while((b = ::sdp_message_bandwidth_get(sdp, 0, i)) != nullptr);
      p_sdp_header.bandwidth() = OPTIONAL<LibSip__SDPTypes::SDP__bandwidth__list>(l);
    } else {
      p_sdp_header.bandwidth().set_to_omit();
    }
    // Connection, c
    char* net__type;
    if ((net__type = ::sdp_message_c_nettype_get(sdp, 0, 0)) != nullptr) {
      loggers::get_instance().log("sip_codec_message_body::decode_sdp: Connections#%d: '%s'", 0, a);
      LibSip__SDPTypes::SDP__connection c;
      c.net__type() = CHARSTRING(net__type);
      c.addr__type() = CHARSTRING(::sdp_message_c_addrtype_get(sdp, 0, 0));
      LibSip__SDPTypes::SDP__conn__addr a;
      a.addr() = CHARSTRING(::sdp_message_c_addr_get(sdp, 0, 0));
      if (::sdp_message_c_addr_multicast_ttl_get(sdp, 0, 0) != nullptr) {
        a.ttl() = OPTIONAL<INTEGER>(::stoi(::sdp_message_c_addr_multicast_ttl_get(sdp, 0, 0)));
      } else {
          a.ttl().set_to_omit();
      }
      if (::sdp_message_c_addr_multicast_int_get(sdp, 0, 0) != nullptr) {
        a.num__of__addr() = OPTIONAL<INTEGER>(::stoi(::sdp_message_c_addr_multicast_int_get(sdp, 0, 0)));
      } else {
        a.num__of__addr().set_to_omit();
      }
      c.conn__addr() = a;
      loggers::get_instance().log_msg("sip_codec_message_body::decode_sdp_sdp: connection: ", c);
      p_sdp_header.connection() = OPTIONAL<LibSip__SDPTypes::SDP__connection>(c);
    } else {
      p_sdp_header.connection().set_to_omit();
    }
    i = 0;
    
    // TODO
    p_sdp_header.uri().set_to_omit();
    p_sdp_header.phone__numbers().set_to_omit();
    p_sdp_header.timezone__adjustments().set_to_omit();
    p_sdp_header.key().set_to_omit();
    
  } else {
    loggers::get_instance().warning("sip_codec_message_body::decode_sdp: Failed to parse SDP");
    return -1;
  }

  loggers::get_instance().log_msg("<<< sip_codec_message_body::decode_sdp: sdp: ", p_sdp_header);
  return 0;
}

int sip_codec_message_body::encode_xml(const LibSip__XMLTypes::XmlBody& p_message_body, osip_body_t** p_body) {
  loggers::get_instance().log_msg(">>> sip_codec_message_body::encode_xml: ", p_message_body);
  
  ::osip_body_init(p_body);

  TTCN_EncDec::clear_error();
  TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_DEFAULT);
  TTCN_Buffer encoding_buffer;
  
  CHARSTRING h("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>\n");
  encoding_buffer.put_s(h.lengthof(), (const unsigned char*)static_cast<const char*>(h));
  if (p_message_body.ischosen(LibSip__XMLTypes::XmlBody::ALT_presence)) { // Held codec
    const urn__ietf__params__xml__ns__pidf::Presence& presence = p_message_body.presence();
    loggers::get_instance().log_msg("sip_codec_message_body::encode_xml: Process Presence", (const Base_Type&)presence);
    presence.encode(urn__ietf__params__xml__ns__pidf::Presence_descr_, encoding_buffer, TTCN_EncDec::CT_XER, XER_EXTENDED);
  } else {
    loggers::get_instance().warning("sip_codec_message_body::encode_xml: Unsupported variant");
    return -1;
  }
  OCTETSTRING data = OCTETSTRING(encoding_buffer.get_len(), encoding_buffer.get_data());

  if (p_message_body.ischosen(LibSip__XMLTypes::XmlBody::ALT_presence)) { // NG112-2021 Workaround for TITAN/XSD issue
                                                                          // TODO TITAN work-around, replace tq0003 namespace???
    std::string s(static_cast<const unsigned char*>(data), data.lengthof() + static_cast<const unsigned char*>(data));
    /*size_t idx = 0;

    std::string f("tq0000:");
    std::string t("");
    while ((idx = s.find(f)) != std::string::npos) {
      s.replace(idx, f.length(), t);
      idx += t.length();
    } // End of 'while' statement
    f.assign(":tq0000");
    while ((idx = s.find(f)) != std::string::npos) {
      s.replace(idx, f.length(), t);
      idx += t.length();
    } // End of 'while' statement
    f.assign("tq0001:");
    while ((idx = s.find(f)) != std::string::npos) {
      s.replace(idx, f.length(), t);
      idx += t.length();
    } // End of 'while' statement
    f.assign(":tq0001");
    while ((idx = s.find(f)) != std::string::npos) {
      s.replace(idx, f.length(), t);
      idx += t.length();
    } // End of 'while' statement
    f.assign("tq0002:");
    while ((idx = s.find(f)) != std::string::npos) {
      s.replace(idx, f.length(), t);
      idx += t.length();
    } // End of 'while' statement
    f.assign(":tq0002");
    while ((idx = s.find(f)) != std::string::npos) {
      s.replace(idx, f.length(), t);
      idx += t.length();
    } // End of 'while' statement
    f.assign("tq0003:");
    while ((idx = s.find(f)) != std::string::npos) {
      s.replace(idx, f.length(), t);
      idx += t.length();
    } // End of 'while' statement
    f.assign(":tq0003");
    while ((idx = s.find(f)) != std::string::npos) {
      s.replace(idx, f.length(), t);
      idx += t.length();
    } // End of 'while' statement
    f.assign("tq0004:");
    while ((idx = s.find(f)) != std::string::npos) {
      s.replace(idx, f.length(), t);
      idx += t.length();
    } // End of 'while' statement
    f.assign(":tq0004");
    while ((idx = s.find(f)) != std::string::npos) {
      s.replace(idx, f.length(), t);
      idx += t.length();
    } // End of 'while' statement
    */
    data = OCTETSTRING(s.length(), (const unsigned char*)s.c_str());
  }
  (*p_body)->body = ::strdup(static_cast<const char*>(oct2char(data)));
  (*p_body)->length = strlen((*p_body)->body);

  loggers::get_instance().log("<<< sip_codec_message_body::encode_xml: %s", (*p_body)->body);
  return 0;
}

int sip_codec_message_body::decode_xml(const osip_body_t* p_body, LibSip__XMLTypes::XmlBody& p_xml_header) {
  loggers::get_instance().log(">>> sip_codec_message_body::decode_xml: %s", p_body->body);
  
  // TODO Unify held_codec for bothHttp & Sip: instead of LibHttp__XmlMessageBodyTypes::XmlBody, use a generic XmlBody common to LibItsHttp & LibSip
  TTCN_EncDec::clear_error();
  TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_DEFAULT);
  OCTETSTRING data(p_body->length, (const unsigned char*)p_body->body);
  TTCN_Buffer decoding_buffer(data);
  loggers::get_instance().log_to_hexa("sip_codec_message_body::decode_xml: decoding_buffer: ", decoding_buffer);
  
  if (strstr(p_body->body, "<presence") != nullptr) { // Held codec
    urn__ietf__params__xml__ns__pidf::Presence presence;
    presence.decode(urn__ietf__params__xml__ns__pidf::Presence_descr_, decoding_buffer, TTCN_EncDec::CT_XER, XER_EXTENDED);
    p_xml_header.presence() = presence;
  } else {
    loggers::get_instance().warning("sip_codec_message_body::decode_xml: Unsupported XML message, to be implemented");
  }
  
  loggers::get_instance().log_msg("<<< sip_codec_message_body::decode_xml: xml: ", p_xml_header);
  return 0;
}
