#include <iomanip>

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

#include "sip_codec_headers.hh"
#include "loggers.hh"

#include "converter.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_headers::encode_headers(const LibSip__SIPTypesAndValues::MessageHeader& p_msg_header, osip_message_t* p_sip_message)
{
  loggers::get_instance().log_msg(">>> sip_codec_headers::encode_headers: ", p_msg_header);
  
  // Encode mandatory fields
  // From
  osip_from_t* from_header = nullptr;
  if (encode_from_header(p_msg_header.fromField(), &from_header) == -1) {
    loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to encode From header");
    return -1;
  }
  char* hvalue;
  ::osip_from_to_str(from_header, &hvalue);
  loggers::get_instance().log("sip_codec_headers::encode_headers: From:%s", hvalue);
  if (::osip_message_set_from(p_sip_message, hvalue) != OSIP_SUCCESS) {
    loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to set From header in sip_message");
    return -1;
  }

  ::osip_from_free(from_header);
  osip_free(hvalue);
  
  // To
  osip_to_t* to_header = nullptr;
  if (encode_to_header(p_msg_header.toField(), &to_header) == -1) {
    loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to encode To header");
    return -1;
  }
  int r = ::osip_to_to_str(to_header, &hvalue);
  loggers::get_instance().log("sip_codec_headers::encode_headers: To:'%s'- result:%d", hvalue, r);
  if (::osip_message_set_to(p_sip_message, hvalue) != OSIP_SUCCESS) {
    loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to set To header in sip_message");
    return -1;
  }
  ::osip_to_free(to_header);
  osip_free(hvalue);

  // Via
  osip_via_t* via_header = nullptr;
  if (encode_via_header(p_msg_header.via(), &via_header) == -1) {
    loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to encode Via header");
    return -1;
  }
  ::osip_via_to_str(via_header, &hvalue);
  loggers::get_instance().log("sip_codec_headers::encode_headers: Via:%s", hvalue);
  std::string str(hvalue);
  std::size_t idx = str.find(" ("); // FIXME Horrible work-around for osip_via_to_str issue (' ()' added sometimes
  if (idx != std::string::npos) {
    str = str.substr(0, idx);
  }
  loggers::get_instance().log("sip_codec_headers::encode_headers: Via (final):%s", str.c_str());
  if (::osip_message_set_via(p_sip_message, str.c_str()) != OSIP_SUCCESS) {
    loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to set Via header in sip_message");
    return -1;
  }
  ::osip_via_free(via_header);
  osip_free(hvalue);

  // Encode Optional fields
  loggers::get_instance().log("sip_codec_headers::encode_headers: Encode Optional fields");
  
  // Accept
  if (p_msg_header.accept().is_present()) {
    if (encode_accept_header(p_msg_header.accept(), &p_sip_message) == -1) {
      loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to encode Accept header");
      return -1;
    }
  }
  
  // AcceptContact
  if (p_msg_header.acceptContact().is_present()) {
    if (encode_accept_contact_header(p_msg_header.acceptContact(), &p_sip_message) == -1) {
      loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to encode AcceptContact header");
      return -1;
    }
  }
  
  // Allow
  if (p_msg_header.allow().is_present()) {
    if (encode_allow_header(p_msg_header.allow(), &p_sip_message) == -1) {
      loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to encode Allow header");
      return -1;
    }
  }
  
  // Authorization
  if (p_msg_header.authorization().is_present()) {
    osip_authorization_t* authorization_header = nullptr;
    if (encode_authorization_header(p_msg_header.authorization(), &authorization_header) == -1) {
      loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to encode Authorization header");
      return -1;
    }
    int result = ::osip_authorization_to_str(authorization_header, &hvalue);
    loggers::get_instance().log("sip_codec_headers::encode_headers: Authorization: %s - %d", hvalue, result);
    result = ::osip_message_set_authorization(p_sip_message, hvalue);
    loggers::get_instance().log("sip_codec_headers::encode_headers: SIP Authorization: %p - %d", p_sip_message->authorizations, result);
    ::osip_authorization_free(authorization_header);
    osip_free(hvalue);
  }
  
  // CallInfo
  if (p_msg_header.callInfo().is_present()) {
    if (encode_call_info_header(p_msg_header.callInfo(), &p_sip_message) == -1) {
      loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to encode CallInfo header");
      return -1;
    }
  }
  
  // CallId
  if (p_msg_header.callId().is_present()) {
    osip_call_id_t* call_id_header;
    if (encode_call_id_header(p_msg_header.callId(), &call_id_header) == -1) {
      loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to encode Call_Id header");
      return -1;
    }
    ::osip_call_id_to_str(call_id_header, &hvalue);
    loggers::get_instance().log("sip_codec_headers::encode_headers: Call_Id:%s", hvalue);
    int result = ::osip_message_set_call_id(p_sip_message, hvalue);
    loggers::get_instance().log("sip_codec_headers::encode_headers: SIP Call_Id: %p - %d", p_sip_message->call_id, result);
    ::osip_call_id_free(call_id_header);
    osip_free(hvalue);
  }
  
  // Contact
  if (p_msg_header.contact().is_present()) {
    osip_contact_t* contact_header;
    if (encode_contact_header(p_msg_header.contact(), &contact_header) == -1) {
      loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to encode Contact header");
      return -1;
    }
    ::osip_contact_to_str(contact_header, &hvalue);
    loggers::get_instance().log("sip_codec_headers::encode_headers: Contact: %s", hvalue);
    int result = ::osip_message_set_contact(p_sip_message, hvalue);
    loggers::get_instance().log("sip_codec_headers::encode_headers: SIP Contact: %p - %d", p_sip_message->contacts, result);
    ::osip_contact_free(contact_header);
    osip_free(hvalue);
  }
  
  // ContentLength
  osip_content_length_t* content_length_header = nullptr;
  if (encode_content_length_header(p_msg_header.contentLength(), &content_length_header) == -1) {
    loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to encode ContentLength header");
    return -1;
  }
  ::osip_content_length_to_str(content_length_header, &hvalue);
  loggers::get_instance().log("sip_codec_headers::encode_headers: ContentLength:%s", hvalue);
  ::osip_message_set_content_length(p_sip_message, hvalue);
  ::osip_content_length_free(content_length_header);
  osip_free(hvalue);
  
  // ContentType
  if (p_msg_header.contentType().is_present()) {
    osip_content_type_t* content_type_header = nullptr;
    if (encode_content_type_header(p_msg_header.contentType(), &content_type_header) == -1) {
      loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to encode ContentType header");
      return -1;
    }
    ::osip_content_type_to_str(content_type_header, &hvalue);
    loggers::get_instance().log("sip_codec_headers::encode_headers: ContentType:%s", hvalue);
    ::osip_message_set_content_type(p_sip_message, hvalue);
    ::osip_content_type_free(content_type_header);
    osip_free(hvalue);
  }
  
  // CSeq
  osip_cseq_t* cseq_header = nullptr;
  if (encode_c_seq_header(p_msg_header.cSeq(), &cseq_header) == -1) {
    loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to encode CSeq header");
    return -1;
  }
  ::osip_cseq_to_str(cseq_header, &hvalue);
  loggers::get_instance().log("sip_codec_headers::encode_headers: Cseq:%s", hvalue);
  ::osip_message_set_cseq(p_sip_message, hvalue);
  ::osip_cseq_free(cseq_header);
  osip_free(hvalue);

  // Event
  if (p_msg_header.event().is_present()) {
    if (encode_event_header(p_msg_header.event(), &p_sip_message) == -1) {
      loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to encode Event header");
      return -1;
    }
  }

  // Expires
  if (p_msg_header.expires().is_present()) {
    if (encode_expires_header(p_msg_header.expires(), &p_sip_message) == -1) {
      loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to encode Expires header");
      return -1;
    }
  }

  // Geolocation
  if (p_msg_header.geolocation().is_present()) {
    if (encode_geolocation_header(p_msg_header.geolocation(), &p_sip_message) == -1) {
      loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to encode Geolocation header");
      return -1;
    }
  }

  // GeolocationRouting
  if (p_msg_header.geolocationRouting().is_present()) {
    if (encode_geolocation_routing_header(p_msg_header.geolocationRouting(), &p_sip_message) == -1) {
      loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to encode GeolocationRouting header");
      return -1;
    }
  }

  // MaxForwards
  if (p_msg_header.maxForwards().is_present()) {
    if (encode_max_forwards_header(p_msg_header.maxForwards(), &p_sip_message) == -1) {
      loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to encode MaxForwards header");
      return -1;
    }
  }
  
  // MinSE
  if (p_msg_header.minSE().is_present()) {
    if (encode_min_se_header(p_msg_header.minSE(), &p_sip_message) == -1) {
      loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to encode MinSE header");
      return -1;
    }
  }
  
  // PAccessNetworkInfo
  if (p_msg_header.pAccessNetworkInfo().is_present()) {
    if (encode_p_access_network_info_header(p_msg_header.pAccessNetworkInfo(), &p_sip_message) == -1) {
      loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to encode PAccessNetworkInfo header");
      return -1;
    }
  }
  
  // Privacy
  if (p_msg_header.privacy().is_present()) {
    if (encode_privacy_header(p_msg_header.privacy(), &p_sip_message) == -1) {
      loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to encode Privacy header");
      return -1;
    }
  }
  
  // Route
  if (p_msg_header.route().is_present()) {
    if (encode_route_header(p_msg_header.route(), &p_sip_message) == -1) {
      loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to encode Route header");
      return -1;
    }
  }
  
  // RecordRoute
  if (p_msg_header.recordRoute().is_present()) {
    if (encode_record_route_header(p_msg_header.recordRoute(), &p_sip_message) == -1) {
      loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to encode RecordRoute header");
      return -1;
    }
  }
  
  // RSeq
  if (p_msg_header.rSeq().is_present()) {
    if (encode_r_seq_header(p_msg_header.rSeq(), &p_sip_message) == -1) {
      loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to encode RSeq header");
      return -1;
    }
  }

  // Supported
  if (p_msg_header.supported().is_present()) {
    if (encode_supported_header(p_msg_header.supported(), &p_sip_message) == -1) {
      loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to encode Supported header");
      return -1;
    }
  }
  
  if (p_msg_header.userAgent().is_present()) {
    if (encode_user_agent_header(p_msg_header.userAgent(), &p_sip_message) == -1) {
      loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to encode UserAgent header");
      return -1;
    }
  }
  
  // WwwAuthenticate
  if (p_msg_header.wwwAuthenticate().is_present()) {
    osip_www_authenticate_t* www_authenticate_header = nullptr;
    if (encode_www_authenticate_header(p_msg_header.wwwAuthenticate(), &www_authenticate_header) == -1) {
      loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to encode WwwAuthenticate header");
      return -1;
    }
    //std::string s("Digest realm=\"testrealm@host.com\", nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\", opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"");
    ::osip_www_authenticate_to_str(www_authenticate_header, &hvalue);
    loggers::get_instance().log("sip_codec_headers::encode_headers: WwwAuthenticate:%s", hvalue);
    if (::osip_message_set_www_authenticate(p_sip_message, hvalue) != OSIP_SUCCESS) {
      loggers::get_instance().warning("sip_codec_headers::encode_headers: Failed to set WwwAuthenticate header in sip_message");
      return -1;
    }
    //int result = ::osip_message_set_www_authenticate(p_sip_message, s.c_str());//hvalue);
    //loggers::get_instance().log("sip_codec_headers::encode_headers: osip_message_set_www_authenticate return code:%d", result);
    osip_free(hvalue);
  }
  
  // TODO continue
  const osip_list_t* p = &(p_sip_message->headers);
  unsigned int pos = 0;
  unsigned int size = ::osip_list_size(p);
  loggers::get_instance().log("Unknown headers count: %d\n", size);
  while (pos < size) {
    const osip_header_t* header = (const osip_header_t*)osip_list_get(p, pos++);
    loggers::get_instance().log("sip_codec_headers::encode_headers: %p: hname='%s' : hvalue='%s'\n", header, header->hname, header->hvalue);
  } // End of 'while' statement

  loggers::get_instance().log("<<< sip_codec_headers::encode_headers");
  return 0;
} // End of method encode_headers

void sip_codec_headers::decode_headers(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::MessageHeader& p_headers)
{
  loggers::get_instance().log(">>> sip_codec_headers::decode_headers");
  
  LibSip__SIPTypesAndValues::MessageHeader headers;
  // Decode mandatory fields
  // From
  loggers::get_instance().log("sip_codec_headers::decode_headers: From");
  LibSip__SIPTypesAndValues::From from_header;
  decode_from_header(::osip_message_get_from(p_sip_message), from_header);
  if (from_header.is_value()) {
    p_headers.fromField() = from_header;
  } else {
    p_headers.fromField().set_to_omit();
  }
  // To
  loggers::get_instance().log("sip_codec_headers::decode_headers: To");
  LibSip__SIPTypesAndValues::To to_header;
  decode_to_header(::osip_message_get_to(p_sip_message), to_header);
  if (to_header.is_value()) {
    p_headers.toField() = to_header;
  } else {
    p_headers.toField().set_to_omit();
  }
  // Via
  loggers::get_instance().log("sip_codec_headers::decode_headers: Via");
  LibSip__SIPTypesAndValues::Via via_header;
  decode_via_header(p_sip_message, via_header);
  if (via_header.is_value()) {
    p_headers.via() = via_header;
  } else {
    p_headers.via().set_to_omit();
  }

  // Decode Optional fields
  LibSip__SIPTypesAndValues::Accept accept_header;
  decode_accept_header(p_sip_message, accept_header);
  if (accept_header.is_value()) {
    p_headers.accept() = accept_header;
  } else {
    p_headers.accept().set_to_omit();
  }

  LibSip__SIPTypesAndValues::AcceptContact accept_contact_header;
  decode_accept_contact_header(p_sip_message, accept_contact_header);
  if (accept_contact_header.is_value()) {
    p_headers.acceptContact() = accept_contact_header;
  } else {
    p_headers.acceptContact().set_to_omit();
  }
  
  LibSip__SIPTypesAndValues::AcceptEncoding accept_encoding_header;
  decode_accept_encoding_header(p_sip_message, accept_encoding_header);
  if (accept_encoding_header.is_value()) {
    p_headers.acceptEncoding() = accept_encoding_header;
  } else {
    p_headers.acceptEncoding().set_to_omit();
  }

  LibSip__SIPTypesAndValues::AcceptLanguage accept_language_header;
  decode_accept_language_header(p_sip_message, accept_language_header);
  if (accept_language_header.is_value()) {
    p_headers.acceptLanguage() = accept_language_header;
  } else {
    p_headers.acceptLanguage().set_to_omit();
  }

  LibSip__SIPTypesAndValues::AlertInfo alert_info_header;
  decode_alert_info_header(p_sip_message, alert_info_header);
  if (alert_info_header.is_value()) {
    p_headers.alertInfo() = alert_info_header;
  } else {
    p_headers.alertInfo().set_to_omit();
  }

  LibSip__SIPTypesAndValues::Allow allow_header;
  decode_allow_header(p_sip_message, allow_header);
  if (allow_header.is_value()) {
    p_headers.allow() = allow_header;
  } else {
    p_headers.allow().set_to_omit();
  }

  LibSip__SIPTypesAndValues::AllowEvents allow_events_header;
  decode_allow_events_header(p_sip_message, allow_events_header);
  if (allow_events_header.is_value()) {
    p_headers.allowEvents() = allow_events_header;
  } else {
    p_headers.allowEvents().set_to_omit();
  }

  LibSip__SIPTypesAndValues::Authorization authorization_header;
  decode_authorization_header(p_sip_message, authorization_header);
  if (authorization_header.is_value()) {
    p_headers.authorization() = authorization_header;
  } else {
    p_headers.authorization().set_to_omit();
  }
  
  p_headers.authenticationInfo().set_to_omit();

  LibSip__SIPTypesAndValues::CallId call_id_header;
  decode_call_id_header(p_sip_message, call_id_header);
  if (call_id_header.is_value()) {
    p_headers.callId() = call_id_header;
  } else {
    p_headers.callId().set_to_omit();
  }
  
  LibSip__SIPTypesAndValues::CallInfo call_info_header;
  decode_call_info_header(p_sip_message, call_info_header);
  if (call_info_header.is_value()) {
    p_headers.callInfo() = call_info_header;
  } else {
    p_headers.callInfo().set_to_omit();
  }

  LibSip__SIPTypesAndValues::Contact contact_header;
  decode_contact_header(p_sip_message, contact_header);
  if (contact_header.is_value()) {
    p_headers.contact() = contact_header;
  } else {
    p_headers.contact().set_to_omit();
  }
  
  p_headers.contentDisposition().set_to_omit();
  p_headers.contentEncoding().set_to_omit();
  p_headers.contentLanguage().set_to_omit();
  
  LibSip__SIPTypesAndValues::ContentLength content_length_header;
  decode_content_length_header(p_sip_message, content_length_header);
  if (content_length_header.is_value()) {
    p_headers.contentLength() = content_length_header;
  } else {
    p_headers.contentLength().set_to_omit();
  }

  LibSip__SIPTypesAndValues::ContentType content_type_header;
  decode_content_type_header(p_sip_message, content_type_header);
  if (content_type_header.is_value()) {
    p_headers.contentType() = content_type_header;
  } else {
    p_headers.contentType().set_to_omit();
  }

  LibSip__SIPTypesAndValues::CSeq c_seq_header;
  decode_c_seq_header(p_sip_message, c_seq_header);
  if (c_seq_header.is_value()) {
    p_headers.cSeq() = c_seq_header;
  } else {
    p_headers.cSeq().set_to_omit();
  }
  
  p_headers.date().set_to_omit();
  p_headers.errorInfo().set_to_omit();
  p_headers.event().set_to_omit();
  p_headers.expires().set_to_omit();
  p_headers.featureCaps().set_to_omit();

  LibSip__SIPTypesAndValues::Geolocation geolocation_header;
  decode_geolocation_header(p_sip_message, geolocation_header);
  if (geolocation_header.is_value()) {
    p_headers.geolocation() = geolocation_header;
  } else {
    p_headers.geolocation().set_to_omit();
  }

  LibSip__SIPTypesAndValues::GeolocationRouting geolocation_routing_header;
  decode_geolocation_routing_header(p_sip_message, geolocation_routing_header);
  if (geolocation_routing_header.is_value()) {
    p_headers.geolocationRouting() = geolocation_routing_header;
  } else {
    p_headers.geolocationRouting().set_to_omit();
  }

  p_headers.historyInfo().set_to_omit();
  p_headers.infoPackage().set_to_omit();
  p_headers.inReplyTo().set_to_omit();

  LibSip__SIPTypesAndValues::Event event_header;
  decode_event_header(p_sip_message, event_header);
  if (event_header.is_value()) {
    p_headers.event() = event_header;
  } else {
    p_headers.event().set_to_omit();
  }

  LibSip__SIPTypesAndValues::Expires expires_header;
  decode_expires_header(p_sip_message, expires_header);
  if (expires_header.is_value()) {
    p_headers.expires() = expires_header;
  } else {
    p_headers.expires().set_to_omit();
  }

  LibSip__SIPTypesAndValues::MaxForwards max_forwards_header;
  decode_max_forwards_header(p_sip_message, max_forwards_header);
  if (max_forwards_header.is_value()) {
    p_headers.maxForwards() = max_forwards_header;
  } else {
    p_headers.maxForwards().set_to_omit();
  }

  p_headers.mimeVersion().set_to_omit();
  p_headers.minExpires().set_to_omit();
  
  LibSip__SIPTypesAndValues::MinSE min_se_header;
  decode_min_se_header(p_sip_message, min_se_header);
  if (min_se_header.is_value()) {
    p_headers.minSE() = min_se_header;
  } else {
    p_headers.minSE().set_to_omit();
  }
  
  p_headers.organization().set_to_omit();
  
  LibSip__SIPTypesAndValues::PAccessNetworkInfo p_access_network_info_header;
  decode_p_access_network_info_header(p_sip_message, p_access_network_info_header);
  if (p_access_network_info_header.is_value()) {
    p_headers.pAccessNetworkInfo() = p_access_network_info_header;
  } else {
    p_headers.pAccessNetworkInfo().set_to_omit();
  }

  p_headers.pAssertedID().set_to_omit();
  p_headers.pAssertedService().set_to_omit();
  p_headers.pAssociatedURI().set_to_omit();
  p_headers.path().set_to_omit();
  p_headers.pCalledPartyID().set_to_omit();
  p_headers.pChargingFunctionAddresses().set_to_omit();
  p_headers.pChargingVector().set_to_omit();
  p_headers.pEarlyMedia().set_to_omit();
  p_headers.pMediaAuthorization().set_to_omit();
  p_headers.pPreferredID().set_to_omit();
  p_headers.pPreferredService().set_to_omit();
  p_headers.priority().set_to_omit();
  
  LibSip__SIPTypesAndValues::Privacy privacy_header;
  decode_privacy_header(p_sip_message, privacy_header);
  if (privacy_header.is_value()) {
    p_headers.privacy() = privacy_header;
  } else {
    p_headers.privacy().set_to_omit();
  }
  
  p_headers.proxyAuthenticate().set_to_omit();
  p_headers.proxyAuthorization().set_to_omit();
  p_headers.proxyRequire().set_to_omit();
  p_headers.pVisitedNetworkID().set_to_omit();
  p_headers.rAck().set_to_omit();
  p_headers.reason().set_to_omit();
  p_headers.recvInfo().set_to_omit();
  p_headers.requestDisposition().set_to_omit();
  p_headers.referredBy().set_to_omit();
  p_headers.referTo().set_to_omit();
  p_headers.referSub().set_to_omit();
  p_headers.replaces().set_to_omit();
  p_headers.replyTo().set_to_omit();
  p_headers.require().set_to_omit();
  
  LibSip__SIPTypesAndValues::RSeq r_seq_header;
  decode_r_seq_header(p_sip_message, r_seq_header);
  if (r_seq_header.is_value()) {
    p_headers.rSeq() = r_seq_header;
  } else {
    p_headers.rSeq().set_to_omit();
  }
  p_headers.retryAfter().set_to_omit();
  
  LibSip__SIPTypesAndValues::Route route_header;
  decode_route_header(p_sip_message, route_header);
  if (route_header.is_value()) {
    p_headers.route() = route_header;
  } else {
    p_headers.route().set_to_omit();
  }
  
  LibSip__SIPTypesAndValues::RecordRoute record_route_header;
  decode_record_route_header(p_sip_message, record_route_header);
  if (record_route_header.is_value()) {
    p_headers.recordRoute() = record_route_header;
  } else {
    p_headers.recordRoute().set_to_omit();
  }
  
  p_headers.securityClient().set_to_omit();
  p_headers.securityServer().set_to_omit();
  p_headers.securityVerify().set_to_omit();
  p_headers.server().set_to_omit();
  p_headers.serviceRoute().set_to_omit();
  
  LibSip__SIPTypesAndValues::SessionExpires session_expires;
  decode_session_expires_header(p_sip_message, session_expires);
  if (session_expires.is_value()) {
    p_headers.sessionExpires() = session_expires;
  } else {
    p_headers.sessionExpires().set_to_omit();
  }
  
  p_headers.sessionId().set_to_omit();
  p_headers.sipETag().set_to_omit();
  p_headers.sipIfMatch().set_to_omit();
  p_headers.subject().set_to_omit();
  p_headers.subscriptionState().set_to_omit();
  
  LibSip__SIPTypesAndValues::Supported supported_header;
  decode_supported_header(p_sip_message, supported_header);
  if (supported_header.is_value()) {
    p_headers.supported() = supported_header;
  } else {
    p_headers.supported().set_to_omit();
  }
  
  p_headers.timestamp__().set_to_omit();
  p_headers.unsupported().set_to_omit();
  p_headers.userToUser().set_to_omit();
  
  LibSip__SIPTypesAndValues::UserAgent user_agent_header;
  decode_user_agent_header(p_sip_message, user_agent_header);
  if (user_agent_header.is_value()) {
    p_headers.userAgent() = user_agent_header;
  } else {
    p_headers.userAgent().set_to_omit();
  }
  p_headers.warning().set_to_omit();

  LibSip__SIPTypesAndValues::WwwAuthenticate www_authenticate_header;
  osip_www_authenticate_t* www_authenticate = nullptr;
  ::osip_message_get_www_authenticate(p_sip_message, 0, &www_authenticate);
  decode_www_authenticate_header(www_authenticate, www_authenticate_header);
  if (www_authenticate_header.is_value()) {
    p_headers.wwwAuthenticate() = www_authenticate_header;
  } else {
    p_headers.wwwAuthenticate().set_to_omit();
  }

  p_headers.resourcePriority().set_to_omit();
  p_headers.answerMode().set_to_omit();
  p_headers.privAnswerMode().set_to_omit();
  p_headers.targetDialog().set_to_omit();
  p_headers.pAnswerState().set_to_omit();
  p_headers.undefinedHeader__List().set_to_omit();
  
  // List unprocessed headers
  const osip_list_t* p = &(p_sip_message->headers);
  unsigned int pos = 0;
  unsigned int size = ::osip_list_size(p);
  loggers::get_instance().log("Unknown headers count: %d\n", size);
  while (pos < size) {
    const osip_header_t* header = (const osip_header_t*)osip_list_get(p, pos++);
    loggers::get_instance().log("sip_codec_headers::decode_headers: %p: hname='%s' : hvalue='%s'\n", header, header->hname, header->hvalue);
  } // End of 'while' statement
  
  loggers::get_instance().log_msg("<<< sip_codec_headers::decode_headers: ", p_headers);
} // End of method decode_headers

int sip_codec_headers::encode_sip_url(const LibSip__SIPTypesAndValues::SipUrl& p_sip_uri, osip_uri_t** p_uri)
{ // TODO To be renamed into encode_uri
  loggers::get_instance().log_msg(">>> sip_codec_headers::encode_sip_uri: ", p_sip_uri);

  std::string host;
  std::string port;
  osip_uri_t *uri = nullptr;
  ::osip_uri_init(&uri);
  const LibSip__SIPTypesAndValues::UriComponents& components = p_sip_uri.components();
  if (components.ischosen(LibSip__SIPTypesAndValues::UriComponents::ALT_sip)) {
    ::osip_uri_set_scheme(uri, (char*)static_cast<const char*>(p_sip_uri.scheme()));
    const LibSip__SIPTypesAndValues::SipUriComponents& s = p_sip_uri.components().sip();
    if (s.userInfo().is_present()) {
      const LibSip__SIPTypesAndValues::UserInfo& u = static_cast<const LibSip__SIPTypesAndValues::UserInfo>(s.userInfo());
      ::osip_uri_set_username(uri, (char*)static_cast<const char*>(static_cast<CHARSTRING>(u.userOrTelephoneSubscriber())));
      if (u.password().is_present()) {
        const CHARSTRING& c = static_cast<CHARSTRING>(u.password());
        ::osip_uri_set_password(uri, (char*)static_cast<const char*>(c));
      }
    }
    encode_host_port(s.hostPort(), host, port);
    if (!host.empty()) {
      ::osip_uri_set_host(uri, (char*)host.c_str());
    }
    if (!port.empty()) {
     ::osip_uri_set_port(uri, (char*)port.c_str());
    }
  } else if (components.ischosen(LibSip__SIPTypesAndValues::UriComponents::ALT_tel)) {
    const LibSip__SIPTypesAndValues::TelUriComponents& t = p_sip_uri.components().tel();
    loggers::get_instance().error("sip_codec_headers::encode_sip_uri: Unsupported LibSip__SIPTypesAndValues::UriComponents::ALT_tel");
  } else if (components.ischosen(LibSip__SIPTypesAndValues::UriComponents::ALT_urn)) {
    const LibSip__SIPTypesAndValues::UrnUriComponents& u = p_sip_uri.components().urn();
    loggers::get_instance().log("sip_codec_headers::encode_sip_uri: Decode Urn");
    std::string str(static_cast<const char*>(p_sip_uri.scheme()));
    str += ":";
    str += static_cast<const char*>(u.namespaceId());
    str += ":";
    str += static_cast<const char*>(u.namespaceSpecificString());
    ::osip_uri_parse(uri, str.c_str());
  } else if (components.ischosen(LibSip__SIPTypesAndValues::UriComponents::ALT_other)) {
    std::string str(static_cast<const char*>(p_sip_uri.scheme()));
    str += ":";
    str += static_cast<const char*>(p_sip_uri.components().other());
    ::osip_uri_parse(uri, str.c_str());
  } // else, noting to do
  
  if (uri != nullptr) {
    ::osip_uri_clone(uri, p_uri);
  } else {
    *p_uri = nullptr;
  }
  
  char* buffer = nullptr;
  std::size_t length = 0;
  int result = ::osip_uri_to_str(*p_uri, &buffer);
  if (result != 0) {
    loggers::get_instance().warning("sip_codec_headers::encode_sip_uri: Failed to encode data structures");
  } else {
    loggers::get_instance().log("sip_codec_headers::encode_sip_uri: URI:%s", buffer);
  }
  
  return 0;
} // End of method encode_sip_url

void sip_codec_headers::encode_host_port(const LibSip__SIPTypesAndValues::HostPort& p_host_port, std::string& p_host, std::string& p_port)
{
  loggers::get_instance().log(">>> sip_codec_headers::encode_host_port");
  
  if (p_host_port.host().is_present()) {
    p_host.assign(static_cast<const char*>(static_cast<CHARSTRING>(p_host_port.host())));
  } else {
    p_host.clear();
  }
  loggers::get_instance().log("sip_codec_headers::encode_host_port: host:'%s'", p_host.c_str());
  if (p_host_port.portField().is_present()) {
    p_port.assign(std::to_string(static_cast<int>(static_cast<INTEGER>(p_host_port.portField()))));
  } else {
    p_port.clear();
  }
  loggers::get_instance().log("sip_codec_headers::encode_port_port: port:'%s'", p_port.c_str());
} // End of method encode_host_port

int sip_codec_headers::encode_accept_header(const LibSip__SIPTypesAndValues::Accept& p_accept, osip_message_t** p_sip_message) {
  loggers::get_instance().log(">>> sip_codec_headers::encode_accept_header");
  
  if (!p_accept.acceptArgs().is_present()) {
    return 0;
  }
  
  const LibSip__SIPTypesAndValues::AcceptBody__List& al = static_cast<const LibSip__SIPTypesAndValues::AcceptBody__List&>(*p_accept.acceptArgs().get_opt_value());
  if (al.lengthof() == 0) {
    return 0;
  }
  std::string accepts;
  for (int i = 0; i < al.lengthof(); i++) {
    const LibSip__SIPTypesAndValues::AcceptBody& b = al[i];
    loggers::get_instance().log_msg("sip_codec_headers::encode_accept_header: b: ", b);
    osip_accept_t *accept;
    accept_init(&accept);
    // Split it using '/' as separator
    std::vector<std::string> output = converter::get_instance().split(static_cast<const char*>(b.mediaRange()), "/");
    accept->type = ::strdup(output[0].c_str());
    if (output.size() > 1) {
      accept->subtype = ::strdup(output[1].c_str());
    }
    if (b.acceptParam().is_present()) {
      encode_semi_colon_params(static_cast<const LibSip__Common::SemicolonParam__List>(b.acceptParam()), &(accept->gen_params));
    }
    char *buff;
    ::osip_accept_to_str(accept, &buff);
    accepts += (const char*)buff;
    accepts += ",";
    osip_free(buff);
    ::osip_accept_free(accept);
    loggers::get_instance().log("sip_codec_headers::encode_accept_header: accepts: %s", accepts.c_str());
  } // End of 'for' statement
  accepts.resize(accepts.length() - 1); // Remove the last ','
  ::osip_message_set_accept(*p_sip_message, ::strdup(accepts.c_str()));
  
  return 0;
} // End of method encode_accept_header

int sip_codec_headers::encode_accept_contact_header(const LibSip__SIPTypesAndValues::AcceptContact& p_accept_contact, osip_message_t** p_sip_message) {
  loggers::get_instance().log(">>> sip_codec_headers::encode_accept_contact_header");

  const LibSip__SIPTypesAndValues::AcRcValue__List& al = p_accept_contact.acValues();
  if (al.lengthof() == 0) {
    return 0;
  }

  std::string accepts;
  for (int i = 0; i < al.lengthof(); i++) {
    const LibSip__SIPTypesAndValues::AcRcValue& a = al[i];
    loggers::get_instance().log_msg("sip_codec_headers::encode_accept_contact_header: a: ", a);
    accepts += static_cast<const char*>(a.wildcard());
    if (a.acRcParams().is_present()) {
      const LibSip__Common::SemicolonParam__List& l = static_cast<const LibSip__Common::SemicolonParam__List&>(*a.acRcParams().get_opt_value());
      for (int j = 0; j < l.lengthof(); j++) {
        accepts += ";";
        const LibSip__Common::GenericParam& p = l[j];
        accepts += static_cast<const char*>(p.id());
        if (p.paramValue().is_present()) {
          const LibSip__Common::GenValue& g = static_cast<const LibSip__Common::GenValue&>(*p.paramValue().get_opt_value());;
          accepts += "=";
          if (g.ischosen(LibSip__Common::GenValue::ALT_tokenOrHost)) {
            accepts += static_cast<const char*>(g.tokenOrHost());
          } else {
            accepts += static_cast<const char*>(g.quotedString());
          }
        }
      } // End of 'for' statement
    }
    accepts += ",";
    loggers::get_instance().log("sip_codec_headers::encode_accept_header: accepts: %s", accepts.c_str());
  } // End of 'for' statement
  accepts.resize(accepts.length() - 1); // Remove the last ','
  ::osip_message_set_header(*p_sip_message, (const char *)"Accept-Contact", ::strdup(accepts.c_str()));

  loggers::get_instance().log("<<< sip_codec_headers::encode_accept_contact_header");
  return 0;
} // End of method encode_accept_contact_header

int sip_codec_headers::encode_allow_header(const OPTIONAL<LibSip__SIPTypesAndValues::Allow>& p_allow, osip_message_t** p_sip_message)
{
  loggers::get_instance().log_msg(">>> sip_codec_headers::encode_allow_header", p_allow);

  const LibSip__SIPTypesAndValues::Allow& allow = static_cast<const LibSip__SIPTypesAndValues::Allow&>(*p_allow.get_opt_value());

  if (!allow.methods().is_present()) {
    return 0;
  }
  
  const LibSip__SIPTypesAndValues::Method__List& m = static_cast<const LibSip__SIPTypesAndValues::Method__List&>(*allow.methods().get_opt_value());
  if (m.lengthof() == 0) {
    return 0;
  }
  
  std::string str(static_cast<const char*>(m[0]));
  if (m.lengthof() > 1) {
    int i = 1;
    do {
      str += ",";
      str += static_cast<const char*>(m[i++]);
    } while (i < m.lengthof());
  }
  ::osip_message_set_header((osip_message_t *)*p_sip_message,(const char *)"Allow", str.c_str());
  
  loggers::get_instance().log("<<< sip_codec_headers::encode_allow_header");
  return 0;
} // End of method encode_allow_header

int sip_codec_headers::encode_authorization_header(const LibSip__SIPTypesAndValues::Authorization& p_authorization, osip_authorization_t** p_authorization_header)
{
  loggers::get_instance().log(">>> sip_codec_headers::encode_authorization_header");
  
  ::osip_authorization_init(p_authorization_header);

  const LibSip__SIPTypesAndValues::CredentialsList& l = p_authorization.body();
  int i = 0;
  do {
    loggers::get_instance().log("sip_codec_headers::encode_authorization_header: Processing item #%d", i);
    const LibSip__SIPTypesAndValues::Credentials& c = l[i++];
    if (c.ischosen(LibSip__SIPTypesAndValues::Credentials::ALT_digestResponse)) {
      bool processed = true;
      const LibSip__Common::CommaParam__List& p = c.digestResponse();
      if (p.lengthof() > 0) {
        loggers::get_instance().log_msg("sip_codec_headers::encode_authorization_header: Processing param ", p);
        int j = 0;
        do {
          const LibSip__Common::GenericParam& g = p[j++];
          std::string str(static_cast<const char*>(g.id()));
          if (str.compare("realm") == 0) {
            loggers::get_instance().log("sip_codec_headers::encode_authorization_header: realm found");
            if (g.paramValue().is_present()) {
              const LibSip__Common::GenValue& v = static_cast<const LibSip__Common::GenValue&>(*g.paramValue().get_opt_value());
              loggers::get_instance().log_msg("sip_codec_headers::encode_authorization_header: GenValue: ", v);
              if (v.ischosen(LibSip__Common::GenValue::ALT_tokenOrHost)) {
                loggers::get_instance().log_msg("sip_codec_headers::encode_authorization_header: tokenOrHost: ", v.tokenOrHost());
                ::osip_authorization_set_realm(*p_authorization_header, (char*)::strdup(static_cast<const char*>(v.tokenOrHost())));
              } else {
                loggers::get_instance().log_msg("sip_codec_headers::encode_authorization_header: quotedString: ", v.quotedString());
                ::osip_authorization_set_realm(*p_authorization_header, (char*)::strdup(static_cast<const char*>(v.quotedString())));
              }
            } else {
              loggers::get_instance().error("sip_codec_headers::encode_authorization_header: Not implemented(4)");
            }
          } else if (str.compare("username") == 0) {
            loggers::get_instance().log("sip_codec_headers::encode_authorization_header: username found");
            if (g.paramValue().is_present()) {
              const LibSip__Common::GenValue& v = static_cast<const LibSip__Common::GenValue&>(*g.paramValue().get_opt_value());
              loggers::get_instance().log_msg("sip_codec_headers::encode_authorization_header: GenValue: ", v);
              if (v.ischosen(LibSip__Common::GenValue::ALT_tokenOrHost)) {
                loggers::get_instance().log_msg("sip_codec_headers::encode_authorization_header: tokenOrHost: ", v.tokenOrHost());
                ::osip_authorization_set_username(*p_authorization_header, (char*)::strdup(static_cast<const char*>(v.tokenOrHost())));
              } else {
                loggers::get_instance().log_msg("sip_codec_headers::encode_authorization_header: quotedString: ", v.quotedString());
                ::osip_authorization_set_username(*p_authorization_header, (char*)::strdup(static_cast<const char*>(v.quotedString())));
              }
            } else {
              loggers::get_instance().error("sip_codec_headers::encode_authorization_header: Not implemented(6)");
            }
          } else if (str.compare("uri") == 0) {
            loggers::get_instance().log("sip_codec_headers::encode_authorization_header: uri found");
            if (g.paramValue().is_present()) {
              const LibSip__Common::GenValue& v = static_cast<const LibSip__Common::GenValue&>(*g.paramValue().get_opt_value());
              loggers::get_instance().log_msg("sip_codec_headers::encode_authorization_header: GenValue: ", v);
              if (v.ischosen(LibSip__Common::GenValue::ALT_tokenOrHost)) {
                loggers::get_instance().log_msg("sip_codec_headers::encode_authorization_header: tokenOrHost: ", v.tokenOrHost());
                ::osip_authorization_set_uri(*p_authorization_header, (char*)::strdup(static_cast<const char*>(v.tokenOrHost())));
              } else {
                loggers::get_instance().log_msg("sip_codec_headers::encode_authorization_header: quotedString: ", v.quotedString());
                ::osip_authorization_set_uri(*p_authorization_header, (char*)::strdup(static_cast<const char*>(v.quotedString())));
              }
            } else {
              loggers::get_instance().error("sip_codec_headers::encode_authorization_header: Not implemented(7)");
            }
          } else if (str.compare("nonce") == 0) {
            loggers::get_instance().log("sip_codec_headers::encode_authorization_header: nonce found");
            if (g.paramValue().is_present()) {
              const LibSip__Common::GenValue& v = static_cast<const LibSip__Common::GenValue&>(*g.paramValue().get_opt_value());
              loggers::get_instance().log_msg("sip_codec_headers::encode_authorization_header: GenValue: ", v);
              if (v.ischosen(LibSip__Common::GenValue::ALT_tokenOrHost)) {
                loggers::get_instance().log_msg("sip_codec_headers::encode_authorization_header: tokenOrHost: ", v.tokenOrHost());
                ::osip_authorization_set_nonce(*p_authorization_header, (char*)::strdup(static_cast<const char*>(v.tokenOrHost())));
              } else {
                loggers::get_instance().log_msg("sip_codec_headers::encode_authorization_header: quotedString: ", v.quotedString());
                ::osip_authorization_set_nonce(*p_authorization_header, (char*)::strdup(static_cast<const char*>(v.quotedString())));
              }
            } else {
              loggers::get_instance().error("sip_codec_headers::encode_authorization_header: Not implemented(10)");
            }
          } else if (str.compare("response") == 0) {
            loggers::get_instance().log("sip_codec_headers::encode_authorization_header: response found");
            if (g.paramValue().is_present()) {
              const LibSip__Common::GenValue& v = static_cast<const LibSip__Common::GenValue&>(*g.paramValue().get_opt_value());
              loggers::get_instance().log_msg("sip_codec_headers::encode_authorization_header: GenValue: ", v);
              if (v.ischosen(LibSip__Common::GenValue::ALT_tokenOrHost)) {
                loggers::get_instance().log_msg("sip_codec_headers::encode_authorization_header: tokenOrHost: ", v.tokenOrHost());
                ::osip_authorization_set_response(*p_authorization_header, (char*)::strdup(static_cast<const char*>(v.tokenOrHost())));
              } else {
                loggers::get_instance().log_msg("sip_codec_headers::encode_authorization_header: quotedString: ", v.quotedString());
                ::osip_authorization_set_response(*p_authorization_header, (char*)::strdup(static_cast<const char*>(v.quotedString())));
              }
            } else {
              loggers::get_instance().error("sip_codec_headers::encode_authorization_header: Not implemented(12)");
            }
          } else {
            loggers::get_instance().log("sip_codec_headers::encode_authorization_header: Set processed to false for %s", str.c_str());
            processed = false;
          }
        } while (j < p.lengthof());
      }
      loggers::get_instance().log("sip_codec_headers::encode_authorization_header: processed: %x", processed);
      if (processed) {
        ::osip_authorization_set_auth_type(*p_authorization_header, (char*)::strdup("Digest"));
      }
    } else {
      const LibSip__SIPTypesAndValues::OtherAuth& o = c.otherResponse();
      loggers::get_instance().error("sip_codec_headers::encode_authorization_header: Not implemented");
    }
  } while (i < l.lengthof());
  
  return 0;
} // End of method encode_authorization_header

int sip_codec_headers::encode_call_id_header(const LibSip__SIPTypesAndValues::CallId& p_call_id, osip_call_id_t** p_call_id_header) {
  loggers::get_instance().log_msg(">>> sip_codec_headers::encode_call_id_header", p_call_id.callid());
  
  ::osip_call_id_init(p_call_id_header);
  ::osip_call_id_parse(*p_call_id_header, static_cast<const char*>(p_call_id.callid()));
  
  loggers::get_instance().log("<<< sip_codec_headers::encode_call_id_header");
  return 0;
} // End of method encode_call_id_header

int sip_codec_headers::encode_call_info_header(const OPTIONAL<LibSip__SIPTypesAndValues::CallInfo>& p_call_info, osip_message_t** p_sip_message) {
  loggers::get_instance().log_msg(">>> sip_codec_headers::encode_call_info_header", p_call_info);
  
  const LibSip__SIPTypesAndValues::CallInfo& call_info = static_cast<const LibSip__SIPTypesAndValues::CallInfo&>(*p_call_info.get_opt_value());

  if (!call_info.callInfoBody().is_present()) {
    return 0;
  }
  
  const LibSip__SIPTypesAndValues::CallInfoBody__List& c = static_cast<const LibSip__SIPTypesAndValues::CallInfoBody__List&>(*call_info.callInfoBody().get_opt_value());
  if (c.lengthof() == 0) {
    return 0;
  }
  
  int pos = 0;
  std::string value;
  do {
    const LibSip__SIPTypesAndValues::CallInfoBody& call_info_body = c[pos++];
    loggers::get_instance().log_msg("sip_codec_headers::encode_call_info_header: Processing ", call_info_body);
    osip_call_info_t *header;
    ::osip_call_info_init(&header);
    ::osip_call_info_set_uri(header, (char*)static_cast<const char*>(call_info_body.url()));
    if (call_info_body.infoParams().is_present()) {
      encode_semi_colon_params(static_cast<const LibSip__Common::SemicolonParam__List>(call_info_body.infoParams()), &(header)->gen_params);
    }
    char *buffer;
    ::osip_call_info_to_str(header, &buffer);
    value += buffer;
    osip_free(buffer);
    osip_free(header);
    loggers::get_instance().log("sip_codec_headers::encode_call_info_header: value=%s", value.c_str());
  } while (pos < c.lengthof());
  ::osip_message_set_header((osip_message_t *)*p_sip_message, (const char *)"callInfo", value.c_str()); 
  loggers::get_instance().log("<<< sip_codec_headers::encode_call_info_header");
  return 0;
} // End of method encode_call_info_header

int sip_codec_headers::encode_contact_header(const LibSip__SIPTypesAndValues::Contact& p_contact, osip_contact_t** p_contact_header) {
  loggers::get_instance().log(">>> sip_codec_headers::encode_contact_header");

  ::osip_contact_init(p_contact_header);
  const LibSip__SIPTypesAndValues::ContactBody& body = p_contact.contactBody();
  if (body.ischosen(LibSip__SIPTypesAndValues::ContactBody::ALT_wildcard)) {
    const CHARSTRING& wildcard = body.wildcard();
    loggers::get_instance().warning("sip_codec_headers::encode_contact_header: wildcard not implemented yet");
    *p_contact_header = nullptr;
    return -1;
  } else if (body.ischosen(LibSip__SIPTypesAndValues::ContactBody::ALT_contactAddresses)) {
    const LibSip__SIPTypesAndValues::ContactAddress__List& l = body.contactAddresses();
    // Encode AddressField
    for (int i = 0; i < l.size_of(); i++) {
      osip_uri_t* uri = nullptr;
      const LibSip__SIPTypesAndValues::ContactAddress c = l[i];
      if (c.addressField().ischosen(LibSip__SIPTypesAndValues::Addr__Union::ALT_nameAddr)) {
        const LibSip__SIPTypesAndValues::NameAddr& addr = c.addressField().nameAddr();
        if (encode_sip_url(addr.addrSpec(), &uri) == -1) {
          loggers::get_instance().warning("sip_codec_headers::encode_contact_header: Failed to encode SipUrl");
          ::osip_contact_free(*p_contact_header);
          *p_contact_header = nullptr;
          return -1;
        }
        ::osip_contact_set_url(*p_contact_header, uri);
        if (addr.displayName().is_present()) {
          const LibSip__SIPTypesAndValues::DisplayName& n = static_cast<const LibSip__SIPTypesAndValues::DisplayName&>(addr.displayName());
          if (n.ischosen(LibSip__SIPTypesAndValues::DisplayName::ALT_token)) {
            ::osip_contact_set_displayname(*p_contact_header, (char*)::strdup(static_cast<const char*>(static_cast<CHARSTRING>(n.token()))));
          } else if (n.ischosen(LibSip__SIPTypesAndValues::DisplayName::ALT_quotedString)) {
            ::osip_contact_set_displayname(*p_contact_header, (char*)::strdup(static_cast<const char*>(static_cast<CHARSTRING>(n.quotedString()))));
          } else {
            loggers::get_instance().warning("sip_codec_headers::encode_contact_header: Failed to encode DisplayName");
            ::osip_contact_free(*p_contact_header);
            *p_contact_header = nullptr;
            return -1;
          }
        }
      } else if (c.addressField().ischosen(LibSip__SIPTypesAndValues::Addr__Union::ALT_addrSpecUnion)) {
        if (encode_sip_url(c.addressField().addrSpecUnion(), &uri) == -1) {
          loggers::get_instance().warning("sip_codec_headers::encode_contact_header: Failed to encode SipUrl");
          ::osip_contact_free(*p_contact_header);
          *p_contact_header = nullptr;
          return -1;
        }
        ::osip_contact_set_url(*p_contact_header, uri);
      } else {
        loggers::get_instance().warning("sip_codec_headers::encode_contact_header: Failed to encode Addr__Union");
        ::osip_contact_free(*p_contact_header);
        *p_contact_header = nullptr;
        return -1;
      }
      // Encode contactParams
      if (c.contactParams().is_present()) {
        encode_semi_colon_params(static_cast<const LibSip__Common::SemicolonParam__List>(c.contactParams()), &(*p_contact_header)->gen_params);
      }

    } // End of 'for' statement
  } else {
    return -1;
  }
  
  loggers::get_instance().log("<<< sip_codec_headers::encode_contact_header");
  return 0;
} // End of method encode_contact_header

int sip_codec_headers::encode_content_length_header(const LibSip__SIPTypesAndValues::ContentLength& p_content_length, osip_content_length_t** p_content_length_header)
{
  loggers::get_instance().log(">>> sip_codec_headers::encode_content_length_header");

  ::osip_content_length_init(p_content_length_header);
  (*p_content_length_header)->value = (char*)::strdup(std::to_string(static_cast<const int>(p_content_length.len())).c_str());
  
  loggers::get_instance().log("<<< sip_codec_headers::encode_content_length_header");
  return 0;
} // End of method encode_content_length_header

int sip_codec_headers::encode_content_type_header(const LibSip__SIPTypesAndValues::ContentType& p_content_type, osip_content_type_t** p_content_type_header)
{
  loggers::get_instance().log_msg(">>> sip_codec_headers::encode_content_type_header: ", p_content_type);

  ::osip_content_type_init(p_content_type_header);

  // Split type/subtype using '/' as separator
  std::vector<std::string> output = converter::get_instance().split(static_cast<const char*>(p_content_type.mTypeSubtype()), "/");
  (*p_content_type_header)->type = ::strdup(output[0].c_str());
  if (output.size() > 1) {
    (*p_content_type_header)->subtype = ::strdup(output[1].c_str());
  }
  
  if (p_content_type.mParams().is_present()) {
    encode_semi_colon_params(static_cast<const LibSip__Common::SemicolonParam__List>(p_content_type.mParams()), &((*p_content_type_header)->gen_params));
  }
  
  loggers::get_instance().log("<<< sip_codec_headers::encode_content_type_header");
  return 0;
} // End of method encode_content_type_header

int sip_codec_headers::encode_c_seq_header(const LibSip__SIPTypesAndValues::CSeq& p_c_seq, osip_cseq_t** p_c_seq_header)
{
  loggers::get_instance().log(">>> sip_codec_headers::encode_c_seq_header");

  ::osip_cseq_init(p_c_seq_header);
  ::osip_cseq_set_number(*p_c_seq_header, (char*)::strdup(std::to_string(static_cast<const int>(p_c_seq.seqNumber())).c_str()));
  ::osip_cseq_set_method(*p_c_seq_header, (char*)::strdup(static_cast<const char*>(p_c_seq.method())));
  
  return 0;
} // End of method encode_c_seq_header

int sip_codec_headers::encode_event_header(const OPTIONAL<LibSip__SIPTypesAndValues::Event>& p_event, osip_message_t** p_sip_message) {
  loggers::get_instance().log(">>> sip_codec_headers::encode_event_header");

  if (!p_event.is_present()) {
    return 0;
  }
  const LibSip__SIPTypesAndValues::Event& event = static_cast<const LibSip__SIPTypesAndValues::Event&>(*p_event.get_opt_value());

  // eventType
  std::string value(static_cast<const char*>(event.eventType()));
  loggers::get_instance().log("sip_codec_headers::encode_event_header: eventType: %s", value.c_str());

  // eventParam
  const OPTIONAL<LibSip__Common::SemicolonParam__List>& event_param = event.eventParams(); // TODO Create a method to fill an std::string with SemicolonParam__List
  if (event_param.is_present()) {
    const LibSip__Common::SemicolonParam__List& l = static_cast<const LibSip__Common::SemicolonParam__List&>(*event_param.get_opt_value());
    int i = 0;
    do {
      value += ";";
      const LibSip__Common::GenericParam& g = l[i];
      value += static_cast<const char*>(g.id());
      if (g.paramValue().is_present()) {
        value += "=";
        const LibSip__Common::GenValue& v = static_cast<const LibSip__Common::GenValue&>(*g.paramValue().get_opt_value());
        if (v.ischosen(LibSip__Common::GenValue::ALT_tokenOrHost)) {
          value += static_cast<const char*>(v.tokenOrHost());
        } else {
          value += static_cast<const char*>(v.quotedString());
        }
      }
      i += 1;
    } while (i < l.lengthof());
  }
  loggers::get_instance().log("sip_codec_headers::encode_event_header: %s", value.c_str());
  ::osip_message_set_header((osip_message_t *)*p_sip_message,(const char *)"Event", value.c_str());

  return 0;
}

int sip_codec_headers::encode_expires_header(const OPTIONAL<LibSip__SIPTypesAndValues::Expires>& p_expires, osip_message_t** p_sip_message) {
  loggers::get_instance().log(">>> sip_codec_headers::encode_expires_header");

  if (!p_expires.is_present()) {
    return 0;
  }
  const LibSip__SIPTypesAndValues::Expires& expires = static_cast<const LibSip__SIPTypesAndValues::Expires&>(*p_expires.get_opt_value());

  // deltaSec
  std::string value(static_cast<const char*>(expires.deltaSec()));

  loggers::get_instance().log("sip_codec_headers::encode_expires_header: %s", value.c_str());
  ::osip_message_set_header((osip_message_t *)*p_sip_message,(const char *)"Expires", value.c_str());

  return 0;
}

int sip_codec_headers::encode_from_header(const LibSip__SIPTypesAndValues::From& p_from, osip_from_t** p_from_header) {
  loggers::get_instance().log(">>> sip_codec_headers::encode_from_header");
  
  ::osip_from_init(p_from_header);
  // Endode addressField
  osip_uri_t* uri = nullptr;
  const LibSip__SIPTypesAndValues::Addr__Union& a = p_from.addressField();
  if (a.ischosen(LibSip__SIPTypesAndValues::Addr__Union::ALT_nameAddr)) {
    const LibSip__SIPTypesAndValues::NameAddr& addr = a.nameAddr();
    if (encode_sip_url(addr.addrSpec(), &uri) == -1) {
      loggers::get_instance().warning("sip_codec_headers::encode_from_header: Failed to encode SipUrl");
      ::osip_from_free(*p_from_header);
      *p_from_header = nullptr;
      return -1;
    }
    ::osip_from_set_url(*p_from_header, uri);
    if (addr.displayName().is_present()) {
      const LibSip__SIPTypesAndValues::DisplayName& n = static_cast<const LibSip__SIPTypesAndValues::DisplayName&>(addr.displayName());
      if (n.ischosen(LibSip__SIPTypesAndValues::DisplayName::ALT_token)) {
        ::osip_from_set_displayname(*p_from_header, (char*)::strdup(static_cast<const char*>(static_cast<CHARSTRING>(n.token()))));
      } else if (n.ischosen(LibSip__SIPTypesAndValues::DisplayName::ALT_quotedString)) {
        ::osip_from_set_displayname(*p_from_header, (char*)::strdup(static_cast<const char*>(static_cast<CHARSTRING>(n.quotedString()))));
      } else {
        loggers::get_instance().warning("sip_codec_headers::encode_from_header: Failed to encode DisplayName");
        ::osip_from_free(*p_from_header);
        *p_from_header = nullptr;
        return -1;
      }
    }
  } else if (a.ischosen(LibSip__SIPTypesAndValues::Addr__Union::ALT_addrSpecUnion)) {
    if (encode_sip_url(a.addrSpecUnion(), &uri) == -1) {
      loggers::get_instance().warning("sip_codec_headers::encode_from_header: Failed to encode SipUrl");
      ::osip_from_free(*p_from_header);
      *p_from_header = nullptr;
      return -1;
    }
    ::osip_from_set_url(*p_from_header, uri);
  } else {
    loggers::get_instance().warning("sip_codec_headers::encode_from_header: Failed to encode Addr__Union");
    ::osip_from_free(*p_from_header);
    *p_from_header = nullptr;
    return -1;
  }
  // Encode fromParams
  if (p_from.fromParams().is_present()) {
    encode_semi_colon_params(static_cast<const LibSip__Common::SemicolonParam__List>(p_from.fromParams()), &(*p_from_header)->gen_params);
  }
  
  return 0;
} // End of method encode_from_header

int sip_codec_headers::encode_geolocation_header(const OPTIONAL<LibSip__SIPTypesAndValues::Geolocation>& p_geolocation, osip_message_t** p_sip_message) {
  loggers::get_instance().log(">>> sip_codec_headers::encode_geolocation_header");

  if (!p_geolocation.is_present()) {
    return 0;
  }
  const LibSip__SIPTypesAndValues::Geolocation& geolocation = static_cast<const LibSip__SIPTypesAndValues::Geolocation&>(*p_geolocation.get_opt_value());

  // addrSpec
  const LibSip__SIPTypesAndValues::SipUrl& addr = geolocation.addrSpec();
  osip_uri_t* uri = nullptr;
  if (encode_sip_url(addr, &uri) == -1) {
    loggers::get_instance().warning("sip_codec_headers::encode_geolocation_header: Failed to encode SipUrl");
    return -1;
  }
  char *buff = nullptr;
  if (::osip_uri_to_str(uri, &buff) != 0) {
   loggers::get_instance().warning("sip_codec_headers::encode_geolocation_header: Failed to convert SipUrl");
    return -1;
  }
  std::string value(buff);
  osip_free(buff);
  loggers::get_instance().log("sip_codec_headers::encode_geolocation_header: addrSpec: %s", value.c_str());
  // geolocParam
  const OPTIONAL<LibSip__Common::SemicolonParam__List>& geoloc_param = geolocation.geolocParam(); // TODO Create a method to fill an std::string with SemicolonParam__List
  if (geoloc_param.is_present()) {
    const LibSip__Common::SemicolonParam__List& l = static_cast<const LibSip__Common::SemicolonParam__List&>(*geoloc_param.get_opt_value());
    int i = 0;
    do {
      value += ";";
      const LibSip__Common::GenericParam& g = l[i];
      value += static_cast<const char*>(g.id());
      if (g.paramValue().is_present()) {
        value += "=";
        const LibSip__Common::GenValue& v = static_cast<const LibSip__Common::GenValue&>(*g.paramValue().get_opt_value());
        if (v.ischosen(LibSip__Common::GenValue::ALT_tokenOrHost)) {
          value += static_cast<const char*>(v.tokenOrHost());
        } else {
          value += static_cast<const char*>(v.quotedString());
        }
      }
      i += 1;
    } while (i < l.lengthof());
  }
  loggers::get_instance().log("sip_codec_headers::encode_geolocation_header: %s", value.c_str());
  ::osip_message_set_header((osip_message_t *)*p_sip_message,(const char *)"Geolocation", value.c_str());

  return 0;
}

int sip_codec_headers::encode_geolocation_routing_header(const OPTIONAL<LibSip__SIPTypesAndValues::GeolocationRouting>& p_geolocation_routing, osip_message_t** p_sip_message) {
  loggers::get_instance().log(">>> sip_codec_headers::encode_geolocation_routing_header");

  if (!p_geolocation_routing.is_present()) {
    return 0;
  }
  const LibSip__SIPTypesAndValues::GeolocationRouting& geolocation_routing = static_cast<const LibSip__SIPTypesAndValues::GeolocationRouting&>(*p_geolocation_routing.get_opt_value());
  std::string value;
  if (geolocation_routing.state() == LibSip__SIPTypesAndValues::GeolocationRoutingState::GEOLOCATION__ROUTING__YES__E) {
    value = "yes";
  } else if (geolocation_routing.state() == LibSip__SIPTypesAndValues::GeolocationRoutingState::GEOLOCATION__ROUTING__NO__E) {
    value = "no";
  } else {
    value = "other";
  }
  loggers::get_instance().log("sip_codec_headers::encode_geolocation_routing_header: state: %s", value.c_str());
  // genericValue
  const OPTIONAL<LibSip__Common::GenericParam>& generic_value = geolocation_routing.genericValue();
  if (generic_value.is_present()) {
    const LibSip__Common::GenericParam& g = static_cast<const LibSip__Common::GenericParam&>(*geolocation_routing.genericValue().get_opt_value());
    value += ";";
    value += static_cast<const char*>(g.id());
    if (g.paramValue().is_present()) {
      value += "=";
      const LibSip__Common::GenValue& v = static_cast<const LibSip__Common::GenValue&>(*g.paramValue().get_opt_value());
      if (v.ischosen(LibSip__Common::GenValue::ALT_tokenOrHost)) {
        value += static_cast<const char*>(v.tokenOrHost());
      } else {
        value += static_cast<const char*>(v.quotedString());
      }
    }
  }
  
  loggers::get_instance().log("sip_codec_headers::encode_geolocation_routing_header: %s", value.c_str());
  ::osip_message_set_header((osip_message_t *)*p_sip_message,(const char *)"Geolocation-Routing", value.c_str());

  return 0;
}

int sip_codec_headers::encode_max_forwards_header(const OPTIONAL<LibSip__SIPTypesAndValues::MaxForwards>& p_max_forwards, osip_message_t** p_sip_message) {
  loggers::get_instance().log(">>> sip_codec_headers::encode_max_forwards_header");

  if (!p_max_forwards.is_present()) {
    return 0;
  }
  
  const LibSip__SIPTypesAndValues::MaxForwards& max_forwards = static_cast<const LibSip__SIPTypesAndValues::MaxForwards&>(*p_max_forwards.get_opt_value());
  osip_message_set_max_forwards(*p_sip_message, std::to_string(static_cast<int>(max_forwards.forwards())).c_str());
  
  return 0;
}

int sip_codec_headers::encode_min_se_header(const OPTIONAL<LibSip__SIPTypesAndValues::MinSE>& p_min_se, osip_message_t** p_sip_message) {
  loggers::get_instance().log_msg(">>> sip_codec_headers::encode_min_se_header", p_min_se);

  const LibSip__SIPTypesAndValues::MinSE& min_se = static_cast<const LibSip__SIPTypesAndValues::MinSE&>(*p_min_se.get_opt_value());
  // deltaSec
  std::string value(static_cast<const char*>(min_se.deltaSec()));
  // seParam
  const OPTIONAL<LibSip__Common::SemicolonParam__List>& se_param = min_se.minSeParam(); // TODO Create a method to fill an std::string with SemicolonParam__List
  if (se_param.is_present()) {
    const LibSip__Common::SemicolonParam__List& l = static_cast<const LibSip__Common::SemicolonParam__List&>(*se_param.get_opt_value());
    int i = 0;
    do {
      value += ";";
      const LibSip__Common::GenericParam& g = l[i];
      value += static_cast<const char*>(g.id());
      if (g.paramValue().is_present()) {
        value += "=";
        const LibSip__Common::GenValue& v = static_cast<const LibSip__Common::GenValue&>(*g.paramValue().get_opt_value());
        if (v.ischosen(LibSip__Common::GenValue::ALT_tokenOrHost)) {
          value += static_cast<const char*>(v.tokenOrHost());
        } else {
          value += static_cast<const char*>(v.quotedString());
        }
      }
      i += 1;
    } while (i < l.lengthof());
  }
  ::osip_message_set_header((osip_message_t *)*p_sip_message,(const char *)"Min-SE", value.c_str());
  
  return 0;
}

int sip_codec_headers::encode_p_access_network_info_header(const OPTIONAL<LibSip__SIPTypesAndValues::PAccessNetworkInfo>& p_p_access_network_info_header, osip_message_t** p_sip_message) {
  loggers::get_instance().log_msg(">>> sip_codec_headers::encode_p_access_network_info_header", p_p_access_network_info_header);

  const LibSip__SIPTypesAndValues::PAccessNetworkInfo& p_access_network_info_header = static_cast<const LibSip__SIPTypesAndValues::PAccessNetworkInfo&>(*p_p_access_network_info_header.get_opt_value());
  // accessType
  std::string value(static_cast<const char*>(p_access_network_info_header.accessType()));
  // Generic parameters
  const OPTIONAL<LibSip__Common::SemicolonParam__List>& p_access_network_info_param = p_access_network_info_header.genericParams(); // TODO Create a method to fill an std::string with SemicolonParam__List
  if (p_access_network_info_param.is_present()) {
    const LibSip__Common::SemicolonParam__List& l = static_cast<const LibSip__Common::SemicolonParam__List&>(*p_access_network_info_param.get_opt_value());
    int i = 0;
    do {
      value += ";";
      const LibSip__Common::GenericParam& g = l[i];
      value += static_cast<const char*>(g.id());
      if (g.paramValue().is_present()) {
        value += "=";
        const LibSip__Common::GenValue& v = static_cast<const LibSip__Common::GenValue&>(*g.paramValue().get_opt_value());
        if (v.ischosen(LibSip__Common::GenValue::ALT_tokenOrHost)) {
          value += static_cast<const char*>(v.tokenOrHost());
        } else {
          value += static_cast<const char*>(v.quotedString());
        }
      }
      i += 1;
    } while (i < l.lengthof());
  }
  ::osip_message_set_header((osip_message_t *)*p_sip_message, (const char *)"P-Access-Network-Info", value.c_str());
  
  return 0;
} // End of method encode_p_access_network_info_header

int sip_codec_headers::encode_p_associated_uri_header(const OPTIONAL<LibSip__SIPTypesAndValues::PAssociatedURI>& p_p_associated_uri_header, osip_message_t** p_sip_message) {
  loggers::get_instance().log_msg(">>> sip_codec_headers::encode_p_associated_uri_header", p_p_associated_uri_header);
  
  if (!p_p_associated_uri_header.is_present()) {
    return 0;
  }
  const LibSip__SIPTypesAndValues::PAssociatedURI& p_associated_uri_header = static_cast<const LibSip__SIPTypesAndValues::PAssociatedURI&>(*p_p_associated_uri_header.get_opt_value());
  
  const LibSip__SIPTypesAndValues::NameAddrParam__List& l = p_associated_uri_header.nameAddrList();
  std::string value;
  for (int i = 0; i < l.lengthof(); i++) {
    osip_uri_t* uri = nullptr;
    if (encode_sip_url(l[i].nameAddr().addrSpec(), &uri) == -1) {
      loggers::get_instance().warning("sip_codec_headers::encode_p_associated_uri_header: Failed to encode SipUrl");
      return -1;
    }
    char *buff = nullptr;
    if (::osip_uri_to_str(uri, &buff) != 0) {
      loggers::get_instance().warning("sip_codec_headers::encode_p_associated_uri_header: Failed to convert SipUrl");
      return -1;
    }
    value += buff;
    osip_free(buff);
    if (l[i].genericParams().is_present()) {
      // TODO To be implemented
      loggers::get_instance().warning("sip_codec_headers::encode_p_associated_uri_header: To be implemented");
    }
    value += ",";
  } // End of 'for' statement
  ::osip_message_set_header((osip_message_t *)*p_sip_message, (const char *)"P-Associated-URI", value.c_str());
  return 0;
}

int sip_codec_headers::encode_privacy_header(const OPTIONAL<LibSip__SIPTypesAndValues::Privacy>& p_privacy_header, osip_message_t** p_sip_message) {
  loggers::get_instance().log_msg(">>> sip_codec_headers::encode_privacy_header", p_privacy_header);

  const LibSip__SIPTypesAndValues::Privacy& privacy_header = static_cast<const LibSip__SIPTypesAndValues::Privacy&>(*p_privacy_header.get_opt_value());
  
  const LibSip__SIPTypesAndValues::PrivacyValue__List& m = privacy_header.privValueList();
  if (m.lengthof() == 0) {
    return 0;
  }
  
  std::string str(static_cast<const char*>(m[0]));
  if (m.lengthof() > 1) {
    int i = 1;
    do {
      str += ",";
      str += static_cast<const char*>(m[i++]);
    } while (i < m.lengthof());
  }
  ::osip_message_set_header((osip_message_t *)*p_sip_message, (const char *)"Privacy", str.c_str());
  
  loggers::get_instance().log("<<< sip_codec_headers::encode_privacy_header");
  return 0;
} // End of method encode_privacy_header

int sip_codec_headers::encode_route_header(const OPTIONAL<LibSip__SIPTypesAndValues::Route>& p_route_header, osip_message_t** p_sip_message) {
  loggers::get_instance().log(">>> sip_codec_headers::encode_route_header", p_route_header);

  osip_route_t* route_header;
  ::osip_route_init(&route_header);
  const LibSip__SIPTypesAndValues::Route& r = static_cast<const LibSip__SIPTypesAndValues::Route&>(*p_route_header.get_opt_value());
  const LibSip__SIPTypesAndValues::RouteBody__List& l = r.routeBody();
  for (int i = 0; i < l.lengthof(); i++) {
      const LibSip__SIPTypesAndValues::NameAddr& addr = l[i].nameAddr();
      osip_uri_t* uri = nullptr;
      if (encode_sip_url(addr.addrSpec(), &uri) == -1) {
        loggers::get_instance().warning("sip_codec_headers::encode_route_header: Failed to encode SipUrl");
        ::osip_route_free(route_header);
        return -1;
      }
      ::osip_route_set_url(route_header, uri);
      // Encode rrParam
      if (l[i].rrParam().is_present()) {
        encode_semi_colon_params(static_cast<const LibSip__Common::SemicolonParam__List>(l[i].rrParam()), &(route_header)->gen_params);
      }
  } // End of 'for' statement
  
  char* hvalue;
  int result = ::osip_route_to_str(route_header, &hvalue);
  loggers::get_instance().log("sip_codec_headers::encode_route_header: '%s'- result:%d", hvalue, result);
  if (::osip_message_set_route(*p_sip_message, hvalue) != OSIP_SUCCESS) {
    loggers::get_instance().warning("sip_codec_headers::encode_route_header: Failed to set Route header in sip_message");
    return -1;
  }
  ::osip_route_free(route_header);
  osip_free(hvalue);
  
  return 0;
}

int sip_codec_headers::encode_record_route_header(const OPTIONAL<LibSip__SIPTypesAndValues::RecordRoute>& p_record_route_header, osip_message_t** p_sip_message) {
  loggers::get_instance().log(">>> sip_codec_headers::encode_record_route_header", p_record_route_header);

  osip_record_route_t* record_route_header;
  ::osip_record_route_init(&record_route_header);
  const LibSip__SIPTypesAndValues::RecordRoute& r = static_cast<const LibSip__SIPTypesAndValues::RecordRoute&>(*p_record_route_header.get_opt_value());
  const LibSip__SIPTypesAndValues::RouteBody__List& l = r.routeBody();
  for (int i = 0; i < l.lengthof(); i++) {
      const LibSip__SIPTypesAndValues::NameAddr& addr = l[i].nameAddr();
      osip_uri_t* uri = nullptr;
      if (encode_sip_url(addr.addrSpec(), &uri) == -1) {
        loggers::get_instance().warning("sip_codec_headers::encode_record_route_header: Failed to encode SipUrl");
        ::osip_record_route_free(record_route_header);
        return -1;
      }
      ::osip_record_route_set_url(record_route_header, uri);
      // Encode rrParam
      if (l[i].rrParam().is_present()) {
        encode_semi_colon_params(static_cast<const LibSip__Common::SemicolonParam__List>(l[i].rrParam()), &(record_route_header)->gen_params);
      }
  } // End of 'for' statement
  
  char* hvalue;
  int result = ::osip_record_route_to_str(record_route_header, &hvalue);
  loggers::get_instance().log("sip_codec_headers::encode_record_route_header: '%s'- result:%d", hvalue, result);
  if (::osip_message_set_record_route(*p_sip_message, hvalue) != OSIP_SUCCESS) {
    loggers::get_instance().warning("sip_codec_headers::encode_record_route_header: Failed to set RecordRoute header in sip_message");
    return -1;
  }
  ::osip_record_route_free(record_route_header);
  osip_free(hvalue);
  
  return 0;
}

int sip_codec_headers::encode_r_seq_header(const OPTIONAL<LibSip__SIPTypesAndValues::RSeq>& p_r_seq, osip_message_t** p_sip_message)
{
  loggers::get_instance().log(">>> sip_codec_headers::encode_r_seq_header", p_r_seq);

  const LibSip__SIPTypesAndValues::RSeq& r_seq = static_cast<const LibSip__SIPTypesAndValues::RSeq&>(*p_r_seq.get_opt_value());
  ::osip_message_set_header((osip_message_t *)*p_sip_message, (const char *)"RSeq", static_cast<const char*>(std::to_string(r_seq.responseNum()).c_str()));
  
  return 0;
} // End of method encode_r_seq_header

int sip_codec_headers::encode_session_expires_header(const OPTIONAL<LibSip__SIPTypesAndValues::SessionExpires>& p_session_expires, osip_message_t** p_sip_message) {
  loggers::get_instance().log(">>> sip_codec_headers::encode_session_expires_header");

  if (!p_session_expires.is_present()) {
    return 0;
  }
  
  const LibSip__SIPTypesAndValues::SessionExpires& session_expires = static_cast<const LibSip__SIPTypesAndValues::SessionExpires&>(*p_session_expires.get_opt_value());
  // deltaSec
  std::string value(static_cast<const char*>(session_expires.deltaSec()));
  // seParam
  const OPTIONAL<LibSip__Common::SemicolonParam__List>& se_param = session_expires.seParam(); // TODO Create a method to fill an std::string with SemicolonParam__List
  if (se_param.is_present()) {
    const LibSip__Common::SemicolonParam__List& l = static_cast<const LibSip__Common::SemicolonParam__List&>(*se_param.get_opt_value());
    int i = 0;
    do {
      value += ";";
      const LibSip__Common::GenericParam& g = l[i];
      value += static_cast<const char*>(g.id());
      if (g.paramValue().is_present()) {
        value += "=";
        const LibSip__Common::GenValue& v = static_cast<const LibSip__Common::GenValue&>(*g.paramValue().get_opt_value());
        if (v.ischosen(LibSip__Common::GenValue::ALT_tokenOrHost)) {
          value += static_cast<const char*>(v.tokenOrHost());
        } else {
          value += static_cast<const char*>(v.quotedString());
        }
      }
    } while (i < l.lengthof());
  }
  osip_message_set_expires(*p_sip_message, value.c_str());
  
  return 0;
}

int sip_codec_headers::encode_supported_header(const OPTIONAL<LibSip__SIPTypesAndValues::Supported>& p_supported, osip_message_t** p_sip_message) {
  loggers::get_instance().log(">>> sip_codec_headers::encode_supported_header");

  if (!p_supported.is_present()) {
    return 0;
  }
  
  const LibSip__SIPTypesAndValues::Supported& supported = static_cast<const LibSip__SIPTypesAndValues::Supported&>(*p_supported.get_opt_value());
  const OPTIONAL<LibSip__SIPTypesAndValues::OptionTag__List>& tags = supported.optionsTags();
  if (!tags.is_present()) {
    return 0;
  }
  if (encode_option_tag_list(static_cast<const LibSip__SIPTypesAndValues::OptionTag__List&>(*tags.get_opt_value()), "Supported", p_sip_message) == -1) {
    return -1;
  }
  
  return 0;
}

int sip_codec_headers::encode_user_agent_header(const OPTIONAL<LibSip__SIPTypesAndValues::UserAgent>& p_user_agent, osip_message_t** p_sip_message) {
  loggers::get_instance().log(">>> sip_codec_headers::encode_user_agent_header");

  if (!p_user_agent.is_present()) {
    return 0;
  }
  
  const LibSip__SIPTypesAndValues::UserAgent& user_agent = static_cast<const LibSip__SIPTypesAndValues::UserAgent&>(*p_user_agent.get_opt_value());
  const LibSip__SIPTypesAndValues::ServerVal__List& s = user_agent.userAgentBody();
  if (encode_server_val_list(s, "User-Agent", p_sip_message) == -1) {
    return -1;
  }
  
  return 0;
}

int sip_codec_headers::encode_to_header(const LibSip__SIPTypesAndValues::To& p_to, osip_to_t** p_to_header) {
  loggers::get_instance().log(">>> sip_codec_headers::encode_to_header");
  
  ::osip_to_init(p_to_header);
  const LibSip__SIPTypesAndValues::Addr__Union& a = p_to.addressField();
  if (a.ischosen(LibSip__SIPTypesAndValues::Addr__Union::ALT_nameAddr)) {
    const LibSip__SIPTypesAndValues::NameAddr& addr = a.nameAddr();
    osip_uri_t *uri;
    if (encode_sip_url(addr.addrSpec(), &uri) == -1) {
      loggers::get_instance().warning("sip_codec_headers::encode_to_header: Failed to encode SipUrl");
      ::osip_to_free(*p_to_header);
      *p_to_header = nullptr;
      return -1;
    }
    ::osip_to_set_url(*p_to_header, uri);
    //::osip_uri_free(uri);
    if (addr.displayName().is_present()) {
      const LibSip__SIPTypesAndValues::DisplayName& n = static_cast<const LibSip__SIPTypesAndValues::DisplayName&>(addr.displayName());
      if (n.ischosen(LibSip__SIPTypesAndValues::DisplayName::ALT_token)) {
        ::osip_to_set_displayname(*p_to_header, (char*)::strdup(static_cast<const char*>(static_cast<CHARSTRING>(n.token()))));
      } else if (n.ischosen(LibSip__SIPTypesAndValues::DisplayName::ALT_quotedString)) {
        ::osip_to_set_displayname(*p_to_header, (char*)::strdup(static_cast<const char*>(static_cast<CHARSTRING>(n.quotedString()))));
      } else {
        loggers::get_instance().warning("sip_codec_headers::encode_to_header: Failed to encode DisplayName");
        ::osip_to_free(*p_to_header);
        *p_to_header = nullptr;
        return -1;
      }
    }
  } else if (a.ischosen(LibSip__SIPTypesAndValues::Addr__Union::ALT_addrSpecUnion)) {
    osip_uri_t *uri;
    if (encode_sip_url(a.addrSpecUnion(), &uri) == -1) {
      loggers::get_instance().warning("sip_codec_headers::encode_to_header: Failed to encode SipUrl");
      ::osip_to_free(*p_to_header);
      *p_to_header = nullptr;
      return -1;
    }
    ::osip_to_set_url(*p_to_header, uri);
  } else {
    loggers::get_instance().warning("sip_codec_headers::encode_to_header: Failed to encode Addr__Union");
    ::osip_to_free(*p_to_header);
    *p_to_header = nullptr;
    return -1;
  }
  if (p_to.toParams().is_present()) {
    encode_semi_colon_params(static_cast<const LibSip__Common::SemicolonParam__List>(p_to.toParams()), &(*p_to_header)->gen_params);
  }
  
  return 0;
} // End of method encode_to_header

int sip_codec_headers::encode_via_header(const LibSip__SIPTypesAndValues::Via& p_via, osip_via_t** p_via_header) {
  loggers::get_instance().log_msg(">>> sip_codec_headers::encode_via_header: ", p_via);
  
  ::osip_via_init(p_via_header);
  const LibSip__SIPTypesAndValues::ViaBody__List& l = p_via.viaBody();
  for (int i = 0; i < l.size_of(); i++) {
    const LibSip__SIPTypesAndValues::ViaBody v = l[i];
    loggers::get_instance().log_msg("sip_codec_headers::encode_via_header: Processing ", v);

    ::via_set_protocol(*p_via_header, (char*)::strdup(static_cast<const char *>(v.sentProtocol().transport())));
    ::via_set_version(*p_via_header, (char*)::strdup(static_cast<const char *>(v.sentProtocol().protocolVersion())));
    std::string host;
    std::string port;
    encode_host_port(v.sentBy(), host, port);
    if (!host.empty()) {
      ::via_set_host(*p_via_header, (char*)::strdup(host.c_str()));
    }
    if (!port.empty()) {
      ::via_set_port (*p_via_header, (char*)::strdup(port.c_str()));
    }
    
    if (v.viaParams().is_present()) {
      encode_semi_colon_params(static_cast<const LibSip__Common::SemicolonParam__List>(v.viaParams()), &(*p_via_header)->via_params);
    }
  } // End of 'for' statement
  
  return 0;
} // End of method encode_via_header
 
int sip_codec_headers::encode_www_authenticate_header(const LibSip__SIPTypesAndValues::WwwAuthenticate& p_www_authenticate, osip_www_authenticate_t** p_www_authenticate_header) {
  loggers::get_instance().log_msg(">>> sip_codec_headers::encode_www_authenticate_header: ", p_www_authenticate);
  
  ::osip_www_authenticate_init(p_www_authenticate_header);
  const LibSip__SIPTypesAndValues::Challenge& c = p_www_authenticate.challenge();
  if (c.ischosen(LibSip__SIPTypesAndValues::Challenge::ALT_digestCln)) {
    osip_www_authenticate_set_auth_type(*p_www_authenticate_header, (char*)::strdup("Digest"));
    const LibSip__Common::CommaParam__List& l = c.digestCln();
    for (int i = 0; i < l.lengthof(); i++) {
      const LibSip__Common::GenericParam& p = l[i];
      if (std::string(static_cast<const char*>(p.id())).compare("realm") == 0) {
        if (p.paramValue().is_present()) {
          const LibSip__Common::GenValue& g = static_cast<const LibSip__Common::GenValue&>(*p.paramValue().get_opt_value());
          if (g.ischosen(LibSip__Common::GenValue::ALT_tokenOrHost)) {
            ::osip_www_authenticate_set_realm(*p_www_authenticate_header, (char*)::strdup(static_cast<const char*>(g.tokenOrHost())));
          } else {
            std::stringstream ss;
            ss << std::quoted(static_cast<const char*>(g.quotedString()));
            ::osip_www_authenticate_set_realm(*p_www_authenticate_header, (char*)::strdup(ss.str().c_str()));
          }
        }
      } else if (std::string(static_cast<const char*>(p.id())).compare("nonce") == 0) {
        if (p.paramValue().is_present()) {
          const LibSip__Common::GenValue& g = static_cast<const LibSip__Common::GenValue&>(*p.paramValue().get_opt_value());
          if (g.ischosen(LibSip__Common::GenValue::ALT_tokenOrHost)) {
            ::osip_www_authenticate_set_nonce(*p_www_authenticate_header, (char*)::strdup(static_cast<const char*>(g.tokenOrHost())));
          } else {
            std::stringstream ss;
            ss << std::quoted(static_cast<const char*>(g.quotedString()));
            ::osip_www_authenticate_set_nonce(*p_www_authenticate_header, (char*)::strdup(ss.str().c_str()));
          }
        }
      } else if (std::string(static_cast<const char*>(p.id())).compare("stale") == 0) {
        if (p.paramValue().is_present()) {
          const LibSip__Common::GenValue& g = static_cast<const LibSip__Common::GenValue&>(*p.paramValue().get_opt_value());
          if (g.ischosen(LibSip__Common::GenValue::ALT_tokenOrHost)) {
            ::osip_www_authenticate_set_stale(*p_www_authenticate_header, (char*)::strdup(static_cast<const char*>(g.tokenOrHost())));
          } else {
            std::stringstream ss;
            ss << std::quoted(static_cast<const char*>(g.quotedString()));
            ::osip_www_authenticate_set_stale(*p_www_authenticate_header, (char*)::strdup(ss.str().c_str()));
          }
        }
      } else if (std::string(static_cast<const char*>(p.id())).compare("algorithm") == 0) {
        if (p.paramValue().is_present()) {
          const LibSip__Common::GenValue& g = static_cast<const LibSip__Common::GenValue&>(*p.paramValue().get_opt_value());
          std::stringstream ss;
          if (g.ischosen(LibSip__Common::GenValue::ALT_tokenOrHost)) {
            ss << std::quoted(static_cast<const char*>(g.tokenOrHost()));
          } else {
            ss << std::quoted(static_cast<const char*>(g.quotedString()));
          }
          ::osip_www_authenticate_set_algorithm(*p_www_authenticate_header, (char*)::strdup(ss.str().c_str()));
        }
      } else if (std::string(static_cast<const char*>(p.id())).compare("qop") == 0) {
        if (p.paramValue().is_present()) {
          const LibSip__Common::GenValue& g = static_cast<const LibSip__Common::GenValue&>(*p.paramValue().get_opt_value());
          std::stringstream ss;
          if (g.ischosen(LibSip__Common::GenValue::ALT_tokenOrHost)) {
            ss << std::quoted(static_cast<const char*>(g.tokenOrHost()));
          } else {
            ss << std::quoted(static_cast<const char*>(g.quotedString()));
          }
          ::osip_www_authenticate_set_qop_options(*p_www_authenticate_header, (char*)::strdup(ss.str().c_str()));
        }
      } else {
        loggers::get_instance().warning("sip_codec_headers::encode_www_authenticate_header: Unimplemented param '%s'", static_cast<const char*>(p.id()));
      }
    } // End of 'for'statement
  } else {
    const LibSip__SIPTypesAndValues::OtherAuth& l = c.otherChallenge();
    loggers::get_instance().warning("sip_codec_headers::encode_www_authenticate_header: Unsupported variant");
    return -1;
  }
  
  return 0;
} // End of method encode_www_authenticate_header
 
int sip_codec_headers::encode_semi_colon_params(const LibSip__Common::SemicolonParam__List& p_list, osip_list_t* p_sip_list) {
  loggers::get_instance().log_msg(">>> sip_codec_headers::encode_semi_colon_params: ", p_list);

  if (p_list.size_of() != 0) {
    for (int i = 0; i < p_list.size_of(); i++) {
      const LibSip__Common::GenericParam& param = static_cast<const LibSip__Common::GenericParam&>(*p_list.get_at(i));
      loggers::get_instance().log_msg("sip_codec_headers::encode_semi_colon_params: param: ", param);
      if (param.paramValue().is_present()) {
        const LibSip__Common::GenValue& v = static_cast<const LibSip__Common::GenValue&>(*param.paramValue().get_opt_value());
        loggers::get_instance().log_msg("sip_codec_headers::encode_semi_colon_params: v: ", v);
        if (v.ischosen(LibSip__Common::GenValue::ALT_tokenOrHost)) {
          loggers::get_instance().log_msg("sip_codec_headers::encode_semi_colon_params: tokenOrHost: ", v.tokenOrHost());
          ::osip_generic_param_add(p_sip_list, (char*)::strdup(static_cast<const char*>(param.id())), (char*)::strdup(static_cast<const char*>(v.tokenOrHost())));
        } else {
          loggers::get_instance().log_msg("sip_codec_headers::encode_semi_colon_params: quotedString: ", v.quotedString());
          ::osip_generic_param_add(p_sip_list, (char*)static_cast<const char*>(param.id()), (char*)static_cast<const char*>(v.quotedString()));
        }
      } else {
        ::osip_generic_param_add(p_sip_list, (char*)::strdup(static_cast<const char*>(param.id())), (char*)::strdup(""));
      }
    } // End of 'for' statement
  } else {
    // Nothing to do
  }
  
  return 0;
}

void sip_codec_headers::decode_semi_colon_params(const osip_list_t& p_sip_list, OPTIONAL<LibSip__Common::SemicolonParam__List>& p_list) {
  loggers::get_instance().log(">>> sip_codec_headers::decode_semi_colon_params");

  if (::osip_list_size(&p_sip_list) != 0) {
    LibSip__Common::SemicolonParam__List l;
    for (int i = 0; i < ::osip_list_size(&p_sip_list); i++) {
      osip_generic_param_t* p = (osip_generic_param_t*)::osip_list_get(&p_sip_list, i);
      loggers::get_instance().log("sip_codec_headers::decode_semi_colon_params: After cast: %p", p);
      CHARSTRING name(p->gname);
      if (p->gvalue == nullptr) {
        l[i] = LibSip__Common::GenericParam(name, OPTIONAL<LibSip__Common::GenValue>(OMIT_VALUE));
      } else {
        LibSip__Common::GenValue g;
        g.tokenOrHost() = CHARSTRING(p->gvalue);
        l[i] = LibSip__Common::GenericParam(name, g);
      }
    } // End of 'for' statement
    p_list = OPTIONAL<LibSip__Common::SemicolonParam__List>(l);
  } else {
    p_list.set_to_omit();
  }

  loggers::get_instance().log_msg("<<< sip_codec_headers::decode_semi_colon_params: ", p_list);
} // End of method decode_semi_colon_params

void sip_codec_headers::decode_semi_colon_params(const std::string& p_params, std::string& p_first_param, LibSip__Common::SemicolonParam__List& p_others_params) {
  loggers::get_instance().log(">>> sip_codec_headers::decode_semi_colon_params: %s", p_params.c_str());
  
  std::size_t idx = p_params.find(";");
  if (idx == std::string::npos) {
    p_first_param = p_params;
  } else {
    std::vector<std::string> output = converter::get_instance().split(p_params, ";");
    p_first_param = output[0];
    LibSip__Common::SemicolonParam__List l;
    for (unsigned int i = 1; i < output.size(); i++) {
      std::vector<std::string> o = converter::get_instance().split(output[i], "=");
      if (o.size() == 2) {
        LibSip__Common::GenValue g;
        g.tokenOrHost() = CHARSTRING(o[1].c_str());
        p_others_params[i - 1] = LibSip__Common::GenericParam(CHARSTRING(o[0].c_str()), g);
      } else {
        p_others_params[i - 1] = LibSip__Common::GenericParam(CHARSTRING(o[0].c_str()), OPTIONAL<LibSip__Common::GenValue>(OMIT_VALUE));
      }
    } // End of 'for' statement
  }
  loggers::get_instance().log("<<< sip_codec_headers::decode_semi_colon_params: %s", p_first_param.c_str());
  loggers::get_instance().log_msg("<<< sip_codec_headers::decode_semi_colon_params: ", p_others_params);
}

void sip_codec_headers::decode_semi_colon_params(const std::string& p_params, LibSip__Common::SemicolonParam__List& p_params_list) {
  loggers::get_instance().log(">>> sip_codec_headers::decode_semi_colon_params: %s", p_params.c_str());

  std::size_t idx = p_params.find(";");
  if (idx == std::string::npos) {
      std::vector<std::string> o = converter::get_instance().split(p_params, "=");
      if (o.size() == 2) {
        LibSip__Common::GenValue g;
        g.tokenOrHost() = CHARSTRING(o[1].c_str());
        p_params_list[0] = LibSip__Common::GenericParam(CHARSTRING(o[0].c_str()), g);
      } else {
    	  p_params_list[0] = LibSip__Common::GenericParam(CHARSTRING(o[0].c_str()), OPTIONAL<LibSip__Common::GenValue>(OMIT_VALUE));
      }
  } else {
    std::vector<std::string> output = converter::get_instance().split(p_params, ";");
    LibSip__Common::SemicolonParam__List l;
    for (unsigned int i = 0; i < output.size(); i++) {
      std::vector<std::string> o = converter::get_instance().split(output[i], "=");
      if (o.size() == 2) {
        LibSip__Common::GenValue g;
        g.tokenOrHost() = CHARSTRING(o[1].c_str());
        p_params_list[i - 1] = LibSip__Common::GenericParam(CHARSTRING(o[0].c_str()), g);
      } else {
    	  p_params_list[i - 1] = LibSip__Common::GenericParam(CHARSTRING(o[0].c_str()), OPTIONAL<LibSip__Common::GenValue>(OMIT_VALUE));
      }
    } // End of 'for' statement
  }
  loggers::get_instance().log_msg("<<< sip_codec_headers::decode_semi_colon_params: ", p_params_list);
}

int sip_codec_headers::encode_ampersand_params(const LibSip__Common::AmpersandParam__List& p_list, osip_list_t** p_sip_list) {
  loggers::get_instance().log(">>> sip_codec_headers::encode_ampersand_params");

  if (p_list.size_of() != 0) {
    ::osip_list_init(*p_sip_list);
    for (int i = 0; i < p_list.size_of(); i++) {
      const LibSip__Common::GenericParam& param = static_cast<const LibSip__Common::GenericParam&>(*p_list.get_at(i));
      if (param.paramValue().is_present()) {
        const LibSip__Common::GenValue& v = static_cast<const LibSip__Common::GenValue&>(*param.paramValue().get_opt_value());
        if (v.ischosen(LibSip__Common::GenValue::ALT_tokenOrHost)) {
          ::osip_generic_param_add(*p_sip_list, (char*)static_cast<const char*>(param.id()), (char*)static_cast<const char*>(v.tokenOrHost()));
        } else {
          ::osip_generic_param_add(*p_sip_list, (char*)static_cast<const char*>(param.id()), (char*)static_cast<const char*>(v.quotedString()));
        }
      }
    } // End of 'for' statement
  } else {
    *p_sip_list = nullptr;
  }
  
  return 0;
}

void sip_codec_headers::decode_ampersand_params(const osip_list_t& p_sip_list, OPTIONAL<LibSip__Common::AmpersandParam__List>& p_list) {
  loggers::get_instance().log(">>> sip_codec_headers::decode_ampersand_params");

  if (::osip_list_size(&p_sip_list) != 0) {
    LibSip__Common::AmpersandParam__List l;
    for (int i = 0; i < ::osip_list_size(&p_sip_list); i++) {
      osip_generic_param_t* p = (osip_generic_param_t*)::osip_list_get(&p_sip_list, i);
      loggers::get_instance().log("sip_codec_headers::decode_ampersand_params: After cast: %p", p);
      CHARSTRING name(p->gname);
      if (p->gvalue == nullptr) {
        l[i] = LibSip__Common::GenericParam(name, OPTIONAL<LibSip__Common::GenValue>(OMIT_VALUE));
      } else {
        LibSip__Common::GenValue g;
        g.tokenOrHost() = CHARSTRING(p->gvalue);
        l[i] = LibSip__Common::GenericParam(name, g);
      }
    } // End of 'for' statement
    p_list = OPTIONAL<LibSip__Common::AmpersandParam__List>(l);
  } else {
    p_list.set_to_omit();
  }

  loggers::get_instance().log_msg("<<< sip_codec_headers::decode_ampersand_params: ", p_list);
} // End of method decode_ampersand_params

int sip_codec_headers::encode_option_tag_list(const LibSip__SIPTypesAndValues::OptionTag__List& p_options_tags, const std::string& p_field_name, osip_message_t** p_sip_message) {
  loggers::get_instance().log(">>> sip_codec_headers::encode_option_tag_list");

  if (p_options_tags.size_of() != 0) {
    std::string str(static_cast<const char*>(*static_cast<const CHARSTRING*>(p_options_tags.get_at(0))));
    loggers::get_instance().log("sip_codec_headers::encode_option_tag_list: str=%s", str.c_str());
    for (int i = 1; i < p_options_tags.size_of() - 1; i++) {
      str += "," + std::string(static_cast<const char*>(*static_cast<const CHARSTRING*>(p_options_tags.get_at(i))));
    } // End of 'for' statement
    loggers::get_instance().log("sip_codec_headers::encode_option_tag_list: Final str=%s", str.c_str());
    ::osip_message_set_header((osip_message_t *)*p_sip_message, p_field_name.c_str(), str.c_str());
  } else {
    ::osip_message_set_header((osip_message_t *)*p_sip_message, p_field_name.c_str(), "");
  }
  return 0;
}

void sip_codec_headers::decode_option_tag_list(const char* p_list, OPTIONAL<LibSip__SIPTypesAndValues::OptionTag__List>& p_options_tags)
{
  loggers::get_instance().log(">>> sip_codec_headers::decode_option_tag_list: %s", p_list);
  
  if (p_list != nullptr) {
    LibSip__SIPTypesAndValues::OptionTag__List l;
    std::string str(p_list);
    std::size_t i = str.find(","); // See RFC 3261 - Page 231 / LibSip__SIPTypesAndValues::OptionTag__List
    if (i == std::string::npos) { // Only on item
      l[0] = CHARSTRING(p_list);
    } else {
      int idx = 0;
      while(i != std::string::npos) {
        l[idx++] = CHARSTRING(str.substr(0, i).c_str());
        str = str.substr(i + 1);
        loggers::get_instance().log("sip_codec_headers::decode_option_tag_list: New str: %s", str.c_str());
        i = str.find(",");
        loggers::get_instance().log("sip_codec_headers::decode_option_tag_list: New i: %d", i);
      } // End of 'while' statement
      l[idx] = CHARSTRING(str.c_str());
    }
    p_options_tags = OPTIONAL<LibSip__SIPTypesAndValues::OptionTag__List>(l);
  } else {
    p_options_tags.set_to_omit();
  }

  loggers::get_instance().log_msg("<<< sip_codec_headers::decode_option_tag_list: ", p_options_tags);
} // End of method decode_option_tag_list

int sip_codec_headers::encode_server_val_list(const LibSip__SIPTypesAndValues::ServerVal__List& p_server_vals, const std::string& p_field_name, osip_message_t** p_sip_message) {
  loggers::get_instance().log(">>> sip_codec_headers::encode_server_val_list");

  if (p_server_vals.size_of() != 0) {
    std::string str(static_cast<const char*>(*static_cast<const CHARSTRING*>(p_server_vals.get_at(0))));
    for (int i = 1; i < p_server_vals.size_of() - 1; i++) {
      str += "," + std::string(static_cast<const char*>(*static_cast<const CHARSTRING*>(p_server_vals.get_at(i))));
    } // End of 'for' statement
    ::osip_message_set_header((osip_message_t *)*p_sip_message, p_field_name.c_str(), str.c_str());
  } else {
    ::osip_message_set_header((osip_message_t *)*p_sip_message, p_field_name.c_str(), "");
  }
  return 0;
}

void sip_codec_headers::decode_server_val_list(const char* p_list, LibSip__SIPTypesAndValues::ServerVal__List& p_server_vals)
{
  loggers::get_instance().log(">>> sip_codec_headers::decode_server_val_list: %s", p_list);
  
  if (p_list != nullptr) {
    std::string str(p_list);
    std::size_t i = str.find(","); // See RFC 3261 - Page 231 / LibSip__SIPTypesAndValues::ServerVal__List
    if (i == std::string::npos) { // Only on item
      p_server_vals[0] = CHARSTRING(p_list);
    } else {
      int idx = 0;
      while(i != std::string::npos) {
        p_server_vals[idx++] = CHARSTRING(str.substr(0, i).c_str());
        str = str.substr(i + 1);
        loggers::get_instance().log("sip_codec_headers::decode_server_val_list: New str: %s", str.c_str());
        i = str.find(" ");
        loggers::get_instance().log("sip_codec_headers::decode_server_val_list: New i: %d", i);
      } // End of 'while' statement
      p_server_vals[idx] = CHARSTRING(str.c_str());
    }
  } else {
    p_server_vals[0] = CHARSTRING("");
  }

  loggers::get_instance().log_msg("<<< sip_codec_headers::decode_server_val_list: ", p_server_vals);
} // End of method decode_server_val_list

void sip_codec_headers::decode_host_port(const char* p_host, const char* p_port, LibSip__SIPTypesAndValues::HostPort& p_host_port) {
  loggers::get_instance().log(">>> sip_codec_headers::decode_host_port");
  
  if (p_host == nullptr) {
    p_host_port.host().set_to_omit();
  } else {
    p_host_port.host() = OPTIONAL<CHARSTRING>(CHARSTRING(p_host));
  }
  OPTIONAL<INTEGER> port;
  if (p_port == nullptr) {
    p_host_port.portField().set_to_omit();
  } else {
    p_host_port.portField() = OPTIONAL<INTEGER>(INTEGER(std::stoi(p_port)));
  }

  loggers::get_instance().log_msg("<<< sip_codec_headers::decode_host_port: ", p_host_port);
} // End of method decode_host_port"

void sip_codec_headers::decode_uri(LibSip__SIPTypesAndValues::SipUrl& p_sip_url, const osip_uri_t* p_uri) {
  loggers::get_instance().log(">>> sip_codec_headers::decode_uri");
  
  // Scheme
  LibSip__SIPTypesAndValues::UriComponents uri_components;
  if (::osip_uri_get_scheme((osip_uri_t*)p_uri) != nullptr) {
    p_sip_url.scheme() = CHARSTRING(::osip_uri_get_scheme((osip_uri_t*)p_uri));
    loggers::get_instance().log_msg("sip_codec_headers::decode_uri: scheme: ", p_sip_url.scheme());
    // SipUriComponents
    if (strcmp(::osip_uri_get_scheme((osip_uri_t*)p_uri), "sip") == 0) {
      // User Info
      OPTIONAL<LibSip__SIPTypesAndValues::UserInfo> user_info;
      if (::osip_uri_get_username((osip_uri_t*)p_uri) == nullptr) {
        user_info.set_to_omit();
      } else {
        OPTIONAL<CHARSTRING> password;
        if (::osip_uri_get_password((osip_uri_t*)p_uri) == nullptr) {
          password.set_to_omit();
        } else {
          password = CHARSTRING(::osip_uri_get_password((osip_uri_t*)p_uri));
        }
        LibSip__SIPTypesAndValues::UserInfo u(CHARSTRING(::osip_uri_get_username((osip_uri_t*)p_uri)), password);
        user_info = OPTIONAL<LibSip__SIPTypesAndValues::UserInfo>(u);
      }
      loggers::get_instance().log_msg("sip_codec_headers::decode_uri: user_info: ", user_info);
      // HostPort
      LibSip__SIPTypesAndValues::HostPort host_port;
      decode_host_port(::osip_uri_get_host((osip_uri_t*)p_uri), ::osip_uri_get_port((osip_uri_t*)p_uri), host_port);
      loggers::get_instance().log_msg("sip_codec_headers::decode_uri: host_port: ", host_port);
      uri_components.sip() = LibSip__SIPTypesAndValues::SipUriComponents(user_info, host_port);
    } else if (strcmp(::osip_uri_get_scheme((osip_uri_t*)p_uri), "tel") == 0) {
      const LibSip__SIPTypesAndValues::TelUriComponents t;
      uri_components.tel() = t; // TODO To be done
      loggers::get_instance().error("sip_codec_headers::decode_uri: Unsupported LibSip__SIPTypesAndValues::UriComponents::ALT_tel");
    } else if (strcmp(::osip_uri_get_scheme((osip_uri_t*)p_uri), "urn") == 0) {
      char *buf = nullptr;
      if (::osip_uri_to_str_canonical((osip_uri_t*)p_uri, &buf) == 0) {
        std::string str(buf);
        loggers::get_instance().log("sip_codec_headers::decode_uri: str: %s", str.c_str());
        std::vector<std::string> output = converter::get_instance().split(str, ":");
        loggers::get_instance().log("sip_codec_headers::decode_uri: split size: %d", output.size());
        LibSip__SIPTypesAndValues::UrnUriComponents urn;
        urn.namespaceId() = output[1].c_str();
        std::string s(output[2]);
        for (std::size_t i = 3; i < output.size(); i++) {
          s += ":" + output[i];
        }
        urn.namespaceSpecificString() = s.c_str();
        uri_components.urn() = urn;
        osip_free(buf); // Macro
      } // TODO Check what to do in this case
    } else {
      char *buffer = nullptr;
      ::osip_uri_to_str_canonical((osip_uri_t*)p_uri, &buffer);
      std::string str(buffer);
      const char* p = static_cast<const char*>(p_sip_url.scheme());
      size_t i = str.find(p);
      if (i == std::string::npos) {
        uri_components.other() = CHARSTRING(buffer);
      } else {
        uri_components.other() = CHARSTRING(str.substr(i + strlen(p) + 1).c_str());
      }
      osip_free(buffer); // Macro
    }
  } else {
    char *buffer = nullptr;
    ::osip_uri_to_str_canonical((osip_uri_t*)p_uri, &buffer);
    uri_components.other() = CHARSTRING(buffer);
    osip_free(buffer); // Macro
  }
  p_sip_url.components() = uri_components;
  // UrlParameters
  OPTIONAL<LibSip__Common::SemicolonParam__List> params;
  decode_semi_colon_params(p_uri->url_params, params);
  p_sip_url.urlParameters() = params;
  // Headers
  OPTIONAL<LibSip__Common::AmpersandParam__List> headers;
  decode_ampersand_params(p_uri->url_headers, headers);
  p_sip_url.headers() = headers;
  
  loggers::get_instance().log_msg("<<< sip_codec_headers::decode_uri: ", p_sip_url);
} // End of method decode_uri

void sip_codec_headers::decode_accept_header(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::Accept& p_accept_header)
{
  loggers::get_instance().log("sip_codec_headers::decode_accept_header");

  // Sanity checks
  osip_accept_t *sip_accept = nullptr;
  ::osip_message_get_accept(p_sip_message, 0, &sip_accept);
  if (sip_accept == nullptr) {
    return;
  }
  
  // FieldName
  p_accept_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("ACCEPT_E"));
  // AcceptArgs
  if (::osip_list_size(&p_sip_message->accepts) == 0) {
    p_accept_header.acceptArgs().set_to_omit();
  } else {
    LibSip__SIPTypesAndValues::AcceptBody__List bl;
    int x = 0;
    for (int i = 0; i < ::osip_list_size(&p_sip_message->accepts); i++) {
      const osip_accept_t* l = (const osip_accept_t*)::osip_list_get(&p_sip_message->accepts, i);
      if (l != nullptr) {
        loggers::get_instance().log("sip_codec_headers::decode_accept_header: %s=%s", l->type, l->subtype); // application=sdp,application/3gpp-ims+xml
        std::string str(l->subtype);
        std::size_t idx = str.find(",");
        if (idx == std::string::npos) {
          LibSip__SIPTypesAndValues::AcceptBody b;
          b.mediaRange() = CHARSTRING(l->type) + CHARSTRING("/") + CHARSTRING(l->subtype); // FIXME CHARSTRING(l->type || "=" ||  l->subtype)???
          if (osip_list_size(&(l->gen_params)) != 0) {
            // TODO
          } else {
            b.acceptParam().set_to_omit();
          }
          bl[x++] = b;
        } else {
          std::vector<std::string> output = converter::get_instance().split(str, ",");
          LibSip__SIPTypesAndValues::AcceptBody b;
          loggers::get_instance().log("sip_codec_headers::decode_accept_header: Processing %s=%s", l->type, output[0].c_str());
          b.mediaRange() = CHARSTRING(l->type) + CHARSTRING("/") + CHARSTRING(output[0].c_str()); // FIXME CHARSTRING(l->type || "=" ||  l->subtype)???
          if (osip_list_size(&(l->gen_params)) != 0) {
            // TODO
          } else {
            b.acceptParam().set_to_omit();
          }
          bl[x++] = b;
          for (unsigned int k = 1; k < output.size(); k++) {
            loggers::get_instance().log("sip_codec_headers::decode_accept_header: In loop, processing %s=%s", output[k].c_str());
            LibSip__SIPTypesAndValues::AcceptBody b;
            b.mediaRange() = CHARSTRING(output[k].c_str()); // FIXME CHARSTRING(l->type || "=" ||  l->subtype)???
            if (osip_list_size(&(l->gen_params)) != 0) {
              // TODO
            } else {
              b.acceptParam().set_to_omit();
            }
            bl[x++] = b;
          }
        }
      }
    } // End of 'for' statement
    p_accept_header.acceptArgs() = OPTIONAL<LibSip__SIPTypesAndValues::AcceptBody__List>(bl);
  }
  
  loggers::get_instance().log_msg("<<< sip_codec_headers::decode_accept_header: ", p_accept_header);
} // End of method decode_accept_header

void sip_codec_headers::decode_accept_contact_header(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::AcceptContact& p_accept_contact_header)
{
  loggers::get_instance().log(">>> sip_codec_headers::decode_accept_contact_header: %p", p_sip_message->contacts);

  // Sanity checks
  osip_header_t *sip_accept_contact = nullptr;
  ::osip_message_header_get_byname(p_sip_message, (const char *)"accept-contact", 0, &sip_accept_contact);
  if (sip_accept_contact == nullptr) {
    return;
  }
  
  loggers::get_instance().log("sip_codec_headers::decode_accept_contact_header: got it: %s:%s", sip_accept_contact->hname, sip_accept_contact->hvalue);
  if ((sip_accept_contact->hvalue == nullptr) || (strlen(sip_accept_contact->hvalue) == 0)) {
    loggers::get_instance().warning("sip_codec_headers::decode_accept_contact_header: Failed to decode Accept-Contact header");
    return;
  }
  // FieldName
  p_accept_contact_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("ACCEPT_CONTACT_E"));
  // AcRcValue list
  std::string str(sip_accept_contact->hvalue);
  LibSip__SIPTypesAndValues::AcRcValue__List la;
  std::size_t idx = str.find(",");
  if (idx == std::string::npos) {
    // Split using ; as separator
    std::vector<std::string> output = converter::get_instance().split(str, ";");
    loggers::get_instance().log("sip_codec_headers::decode_accept_contact_header (1): Split size: %d", output.size());
    // The first parameter is the wild card
    LibSip__SIPTypesAndValues::AcRcValue acRcValue;
    acRcValue.wildcard() = CHARSTRING(output[0].c_str());
    if (output.size() > 1) {
      // Extract the other parameters
      LibSip__Common::SemicolonParam__List l;
      for (unsigned int i = 1; i < output.size(); i++) {
        LibSip__Common::GenericParam p;
        std::vector<std::string> o = converter::get_instance().split(output[i], "=");
        p.id() = CHARSTRING(o[0].c_str());
        if (o.size() == 1) { // No value
          p.paramValue().set_to_omit();
        } else {
          loggers::get_instance().log("sip_codec_headers::decode_accept_contact_header (1): o: %s:%s", o[0].c_str(), o[1].c_str());
          LibSip__Common::GenValue g;
          g.tokenOrHost() = CHARSTRING(o[1].c_str());
          p.paramValue() = OPTIONAL<LibSip__Common::GenValue>(g);
        }
        l[i - 1] = p;
      } // End of 'for' statement
      loggers::get_instance().log_msg("sip_codec_headers::decode_accept_contact_header: l: ", l);
      acRcValue.acRcParams() = OPTIONAL<LibSip__Common::SemicolonParam__List>(l);
    } else {
      acRcValue.acRcParams().set_to_omit();
    }
    la[0] = acRcValue;
  } else {
    // Split the list of values using , as separator
    std::vector<std::string> lop = converter::get_instance().split(str, ",");
    for (std::size_t s = 0; s < lop.size(); s++) {
      str = lop[s];
      // Extract parameters separated by ; into SemiColumn__List
      std::vector<std::string> output = converter::get_instance().split(str, ";");
      // The first parameter is the wild card
      LibSip__SIPTypesAndValues::AcRcValue acRcValue;
      acRcValue.wildcard() = CHARSTRING(output[0].c_str());
      if (output.size() > 1) {
        // Extract the other parameters
        LibSip__Common::SemicolonParam__List l;
        for (unsigned int i = 1; i < output.size(); i++) {
          LibSip__Common::GenericParam p;
          std::vector<std::string> o = converter::get_instance().split(output[i], "=");
          p.id() = CHARSTRING(o[0].c_str());
          if (o.size() == 1) { // No value
            p.paramValue().set_to_omit();
          } else {
            loggers::get_instance().log("sip_codec_headers::decode_accept_contact_header (2): o: %s:%s", o[0].c_str(), o[1].c_str());
            LibSip__Common::GenValue g;
            g.tokenOrHost() = CHARSTRING(o[1].c_str());
            p.paramValue() = OPTIONAL<LibSip__Common::GenValue>(g);
          }
          l[i - 1] = p;
        } // End of 'for' statement
        loggers::get_instance().log_msg("sip_codec_headers::decode_accept_contact_header: l: ", l);
        acRcValue.acRcParams() = OPTIONAL<LibSip__Common::SemicolonParam__List>(l);
      } else {
        acRcValue.acRcParams().set_to_omit();
      }
      la[s] = acRcValue;
    } // End of 'for'statement
  }
  p_accept_contact_header.acValues() = la;
  
  loggers::get_instance().log_msg("<<< sip_codec_headers::decode_accept_contact_header: ", p_accept_contact_header);
} // End of method decode_accept_contact_header

void sip_codec_headers::decode_accept_encoding_header(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::AcceptEncoding& p_accept_encoding_header)
{
  loggers::get_instance().log(">>> sip_codec_headers::decode_accept_encoding_header: %p", p_sip_message->accept_encodings);

  // Sanity checks
  osip_accept_encoding_t *sip_accept_encoding = nullptr;
  ::osip_message_get_accept_encoding(p_sip_message, 0, &sip_accept_encoding);
  if (sip_accept_encoding == nullptr) {
    return;
  }
  // FieldName
  p_accept_encoding_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("ACCEPT_ENCODING_E"));
  // ContentCoding
  p_accept_encoding_header.contentCoding().set_to_omit();

  loggers::get_instance().log_msg("<<< sip_codec_headers::decode_accept_encoding_header: ", p_accept_encoding_header);
} // End of method decode_accept_encoding_header

void sip_codec_headers::decode_accept_language_header(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::AcceptLanguage& p_accept_language_header)
{
  loggers::get_instance().log(">>> sip_codec_headers::decode_accept_language_header: %p", p_sip_message->accept_languages);

  // Sanity checks
  osip_accept_language_t *sip_accept_language = nullptr;
  ::osip_message_get_accept_language(p_sip_message, 0, &sip_accept_language);
  if (sip_accept_language == nullptr) {
    return;
  }
  
  // FieldName
  p_accept_language_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("ACCEPT_LANGUAGE_E"));
  // LanguageBody
  p_accept_language_header.languageBody().set_to_omit();

  loggers::get_instance().log_msg("<<< sip_codec_headers::decode_accept_language_header: ", p_accept_language_header);
} // End of method decode_accept_language_header

void sip_codec_headers::decode_alert_info_header(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::AlertInfo& p_alert_info_header)
{
  loggers::get_instance().log(">>> sip_codec_headers::decode_alert_info_header: %p", p_sip_message->alert_infos);

  // Sanity checks
  osip_alert_info_t *sip_alert_info = nullptr;
  ::osip_message_get_alert_info(p_sip_message, 0, &sip_alert_info);
  if (sip_alert_info == nullptr) {
    return;
  }
  
  // FieldName
  p_alert_info_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("ALERT_INFO_E"));
  // AlertInfoBody
  p_alert_info_header.alertInfoBody().set_to_omit();

  loggers::get_instance().log_msg("<<< sip_codec_headers::decode_alert_info_header: ", p_alert_info_header);
} // End of method decode_alert_info_header

void sip_codec_headers::decode_allow_header(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::Allow& p_allow_header)
{
  loggers::get_instance().log(">>> sip_codec_headers::decode_allow_header: %p", p_sip_message->allows);

  // Sanity checks
  osip_allow_t *sip_allow = nullptr;
  ::osip_message_get_allow(p_sip_message, 0, &sip_allow);
  if (sip_allow == nullptr) {
    return;
  }
  
  // FieldName
  p_allow_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("ALLOW_E"));
  // Methods
  loggers::get_instance().log("sip_codec_headers::decode_allow_header: value: %s", sip_allow->value);
  if ((sip_allow->value == nullptr) || (strlen(sip_allow->value) == 0)) {
    p_allow_header.methods().set_to_omit();
  } else {
    LibSip__SIPTypesAndValues::Method__List m;
    std::string str(sip_allow->value);
    std::vector<std::string> output = converter::get_instance().split(str, ",");
    unsigned int i = 0;
    while (i < output.size()) {
      m[i] = CHARSTRING(output[i].c_str());
      i += 1;
    } // End of 'while' statement
    p_allow_header.methods() = OPTIONAL<LibSip__SIPTypesAndValues::Method__List>(m);
  }

  loggers::get_instance().log_msg("<<< sip_codec_headers::decode_allow_header: ", p_allow_header);
} // End of method decode_allow_header

void sip_codec_headers::decode_allow_events_header(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::AllowEvents& p_allow_events_header)
{
  loggers::get_instance().log(">>> sip_codec_headers::decode_allow_events_header: %p", p_sip_message->headers);

  // Sanity checks
  osip_header_t *sip_allow_events = nullptr;
  ::osip_message_header_get_byname(p_sip_message, (const char *)"allow_events", 0, &sip_allow_events);
  if (sip_allow_events == nullptr) {
    return;
  }
  
  // FieldName
  p_allow_events_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("ALLOW_EVENTS_E"));
  // EventTypes
  LibSip__SIPTypesAndValues::EventType__List l;
  // TODO To be done
  l[0] = CHARSTRING("*");
  p_allow_events_header.eventTypes() = l;

  loggers::get_instance().log_msg("<<< sip_codec_headers::decode_allow_events_header: ", p_allow_events_header);
} // End of method decode_allow_events_header

void sip_codec_headers::decode_authorization_header(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::Authorization& p_authorization_header)
{
  loggers::get_instance().log(">>> sip_codec_headers::decode_authorization_header");

  // Sanity checks
  osip_authorization_t *sip_authorization = nullptr;
  ::osip_message_get_authorization(p_sip_message, 0, &sip_authorization);
  if (sip_authorization == nullptr) {
    return;
  }
  
  // FieldName
  p_authorization_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("AUTHORIZATION_E"));
  // CredentialsList
  LibSip__SIPTypesAndValues::CredentialsList l;
  int i = 0;
  do {
    loggers::get_instance().log("sip_codec_headers::decode_authorization_header: Processing item #%d", i);
    LibSip__SIPTypesAndValues::Credentials v;
    LibSip__Common::CommaParam__List cl;
    int j = 0;
    if (::osip_authorization_get_digest(sip_authorization) != nullptr) {
      LibSip__Common::GenValue v;
      v.tokenOrHost() = CHARSTRING(::osip_authorization_get_digest(sip_authorization));
      cl[j++] = LibSip__Common::GenericParam(
                                            CHARSTRING("digest"),
                                            OPTIONAL<LibSip__Common::GenValue>(v)
                                            );
    }
    if (::osip_authorization_get_username(sip_authorization) != nullptr) {
      LibSip__Common::GenValue v;
      v.tokenOrHost() = CHARSTRING(::osip_authorization_get_username(sip_authorization));
      cl[j++] = LibSip__Common::GenericParam(
                                            CHARSTRING("username"),
                                            OPTIONAL<LibSip__Common::GenValue>(v)
                                            );
    }
    if (::osip_authorization_get_uri(sip_authorization) != nullptr) {
      LibSip__Common::GenValue v;
      v.tokenOrHost() = CHARSTRING(::osip_authorization_get_uri(sip_authorization));
      cl[j++] = LibSip__Common::GenericParam(
                                            CHARSTRING("uri"),
                                            OPTIONAL<LibSip__Common::GenValue>(v)
                                            );
    }
    if (::osip_authorization_get_realm(sip_authorization) != nullptr) {
      LibSip__Common::GenValue v;
      v.tokenOrHost() = CHARSTRING(::osip_authorization_get_realm(sip_authorization));
      cl[j++] = LibSip__Common::GenericParam(
                                            CHARSTRING("realm"),
                                            OPTIONAL<LibSip__Common::GenValue>(v)
                                            );
    }
    if (::osip_authorization_get_nonce(sip_authorization) != nullptr) {
      loggers::get_instance().log("sip_codec_headers::decode_authorization_header: Decode nonce");
      LibSip__Common::GenValue v;
      v.tokenOrHost() = CHARSTRING(::osip_authorization_get_nonce(sip_authorization));
      cl[j++] = LibSip__Common::GenericParam(
                                            CHARSTRING("nonce"),
                                            OPTIONAL<LibSip__Common::GenValue>(v)
                                            );
    }
    if (::osip_authorization_get_response(sip_authorization) != nullptr) {
      loggers::get_instance().log("sip_codec_headers::decode_authorization_header: Decode response");
      LibSip__Common::GenValue v;
      v.tokenOrHost() = CHARSTRING(::osip_authorization_get_response(sip_authorization));
      cl[j++] = LibSip__Common::GenericParam(
                                            CHARSTRING("response"),
                                            OPTIONAL<LibSip__Common::GenValue>(v)
                                            );
    }
    loggers::get_instance().log_msg("sip_codec_headers::decode_authorization_header: New GenValue:", cl);
    v.digestResponse() = cl;
    loggers::get_instance().log_msg("sip_codec_headers::decode_authorization_header: New GenValue list:", cl);
    l[i++] = v;
    loggers::get_instance().log_msg("sip_codec_headers::decode_authorization_header: New CredentialsList:", l);
  } while(::osip_message_get_authorization(p_sip_message, i, &sip_authorization) == 0); // End of 'do-while' statement
  p_authorization_header.body() = l;
  
  loggers::get_instance().log_msg("<<< sip_codec_headers::decode_authorization_header: ", p_authorization_header);
} // End of method decode_authorization_header

void sip_codec_headers::decode_call_id_header(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::CallId& p_call_id_header)
{
  loggers::get_instance().log(">>> sip_codec_headers::decode_call_id_header: %p", p_sip_message->call_id);
  
  // Sanity check
  if (p_sip_message->call_id == nullptr) {
    return;
  }

  // FieldName
  p_call_id_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("CALL_ID_E"));
  // CallId
  char *buffer;
  ::osip_call_id_to_str(p_sip_message->call_id, &buffer);
  if (buffer != nullptr) {
    p_call_id_header.callid() = CHARSTRING(buffer);
    osip_free(buffer);
  }
} // End of method decode_call_id_header

void sip_codec_headers::decode_call_info_header(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::CallInfo& p_call_info_header)
{
  loggers::get_instance().log(">>> sip_codec_headers::decode_call_info_header: %p", p_sip_message->call_infos);
  
  osip_call_info_t *call_info = nullptr;
  ::osip_message_get_call_info(p_sip_message, 0, &call_info);
  if (call_info == nullptr) {
    return;
  }

  // FieldName
  p_call_info_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("CALL_INFO_E"));
  // CallInfoBody_List
  loggers::get_instance().log("sip_codec_headers::decode_call_info_header: value: %s", call_info->element);
  if ((call_info->element == nullptr) || (strlen(call_info->element) == 0)) {
    p_call_info_header.callInfoBody().set_to_omit();
  } else if (osip_list_size(&(p_sip_message->call_infos)) == 0) {
    p_call_info_header.callInfoBody().set_to_omit();
  } else {
    LibSip__SIPTypesAndValues::CallInfoBody__List l;
    int pos = 0;
    while (pos < osip_list_size(&(p_sip_message->call_infos))) {
      ::osip_message_get_call_info(p_sip_message, pos, &call_info);	
      loggers::get_instance().log("sip_codec_headers::decode_call_info_header: call_info.element=%s", call_info->element);
      OPTIONAL<LibSip__Common::SemicolonParam__List> params;
      decode_semi_colon_params(call_info->gen_params, params);
      l[pos++] = LibSip__SIPTypesAndValues::CallInfoBody(call_info->element, params);
    } // End of 'while' statement
    p_call_info_header.callInfoBody() = OPTIONAL<LibSip__SIPTypesAndValues::CallInfoBody__List>(l);
  }

  loggers::get_instance().log_msg("<<< sip_codec_headers::decode_call_info_header: ", p_call_info_header);
} // End of method decode_call_info_header

void sip_codec_headers::decode_c_seq_header(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::CSeq& p_c_seq_header)
{
  loggers::get_instance().log(">>> sip_codec_headers::decode_c_seq_header");
  
  // Sanity check
  if (p_sip_message->cseq == nullptr) {
    return;
  }

  // FieldName
  p_c_seq_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("CSEQ_E"));
  // Sequence number
  p_c_seq_header.seqNumber() = INTEGER(std::stoi(osip_cseq_get_number(p_sip_message->cseq)));
  // Method
  p_c_seq_header.method() = CHARSTRING(::osip_cseq_get_method(p_sip_message->cseq));
} // End of method decode_c_seq_header

void sip_codec_headers::decode_content_length_header(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::ContentLength& p_content_length_header)
{
  loggers::get_instance().log(">>> sip_codec_headers::decode_content_length_header");
  
  // Sanity check
  if (p_sip_message->content_length == nullptr) {
    return;
  }

  // FieldName
  p_content_length_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("CONTENT_LENGTH_E"));
  // Length
  char *buffer;
  ::osip_content_length_to_str(p_sip_message->content_length, &buffer);
  if (buffer != nullptr) {
    p_content_length_header.len() = INTEGER(std::stoi(buffer));
    osip_free(buffer);
  }
} // End of method decode_content_length_header

void sip_codec_headers::decode_content_type_header(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::ContentType& p_content_type_header)
{
  loggers::get_instance().log(">>> sip_codec_headers::decode_content_type_header");
  
  // Sanity check
  if (p_sip_message->content_type == nullptr) {
    return;
  }

  // FieldName
  p_content_type_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("CONTENT_TYPE_E"));
  // Type/SubType
  std::string str(p_sip_message->content_type->type);
  if (p_sip_message->content_type->subtype != nullptr) {
    str += "/";
    str += p_sip_message->content_type->subtype; 
    p_content_type_header.mTypeSubtype() = CHARSTRING(str.c_str());
  }
  // Parameters
  OPTIONAL<LibSip__Common::SemicolonParam__List> params;
  decode_semi_colon_params(p_sip_message->content_type->gen_params, params);
  p_content_type_header.mParams() = params;
} // End of method decode_content_type_header

void sip_codec_headers::decode_contact_header(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::Contact& p_contact_header) {
  loggers::get_instance().log("sip_codec_headers::decode_contact_header");
  
  // Sanity check
  if (::osip_list_size(&p_sip_message->contacts) == 0) {
    return;
  }
  
  // FieldName
  p_contact_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("CONTACT_E"));
  // ContactBody
  LibSip__SIPTypesAndValues::ContactAddress__List c;
  int i = 0;
  osip_contact_t* contact = nullptr;
  while (::osip_message_get_contact(p_sip_message, i, &contact) == 0) {
    LibSip__SIPTypesAndValues::ContactAddress contact_addr;
    LibSip__SIPTypesAndValues::SipUrl uri;
    decode_uri(uri, ::osip_contact_get_url((osip_contact_t*)contact));
    LibSip__SIPTypesAndValues::Addr__Union addr;
    OPTIONAL<LibSip__SIPTypesAndValues::DisplayName> display_name;
    if (::osip_contact_get_displayname((osip_contact_t*)contact) != nullptr) {
      LibSip__SIPTypesAndValues::DisplayName n;
      n.token() = CHARSTRING(::osip_contact_get_displayname((osip_contact_t*)contact));
      display_name = OPTIONAL<LibSip__SIPTypesAndValues::DisplayName>(n);
      LibSip__SIPTypesAndValues::NameAddr name_addr(display_name, uri);
      addr.nameAddr() = name_addr;
    } else {
      display_name.set_to_omit();
      addr.addrSpecUnion() = uri;
    }
    contact_addr.addressField() = addr;
    // Params
    OPTIONAL<LibSip__Common::SemicolonParam__List> params;
    decode_semi_colon_params(contact->gen_params, params);
    contact_addr.contactParams() = params;
    
    c[i++] = contact_addr;
  } // End of 'while' statement
  p_contact_header.contactBody().contactAddresses() = c;
  
  loggers::get_instance().log_msg("<<< sip_codec_headers::decode_contact_header: ", p_contact_header);
} // End of method decode_contact_header

void sip_codec_headers::decode_event_header(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::Event& p_event_header)
{
  loggers::get_instance().log("sip_codec_headers::decode_event_header");

  // Sanity checks
  osip_header_t *dest = nullptr;
  ::osip_message_header_get_byname(p_sip_message, (const char *)"Event", 0, &dest); // TODO Create osip_message_[g|s]et_event
  if (dest == nullptr) {
    loggers::get_instance().warning("sip_codec_headers::decode_event_header: Not found");
    return;
  }
  loggers::get_instance().log("sip_codec_headers::decode_event_header: hname='%s' : hvalue='%s'\n", dest->hname, dest->hvalue);

  // FieldName
  p_event_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("EVENT_E"));
  // EventType
  std::string str(dest->hvalue);
  size_t p1 = str.find("<");
  size_t p2 = str.find(">");
  size_t p3 = str.find(";");
  std::string u = str.substr(p1 + 1, p2 - p1 - 1);
  loggers::get_instance().log("sip_codec_headers::decode_event_header: u='%s'\n", u.c_str());
  p_event_header.eventType() = CHARSTRING(u.c_str());
  // eventParam
  if (p3 != std::string::npos) {
    std::string p = str.substr(p3 + 1);
    loggers::get_instance().log("sip_codec_headers::decode_event_header: p='%s'\n", p.c_str());
    LibSip__Common::SemicolonParam__List params;
    decode_semi_colon_params(p.c_str(), params);
    if (params.is_bound()) {
      p_event_header.eventParams() = OPTIONAL<LibSip__Common::SemicolonParam__List>(params);
    } else {
      p_event_header.eventParams().set_to_omit();
    }
  } else {
    p_event_header.eventParams().set_to_omit();
  }
} // End of method decode_event_header

void sip_codec_headers::decode_expires_header(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::Expires& p_expires_header)
{
  loggers::get_instance().log("sip_codec_headers::decode_expires_header");

  // Sanity checks
  osip_header_t *dest = nullptr;
  ::osip_message_header_get_byname(p_sip_message, (const char *)"Expires", 0, &dest); // TODO Create osip_message_[g|s]et_expires
  if (dest == nullptr) {
    loggers::get_instance().warning("sip_codec_headers::decode_expires_header: Not found");
    return;
  }
  loggers::get_instance().log("sip_codec_headers::decode_expires_header: hname='%s' : hvalue='%s'\n", dest->hname, dest->hvalue);

  // FieldName
  p_expires_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("EXPIRES_E"));
  // DeltaSec
  std::string str(dest->hvalue);
  p_expires_header.deltaSec() = CHARSTRING(str.c_str());
} // End of method decode_expires_header

void sip_codec_headers::decode_from_header(const osip_from_t* p_sip_from, LibSip__SIPTypesAndValues::From& p_from_header)
{
  loggers::get_instance().log("sip_codec_headers::decode_from_header");
  
  // Sanity check
  if (p_sip_from == nullptr) {
    loggers::get_instance().warning("sip_codec_headers::decode_from_header: Invalid SIP message");
    return;
  }

  // FieldName
  p_from_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("FROM_E"));
  // Addr_Union
  LibSip__SIPTypesAndValues::SipUrl uri;
  decode_uri(uri, ::osip_from_get_url((osip_from_t*)p_sip_from));
  LibSip__SIPTypesAndValues::Addr__Union addr;
  OPTIONAL<LibSip__SIPTypesAndValues::DisplayName> display_name;
  if (::osip_from_get_displayname((osip_from_t*)p_sip_from) != nullptr) {
    LibSip__SIPTypesAndValues::DisplayName n;
    n.token() = CHARSTRING(::osip_from_get_displayname((osip_from_t*)p_sip_from));
    display_name = OPTIONAL<LibSip__SIPTypesAndValues::DisplayName>(n);
    LibSip__SIPTypesAndValues::NameAddr name_addr(display_name, uri);
    addr.nameAddr() = name_addr;
  } else {
    display_name.set_to_omit();
    addr.addrSpecUnion() = uri;
  }
  p_from_header.addressField() = addr;
  // Params
  OPTIONAL<LibSip__Common::SemicolonParam__List> params;
  decode_semi_colon_params(p_sip_from->gen_params, params);
  p_from_header.fromParams() = params;
  
  loggers::get_instance().log_msg("<<< sip_codec_headers::decode_from_header: ", p_from_header);
} // End of method decode_from_header

void sip_codec_headers::decode_geolocation_header(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::Geolocation& p_geolocation_header)
{
  loggers::get_instance().log("sip_codec_headers::decode_geolocation_header");

  // Sanity checks
  osip_header_t *dest = nullptr;
  ::osip_message_header_get_byname(p_sip_message, (const char *)"geolocation", 0, &dest); // TODO Create osip_message_[g|s]et_geolocation
  if (dest == nullptr) {
    loggers::get_instance().warning("sip_codec_headers::decode_geolocation_header: Not found");
    return;
  }
  loggers::get_instance().log("sip_codec_headers::decode_geolocation_header: hname='%s' : hvalue='%s'\n", dest->hname, dest->hvalue);

  // FieldName
  p_geolocation_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("GEOLOCATION_E"));
  // addrSpec
  std::string str(dest->hvalue);
  size_t p1 = str.find("<");
  size_t p2 = str.find(">");
  size_t p3 = str.find(";");
  std::string u = str.substr(p1 + 1, p2 - p1 - 1);
  loggers::get_instance().log("sip_codec_headers::decode_geolocation_header: u='%s'\n", u.c_str());
  osip_uri_t *uri = nullptr;
  ::osip_uri_init(&uri);
  ::osip_uri_parse(uri, u.c_str());
  decode_uri(p_geolocation_header.addrSpec(), uri);
  // geolocParam
  if (p3 != std::string::npos) {
    std::string p = str.substr(p3 + 1);
    loggers::get_instance().log("sip_codec_headers::decode_geolocation_header: p='%s'\n", p.c_str());
    LibSip__Common::SemicolonParam__List params;
    decode_semi_colon_params(p.c_str(), params);
    if (params.is_bound()) {
      p_geolocation_header.geolocParam() = OPTIONAL<LibSip__Common::SemicolonParam__List>(params);
    } else {
      p_geolocation_header.geolocParam().set_to_omit();
    }
  } else {
    p_geolocation_header.geolocParam().set_to_omit();
  }
} // End of method decode_geolocation_header

void sip_codec_headers::decode_geolocation_routing_header(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::GeolocationRouting& p_geolocation_routing_header)
{
  loggers::get_instance().log("sip_codec_headers::decode_geolocation_routing_header");

  // Sanity checks
  osip_header_t *dest = nullptr;
  ::osip_message_header_get_byname(p_sip_message, (const char *)"geolocation-routing", 0, &dest); // TODO Create osip_message_[g|s]et_geolocation_routing
  if (dest == nullptr) {
    loggers::get_instance().warning("sip_codec_headers::decode_geolocation_routing_header: Not found");
    return;
  }
  loggers::get_instance().log("sip_codec_headers::decode_geolocation_routing_header: hname='%s' : hvalue='%s'\n", dest->hname, dest->hvalue);

  // FieldName
  p_geolocation_routing_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("GEOLOCATION_ROUTING_E"));
  std::string str(dest->hvalue);
  size_t pos = str.find(";");
  if (pos == std::string::npos) {
    if (str.compare("yes") == 0) {
      p_geolocation_routing_header.state() = LibSip__SIPTypesAndValues::GeolocationRoutingState(LibSip__SIPTypesAndValues::GeolocationRoutingState::GEOLOCATION__ROUTING__YES__E);
    } else if (str.compare("no") == 0) {
      p_geolocation_routing_header.state() = LibSip__SIPTypesAndValues::GeolocationRoutingState(LibSip__SIPTypesAndValues::GeolocationRoutingState::GEOLOCATION__ROUTING__NO__E);
    } else {
      p_geolocation_routing_header.state() = LibSip__SIPTypesAndValues::GeolocationRoutingState(LibSip__SIPTypesAndValues::GeolocationRoutingState::GEOLOCATION__ROUTING__OTHER__E);
    }
    p_geolocation_routing_header.genericValue().set_to_omit();
  } else {
    std::string s = str.substr(0, pos - 1);
    loggers::get_instance().log("sip_codec_headers::decode_geolocation_routing_header: s='%s'\n", s.c_str());
    if (s.compare("yes") == 0) {
      p_geolocation_routing_header.state() = LibSip__SIPTypesAndValues::GeolocationRoutingState(LibSip__SIPTypesAndValues::GeolocationRoutingState::GEOLOCATION__ROUTING__YES__E);
    } else if (s.compare("no") == 0) {
      p_geolocation_routing_header.state() = LibSip__SIPTypesAndValues::GeolocationRoutingState(LibSip__SIPTypesAndValues::GeolocationRoutingState::GEOLOCATION__ROUTING__NO__E);
    } else {
      p_geolocation_routing_header.state() = LibSip__SIPTypesAndValues::GeolocationRoutingState(LibSip__SIPTypesAndValues::GeolocationRoutingState::GEOLOCATION__ROUTING__OTHER__E);
    }
    str = str.substr(pos + 1);
    LibSip__Common::GenericParam p;
    pos = str.find("=");
    if (pos != std::string::npos) {
      p.id() = CHARSTRING(str.substr(0, pos - 1).c_str());
      LibSip__Common::GenValue v;
      v.quotedString() = CHARSTRING(str.substr(pos + 1).c_str());
      p.paramValue() = OPTIONAL<LibSip__Common::GenValue>(v);
    } else {
      p.id() = CHARSTRING(str.c_str());
      p.paramValue().set_to_omit();
    }
    loggers::get_instance().log("sip_codec_headers::decode_geolocation_routing_header: genericValue='%s'\n", str.c_str());
    p_geolocation_routing_header.genericValue() = OPTIONAL<LibSip__Common::GenericParam>(p);
  }
}

void sip_codec_headers::decode_max_forwards_header(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::MaxForwards& p_max_forwards_header)
{
  loggers::get_instance().log("sip_codec_headers::decode_max_forwards_header");

  // Sanity checks
  osip_header_t *dest = nullptr;
  osip_message_get_max_forwards(p_sip_message, 0, &dest);
  if (dest == nullptr) {
    return;
  }
  
  // FieldName
  p_max_forwards_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("MAX_FORWARDS_E"));
  // Forwards
  loggers::get_instance().log("sip_codec_headers::decode_max_forwards_header: got it: %s:%s", dest->hname, dest->hvalue);
  p_max_forwards_header.forwards() = INTEGER(std::stoi(dest->hvalue));
} // End of method decode_max_forwards_header

void sip_codec_headers::decode_min_se_header(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::MinSE& p_min_se_header)
{
  loggers::get_instance().log("sip_codec_headers::decode_min_se_header");

  // Sanity checks
  osip_header_t *dest = nullptr;
  ::osip_message_header_get_byname((osip_message_t*)p_sip_message, (const char *)"min-se", 0, &dest); // TODO Create osip_message_[g|s]et_min_se
  if (dest == nullptr) {
    return;
  }
  
  // FieldName
  p_min_se_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("MIN_SE_E"));
  
  std::string fisrt_parameter;
  LibSip__Common::SemicolonParam__List others_params;
  decode_semi_colon_params(dest->hvalue, fisrt_parameter, others_params);
  p_min_se_header.deltaSec() = CHARSTRING(fisrt_parameter.c_str());
  if (others_params.is_bound()) {
    p_min_se_header.minSeParam() = OPTIONAL<LibSip__Common::SemicolonParam__List>(others_params);
  } else {
    p_min_se_header.minSeParam().set_to_omit();
  }
} // End of method decode_min_se_header

void sip_codec_headers::decode_p_associated_uri_header(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::PAssociatedURI& p_p_associated_uri_header)
{
  loggers::get_instance().log("sip_codec_headers::decode_p_associated_uri_header");

  // Sanity checks
  osip_header_t *dest = nullptr;
  ::osip_message_header_get_byname((osip_message_t*)p_sip_message, (const char *)"p-associated-uri", 0, &dest); // TODO Create osip_message_[g|s]et_p_associated_uri
  if (dest == nullptr) {
    return;
  }
  loggers::get_instance().log("sip_codec_headers::decode_p_associated_uri_header: hname='%s' : hvalue='%s'\n", dest->hname, dest->hvalue);
  
  // FieldName
  p_p_associated_uri_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("P_ASSOCIATED_URI_E"));
  // nameAddrList
  LibSip__SIPTypesAndValues::NameAddrParam__List l;
  std::string str(dest->hvalue);
  
  std::size_t idx = str.find(",");
  if (idx == std::string::npos) {
    LibSip__SIPTypesAndValues::NameAddrParam n; //<sip:8007@huawei.com>,<sip:8007@huawei.com;user=phone>
    n.genericParams().set_to_omit(); // TODO To be implemented
    n.nameAddr().displayName().set_to_omit();
    std::string str(dest->hvalue);
    size_t p1 = str.find("<");
    size_t p2 = str.find(">");
    std::string u = str.substr(p1 + 1, p2 - p1 - 1);
    loggers::get_instance().log("sip_codec_headers::decode_p_associated_uri_header: u='%s'\n", u.c_str());
    osip_uri_t *uri = nullptr;
    ::osip_uri_init(&uri);
    ::osip_uri_parse(uri, u.c_str());
    decode_uri(n.nameAddr().addrSpec(), uri);
    l[0] = n;
  } else {
    std::vector<std::string> output = converter::get_instance().split(str, ",");
    for (unsigned int i = 0; i < output.size(); i++) {
      LibSip__SIPTypesAndValues::NameAddrParam n; //<sip:8007@huawei.com>,<sip:8007@huawei.com;user=phone>
      n.genericParams().set_to_omit(); // TODO To be implemented
      n.nameAddr().displayName().set_to_omit();
      size_t p1 = output[i].find("<");
      size_t p2 = output[i].find(">");
      std::string u = output[i].substr(p1 + 1, p2 - p1 - 1);
      loggers::get_instance().log("sip_codec_headers::decode_p_associated_uri_header: u='%s'\n", u.c_str());
      osip_uri_t *uri = nullptr;
      ::osip_uri_init(&uri);
      ::osip_uri_parse(uri, u.c_str());
      decode_uri(n.nameAddr().addrSpec(), uri);
      l[i++] = n;
    } // End of 'for' statement
  }
  p_p_associated_uri_header.nameAddrList() = l;
} // End of method decode_p_associated_uri_header

void sip_codec_headers::decode_p_access_network_info_header(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::PAccessNetworkInfo& p_p_access_network_info_header)
{
  loggers::get_instance().log("sip_codec_headers::decode_p_access_network_info_header");

  // Sanity checks
  osip_header_t *dest = nullptr;
  ::osip_message_header_get_byname((osip_message_t*)p_sip_message, (const char *)"p-access-network-info", 0, &dest); // TODO Create osip_message_[g|s]et_p_access_network_info
  if (dest == nullptr) {
    return;
  }
  
  // FieldName
  p_p_access_network_info_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("P_ACCESS_NETWORK_INFO_E"));
  std::string fisrt_parameter;
  LibSip__Common::SemicolonParam__List others_params;
  decode_semi_colon_params(dest->hvalue, fisrt_parameter, others_params);
  p_p_access_network_info_header.accessType() = CHARSTRING(fisrt_parameter.c_str());
  if (others_params.is_bound()) {
    p_p_access_network_info_header.genericParams() = OPTIONAL<LibSip__Common::SemicolonParam__List>(others_params);
  } else {
    p_p_access_network_info_header.genericParams().set_to_omit();
  }
} // End of method decode_p_access_network_info_header

void sip_codec_headers::decode_privacy_header(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::Privacy& p_privacy_header)
{
  loggers::get_instance().log("sip_codec_headers::decode_privacy_header");

  // Sanity checks
  osip_header_t *dest = nullptr;
  ::osip_message_header_get_byname((osip_message_t*)p_sip_message, (const char *)"privacy", 0, &dest); // TODO Create osip_message_[g|s]et_privacy
  if (dest == nullptr) {
    return;
  }
  
  // FieldName
  p_privacy_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("PRIVACY_E"));
  // Privacy list
  loggers::get_instance().log("sip_codec_headers::decode_allow_header: value: %s", dest->hvalue);
  if ((dest->hvalue == nullptr) || (strlen(dest->hvalue) == 0)) {
    p_privacy_header.privValueList().set_to_omit();
  } else {
    LibSip__SIPTypesAndValues::PrivacyValue__List m;
    std::string str(dest->hvalue);
    std::vector<std::string> output = converter::get_instance().split(str, ",");
    unsigned int i = 0;
    while (i < output.size()) {
      m[i] = CHARSTRING(output[i].c_str());
      i += 1;
    } // End of 'while' statement
    p_privacy_header.privValueList() = OPTIONAL<LibSip__SIPTypesAndValues::PrivacyValue__List>(m);
  }

  loggers::get_instance().log_msg("<<< sip_codec_headers::decode_privacy_header: ", p_privacy_header);
}

void sip_codec_headers::decode_route_header(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::Route& p_route_header) {
  loggers::get_instance().log("sip_codec_headers::decode_route_header");
  // Sanity check
  if (::osip_list_size(&p_sip_message->routes) == 0) {
    return;
  }
  
  // FieldName
  p_route_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("ROUTE_E"));
  // RouteBody
  LibSip__SIPTypesAndValues::RouteBody__List c;
  int i = 0;
  osip_route_t* route = nullptr;
  while (::osip_message_get_route(p_sip_message, i, &route) == 0) {
    LibSip__SIPTypesAndValues::RouteBody route_body;
    // Decode uri
    LibSip__SIPTypesAndValues::SipUrl uri;
    decode_uri(uri, ::osip_from_get_url((osip_from_t*)route));
    // Decode display name
    OPTIONAL<LibSip__SIPTypesAndValues::DisplayName> display_name;
    if (::osip_from_get_displayname((osip_route_t*)route) != nullptr) {
      LibSip__SIPTypesAndValues::DisplayName n;
      n.token() = CHARSTRING(::osip_from_get_displayname((osip_route_t*)route));
      display_name = OPTIONAL<LibSip__SIPTypesAndValues::DisplayName>(n);
    } else {
      display_name.set_to_omit();
    }
    route_body.nameAddr() = LibSip__SIPTypesAndValues::NameAddr(display_name, uri);
    // Params
    OPTIONAL<LibSip__Common::SemicolonParam__List> params;
    decode_semi_colon_params(route->gen_params, params);
    route_body.rrParam() = params;
    
    c[i++] = route_body;
  } // End of 'while' statement
  p_route_header.routeBody() = c;
  
  loggers::get_instance().log_msg("<<< sip_codec_headers::decode_route_header: ", p_route_header);
} // End of method decode_route_header

void sip_codec_headers::decode_record_route_header(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::RecordRoute& p_record_route_header) {
  loggers::get_instance().log("sip_codec_headers::decode_record_route_header");
  // Sanity check
  if (::osip_list_size(&p_sip_message->record_routes) == 0) {
    return;
  }
  
  // FieldName
  p_record_route_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("RECORD_ROUTE_E"));
  // RecordRouteBody
  LibSip__SIPTypesAndValues::RouteBody__List c;
  int i = 0;
  osip_record_route_t* record_route = nullptr;
  while (::osip_message_get_record_route(p_sip_message, i, &record_route) == 0) {
    LibSip__SIPTypesAndValues::RouteBody record_route_body;
    // Decode uri
    LibSip__SIPTypesAndValues::SipUrl uri;
    decode_uri(uri, ::osip_from_get_url((osip_from_t*)record_route));
    // Decode display name
    OPTIONAL<LibSip__SIPTypesAndValues::DisplayName> display_name;
    if (::osip_from_get_displayname((osip_record_route_t*)record_route) != nullptr) {
      LibSip__SIPTypesAndValues::DisplayName n;
      n.token() = CHARSTRING(::osip_from_get_displayname((osip_record_route_t*)record_route));
      display_name = OPTIONAL<LibSip__SIPTypesAndValues::DisplayName>(n);
    } else {
      display_name.set_to_omit();
    }
    record_route_body.nameAddr() = LibSip__SIPTypesAndValues::NameAddr(display_name, uri);
    // Params
    OPTIONAL<LibSip__Common::SemicolonParam__List> params;
    decode_semi_colon_params(record_route->gen_params, params);
    record_route_body.rrParam() = params;
    
    c[i++] = record_route_body;
  } // End of 'while' statement
  p_record_route_header.routeBody() = c;
  
  loggers::get_instance().log_msg("<<< sip_codec_headers::decode_record_route_header: ", p_record_route_header);
} // End of method decode_record_route_header

void sip_codec_headers::decode_r_seq_header(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::RSeq& p_r_seq_header)
{
  loggers::get_instance().log("sip_codec_headers::decode_r_seq_header");

  // Sanity checks
  osip_header_t *dest = nullptr;
  ::osip_message_header_get_byname((osip_message_t*)p_sip_message, (const char *)"rseq", 0, &dest); // TODO Create osip_message_[g|s]et_rseq
  if (dest == nullptr) {
    return;
  }
  
  // FieldName
  p_r_seq_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("RSEQ_E"));
  p_r_seq_header.responseNum() = INTEGER(std::stoi(dest->hvalue));
}

void sip_codec_headers::decode_session_expires_header(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::SessionExpires& p_session_expires_header)
{
  loggers::get_instance().log("sip_codec_headers::decode_session_expires_header");

  // Sanity checks
  osip_header_t *dest = nullptr;
  ::osip_message_header_get_byname((osip_message_t*)p_sip_message,(const char *)"session-expires", 0, &dest); // TODO Create osip_message_[g|s]et_session_expires
  if (dest == nullptr) {
    return;
  }
  
  // FieldName
  p_session_expires_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("SESSION_EXPIRES_E"));
  
  std::string fisrt_parameter;
  LibSip__Common::SemicolonParam__List others_params;
  decode_semi_colon_params(dest->hvalue, fisrt_parameter, others_params);
  p_session_expires_header.deltaSec() = CHARSTRING(fisrt_parameter.c_str()); 
  if (others_params.is_bound()) {
    p_session_expires_header.seParam() = OPTIONAL<LibSip__Common::SemicolonParam__List>(others_params); 
  } else {
    p_session_expires_header.seParam().set_to_omit();
  }
  
  // loggers::get_instance().log("sip_codec_headers::decode_session_expires_header: got it: %s:%s", dest->hname, dest->hvalue);
  // std::size_t idx = str.find(";");
  // if (idx == std::string::npos) {
  //   p_session_expires_header.deltaSec() = dest->hvalue;
  //   p_session_expires_header.seParam().set_to_omit();
  // } else {
  //   std::vector<std::string> output = converter::get_instance().split(str, ";");
  //   p_session_expires_header.deltaSec() = CHARSTRING(output[0].c_str());
  //   LibSip__Common::SemicolonParam__List l;
  //   for (unsigned int i = 1; i < output.size(); i++) {
  //     std::vector<std::string> o = converter::get_instance().split(output[i], "=");
  //     LibSip__Common::GenValue g;
  //     g.tokenOrHost() = CHARSTRING(o[1].c_str());
  //     l[i - 1] = LibSip__Common::GenericParam(CHARSTRING(o[0].c_str()), g);
  //   } // End of 'for' statement
  //   p_session_expires_header.seParam() = OPTIONAL<LibSip__Common::SemicolonParam__List>(l);
  // }
} // End of method decode_session_expires_header

void sip_codec_headers::decode_supported_header(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::Supported& p_supported_header)
{
  loggers::get_instance().log("sip_codec_headers::decode_supported_header");

  // Sanity checks
  osip_header_t *dest = nullptr;
  osip_message_get_supported(p_sip_message, 0, &dest);
  if (dest == nullptr) {
    return;
  }
  
  // FieldName
  p_supported_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("SUPPORTED_E"));
  // OptionTags
  loggers::get_instance().log("sip_codec_headers::decode_supported_header: got it: %s:%s", dest->hname, dest->hvalue);
  OPTIONAL<LibSip__SIPTypesAndValues::OptionTag__List>& l = p_supported_header.optionsTags();
  decode_option_tag_list(dest->hvalue, l);
} // End of method decode_supported_header

void sip_codec_headers::decode_user_agent_header(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::UserAgent& p_user_agent_header)
{
  loggers::get_instance().log("sip_codec_headers::decode_user_agent_header");

  // Sanity checks
  osip_header_t *dest = nullptr;
  osip_message_get_user_agent(p_sip_message, 0, &dest);
  if (dest == nullptr) {
    return;
  }
  
  // FieldName
  p_user_agent_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("USER_AGENT_E"));
  // UserAgent body
  loggers::get_instance().log("sip_codec_headers::decode_user_agent_header: got it: %s:%s", dest->hname, dest->hvalue);
  LibSip__SIPTypesAndValues::ServerVal__List& l = p_user_agent_header.userAgentBody();
  decode_server_val_list(dest->hvalue, l);
} // End of method decode_user_agent_header

void sip_codec_headers::decode_to_header(const osip_to_t* p_sip_to, LibSip__SIPTypesAndValues::To& p_to_header)
{
  loggers::get_instance().log("sip_codec_headers::decode_to_header");
  
  // Sanity check
  if (p_sip_to == nullptr) {
    return;
  }

  // FieldName
  p_to_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("TO_E"));
  // Addr_Union
  LibSip__SIPTypesAndValues::SipUrl uri;
  decode_uri(uri, ::osip_to_get_url((osip_to_t*)p_sip_to));
  LibSip__SIPTypesAndValues::Addr__Union addr;
  OPTIONAL<LibSip__SIPTypesAndValues::DisplayName> display_name;
  if (::osip_to_get_displayname((osip_to_t*)p_sip_to) != nullptr) {
    LibSip__SIPTypesAndValues::DisplayName n;
    n.token() = CHARSTRING(::osip_to_get_displayname((osip_to_t*)p_sip_to));
    display_name = OPTIONAL<LibSip__SIPTypesAndValues::DisplayName>(n);
    LibSip__SIPTypesAndValues::NameAddr name_addr(display_name, uri);
    addr.nameAddr() = name_addr;
  } else {
    display_name.set_to_omit();
    addr.addrSpecUnion() = uri;
  }
  p_to_header.addressField() = addr;
  // Params
  OPTIONAL<LibSip__Common::SemicolonParam__List> params;
  decode_semi_colon_params(p_sip_to->gen_params, params);
  p_to_header.toParams() = params;
  
  loggers::get_instance().log_msg("<<< sip_codec_headers::decode_to_header: ", p_to_header);
} // End of method decode_to_header

void sip_codec_headers::decode_via_header(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::Via& p_via_header)
{
  loggers::get_instance().log(">>> sip_codec_headers::decode_via_header");

  // Sanity checks
  osip_via_t *sip_via = nullptr;
  ::osip_message_get_via(p_sip_message, 0, &sip_via);
  if (sip_via == nullptr) {
    return;
  }
  
  // FieldName
  p_via_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("VIA_E"));
  // ViaBody
  LibSip__SIPTypesAndValues::ViaBody__List l;
  int i = 0;
  do {
    loggers::get_instance().log("sip_codec_headers::decode_via_header: Processing item #%d", i);
    LibSip__SIPTypesAndValues::ViaBody v;
    v.sentProtocol() = LibSip__SIPTypesAndValues::SentProtocol(
                                                               CHARSTRING("SIP"),
                                                               CHARSTRING(::via_get_version(sip_via)),
                                                               CHARSTRING(::via_get_protocol(sip_via))
                                                               );
    OPTIONAL<LibSip__SIPTypesAndValues::HostPort> host_port;
    decode_host_port(::via_get_host(sip_via), ::via_get_port(sip_via), host_port);
    loggers::get_instance().log_msg("sip_codec_headers::decode_via_uri: host_port: ", host_port);
    v.sentBy() = host_port;
    OPTIONAL<LibSip__Common::SemicolonParam__List> params;
    decode_semi_colon_params(sip_via->via_params, params);
    v.viaParams() = params;
    l[i++] = v;
  } while(::osip_message_get_via(p_sip_message, i, &sip_via) == 0); // End of 'while' statement
  p_via_header.viaBody() = l;
  
  loggers::get_instance().log_msg("<<< sip_codec_headers::decode_via_header: ", p_via_header);
} // End of method decode_via_header

void sip_codec_headers::decode_www_authenticate_header(const osip_www_authenticate_t* p_www_authenticate, LibSip__SIPTypesAndValues::WwwAuthenticate& p_www_authenticate_header)
{
  loggers::get_instance().log(">>> sip_codec_headers::decode_www_authenticate_header");

  // Sanity checks
  if (p_www_authenticate == nullptr) {
    loggers::get_instance().warning("sip_codec_headers::decode_www_authenticate_header: failed to decode WwwAuthenticate header");
    return;
  }
  
  // FieldName
  p_www_authenticate_header.fieldName() = LibSip__SIPTypesAndValues::FieldName(LibSip__SIPTypesAndValues::FieldName::str_to_enum("WWW_AUTHENTICATE_E"));
  // ViaBody
  LibSip__SIPTypesAndValues::Challenge c;
  std::string auth(::osip_www_authenticate_get_auth_type((osip_www_authenticate_t*)p_www_authenticate));
  loggers::get_instance().log("sip_codec_headers::decode_www_authenticate_header: Auth: %s", auth.c_str());
  LibSip__Common::CommaParam__List l;
  int i = 0;
  if (auth.compare("Digest") == 0) {
    l[i++] = LibSip__Common::GenericParam(CHARSTRING(auth.c_str()), OPTIONAL<LibSip__Common::GenValue>(OMIT_VALUE));
    auth = ::osip_www_authenticate_get_realm((osip_www_authenticate_t*)p_www_authenticate);
    loggers::get_instance().log("sip_codec_headers::decode_www_authenticate_header: Realm: %s", auth.c_str());
    if (auth.length() != 0) {
      LibSip__Common::GenValue v;
      v.quotedString() = CHARSTRING(auth.c_str());
      l[i++] = LibSip__Common::GenericParam(CHARSTRING("realm"), OPTIONAL<LibSip__Common::GenValue>(v));
    }
    auth = ::osip_www_authenticate_get_nonce((osip_www_authenticate_t*)p_www_authenticate);
    loggers::get_instance().log("sip_codec_headers::decode_www_authenticate_header: Nonce: %s", auth.c_str());
    if (auth.length() != 0) {
      LibSip__Common::GenValue v;
      v.quotedString() = CHARSTRING(auth.c_str());
      l[i++] = LibSip__Common::GenericParam(CHARSTRING("nonce"), OPTIONAL<LibSip__Common::GenValue>(v));
    }
    auth = ::osip_www_authenticate_get_algorithm((osip_www_authenticate_t*)p_www_authenticate);
    loggers::get_instance().log("sip_codec_headers::decode_www_authenticate_header: Algorithm: %s", auth.c_str());
    if (auth.length() != 0) {
      LibSip__Common::GenValue v;
      v.quotedString() = CHARSTRING(auth.c_str());
      l[i++] = LibSip__Common::GenericParam(CHARSTRING("algorithm"), OPTIONAL<LibSip__Common::GenValue>(v));
    }
    auth = ::osip_www_authenticate_get_qop_options((osip_www_authenticate_t*)p_www_authenticate);
    loggers::get_instance().log("sip_codec_headers::decode_www_authenticate_header: Qop: %s", auth.c_str());
    if (auth.length() != 0) {
      LibSip__Common::GenValue v;
      v.quotedString() = CHARSTRING(auth.c_str());
      l[i++] = LibSip__Common::GenericParam(CHARSTRING("qop"), OPTIONAL<LibSip__Common::GenValue>(v));
    }
    if (::osip_www_authenticate_get_stale((osip_www_authenticate_t*)p_www_authenticate) != NULL) {
      auth = ::osip_www_authenticate_get_stale((osip_www_authenticate_t*)p_www_authenticate);
      loggers::get_instance().log("sip_codec_headers::decode_www_authenticate_header: Stale: %s", auth.c_str());
      if (auth.length() != 0) {
        LibSip__Common::GenValue v;
        v.quotedString() = CHARSTRING(auth.c_str());
        l[i++] = LibSip__Common::GenericParam(CHARSTRING("stale"), OPTIONAL<LibSip__Common::GenValue>(v));
      }
    }
    loggers::get_instance().log_msg("sip_codec_headers::decode_www_authenticate_header: LibSip__Common::CommaParam__List= ", l);
    if (::osip_www_authenticate_get_domain((osip_www_authenticate_t*)p_www_authenticate) != NULL) {
      auth = ::osip_www_authenticate_get_domain((osip_www_authenticate_t*)p_www_authenticate);
      loggers::get_instance().log("sip_codec_headers::decode_www_authenticate_header: Domain: %s", auth.c_str());
    }
    if (::osip_www_authenticate_get_opaque((osip_www_authenticate_t*)p_www_authenticate) != NULL) {
      auth = ::osip_www_authenticate_get_opaque((osip_www_authenticate_t*)p_www_authenticate);
      loggers::get_instance().log("sip_codec_headers::decode_www_authenticate_header: Opaque: %s", auth.c_str());
    }
    
    c.digestCln() = l;
  } else {
    loggers::get_instance().error("sip_codec_headers::decode_www_authenticate_header: Not implemented yet");
    //c.otherChallenge() = l;
  }
  p_www_authenticate_header.challenge() = c;
  
  loggers::get_instance().log_msg("<<< sip_codec_headers::decode_www_authenticate_header: ", p_www_authenticate_header);
} // End of method decode_www_authenticate_header

