#include <stdexcept>
#include <regex>
#include <string>

#include "json_codec_factory.hh"

#include "loggers.hh"

#include "LibItsHttp_JsonMessageBodyTypes.hh"

int json_codec::encode (const LibItsHttp__JsonMessageBodyTypes::JsonBody& msg, OCTETSTRING& data)
{
  loggers::get_instance().log_msg(">>> json_codec::encode: ", (const Base_Type&)msg);

  TTCN_EncDec::clear_error();
  TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_DEFAULT);
  TTCN_Buffer encoding_buffer;

  if (msg.ischosen(LibItsHttp__JsonMessageBodyTypes::JsonBody::ALT_ueIdentityTagInfo)) {
    const UEidentityAPI__TypesAndValues::UeIdentityTagInfo& ue_identity_tag_info = msg.ueIdentityTagInfo();
    ue_identity_tag_info.encode(UEidentityAPI__TypesAndValues::UeIdentityTagInfo_descr_, encoding_buffer, TTCN_EncDec::CT_JSON);
    data = OCTETSTRING(encoding_buffer.get_len(), encoding_buffer.get_data());
  } else if (msg.ischosen(LibItsHttp__JsonMessageBodyTypes::JsonBody::ALT_userTrackingSubscription)) {
    const LocationAPI__TypesAndValues::UserTrackingSubscription& user_tracking_subscription = msg.userTrackingSubscription();
    user_tracking_subscription.encode(LocationAPI__TypesAndValues::UserTrackingSubscription_descr_, encoding_buffer, TTCN_EncDec::CT_JSON);
    data = /*char2oct(CHARSTRING("{\"userTrackingSubscription\": ")) + */OCTETSTRING(encoding_buffer.get_len(), encoding_buffer.get_data())/* + char2oct(CHARSTRING("}"))*/;
  } else if (msg.ischosen(LibItsHttp__JsonMessageBodyTypes::JsonBody::ALT_zonalTrafficSubscription)) {
    const LocationAPI__TypesAndValues::ZonalTrafficSubscription& zonal_traffic_subscription = msg.zonalTrafficSubscription();
    zonal_traffic_subscription.encode(LocationAPI__TypesAndValues::ZonalTrafficSubscription_descr_, encoding_buffer, TTCN_EncDec::CT_JSON);
    data = /*char2oct(CHARSTRING("{\"zonalTrafficSubscription\": ")) + */OCTETSTRING(encoding_buffer.get_len(), encoding_buffer.get_data())/* + char2oct(CHARSTRING("}"))*/;
  } else if (msg.ischosen(LibItsHttp__JsonMessageBodyTypes::JsonBody::ALT_circleNotificationSubscription)) {
    const LocationAPI__TypesAndValues::CircleNotificationSubscription& notif = msg.circleNotificationSubscription();
    notif.encode(LocationAPI__TypesAndValues::CircleNotificationSubscription_descr_, encoding_buffer, TTCN_EncDec::CT_JSON);
    data = /*char2oct(CHARSTRING("{\"circleNotificationSubscription\": ")) + */OCTETSTRING(encoding_buffer.get_len(), encoding_buffer.get_data())/* + char2oct(CHARSTRING("}"))*/;
  } else if (msg.ischosen(LibItsHttp__JsonMessageBodyTypes::JsonBody::ALT_distanceNotificationSubscription)) {
    const LocationAPI__TypesAndValues::DistanceNotificationSubscription& notif = msg.distanceNotificationSubscription();
    notif.encode(LocationAPI__TypesAndValues::DistanceNotificationSubscription_descr_, encoding_buffer, TTCN_EncDec::CT_JSON);
    data = /*char2oct(CHARSTRING("{\"distanceNotificationSubscription\": ")) + */OCTETSTRING(encoding_buffer.get_len(), encoding_buffer.get_data())/* + char2oct(CHARSTRING("}"))*/;
  } else if (msg.ischosen(LibItsHttp__JsonMessageBodyTypes::JsonBody::ALT_cellChangeSubscription)) {
    const RnisAPI__TypesAndValues::CellChangeSubscription& cell_change_subscription = msg.cellChangeSubscription();
    cell_change_subscription.encode(RnisAPI__TypesAndValues::CellChangeSubscription_descr_, encoding_buffer, TTCN_EncDec::CT_JSON);
    data = char2oct(CHARSTRING("{\"CellChangeSubscription\": ")) + OCTETSTRING(encoding_buffer.get_len(), encoding_buffer.get_data()) + char2oct(CHARSTRING("}"));
  } else if (msg.ischosen(LibItsHttp__JsonMessageBodyTypes::JsonBody::ALT_appContext)) {
    const UEAppInterfaceAPI__TypesAndValues::AppContext& app_context = msg.appContext();
    app_context.encode(UEAppInterfaceAPI__TypesAndValues::AppContext_descr_, encoding_buffer, TTCN_EncDec::CT_JSON);
    data = char2oct(CHARSTRING("{\"AppContext\": ")) + OCTETSTRING(encoding_buffer.get_len(), encoding_buffer.get_data()) + char2oct(CHARSTRING("}"));
  } else if (msg.ischosen(LibItsHttp__JsonMessageBodyTypes::JsonBody::ALT_serviceInfo)) {
    const AppEnablementAPI__TypesAndValues::ServiceInfo& service_info = msg.serviceInfo();
    service_info.encode(AppEnablementAPI__TypesAndValues::ServiceInfo_descr_, encoding_buffer, TTCN_EncDec::CT_JSON);
    data = /*char2oct(CHARSTRING("{\"ServiceInfo\": ")) + */OCTETSTRING(encoding_buffer.get_len(), encoding_buffer.get_data())/* + char2oct(CHARSTRING("}"))*/;
  } else if (msg.ischosen(LibItsHttp__JsonMessageBodyTypes::JsonBody::ALT_appTerminationNotificationSubscription)) {
    const AppEnablementAPI__TypesAndValues::AppTerminationNotificationSubscription& app = msg.appTerminationNotificationSubscription();
    app.encode(AppEnablementAPI__TypesAndValues::AppTerminationNotificationSubscription_descr_, encoding_buffer, TTCN_EncDec::CT_JSON);
    data = /*char2oct(CHARSTRING("{\"AppTerminationNotificationSubscription\": ")) + */OCTETSTRING(encoding_buffer.get_len(), encoding_buffer.get_data())/* + char2oct(CHARSTRING("}"))*/;
  } else if (msg.ischosen(LibItsHttp__JsonMessageBodyTypes::JsonBody::ALT_dnsRule)) {
    const AppEnablementAPI__TypesAndValues::DnsRule& dns_rule = msg.dnsRule();
    dns_rule.encode(AppEnablementAPI__TypesAndValues::DnsRule_descr_, encoding_buffer, TTCN_EncDec::CT_JSON);
    data = /*char2oct(CHARSTRING("{\"DnsRule\": ")) + */OCTETSTRING(encoding_buffer.get_len(), encoding_buffer.get_data())/* + char2oct(CHARSTRING("}"))*/;
  } else if (msg.ischosen(LibItsHttp__JsonMessageBodyTypes::JsonBody::ALT_serAvailabilityNotificationSubscription)) {
    const AppEnablementAPI__TypesAndValues::SerAvailabilityNotificationSubscription& ser = msg.serAvailabilityNotificationSubscription();
    ser.encode(AppEnablementAPI__TypesAndValues::SerAvailabilityNotificationSubscription_descr_, encoding_buffer, TTCN_EncDec::CT_JSON);
    data = /*char2oct(CHARSTRING("{\"SerAvailabilityNotificationSubscription\": ")) + */OCTETSTRING(encoding_buffer.get_len(), encoding_buffer.get_data())/* + char2oct(CHARSTRING("}"))*/;
  } else if (msg.ischosen(LibItsHttp__JsonMessageBodyTypes::JsonBody::ALT_trafficRule)) {
    const AppEnablementAPI__TypesAndValues::TrafficRule& traffic_rule = msg.trafficRule();
    traffic_rule.encode(AppEnablementAPI__TypesAndValues::TrafficRule_descr_, encoding_buffer, TTCN_EncDec::CT_JSON);
    data = /*char2oct(CHARSTRING("{\"TrafficRule\": ")) + */OCTETSTRING(encoding_buffer.get_len(), encoding_buffer.get_data())/* + char2oct(CHARSTRING("}"))*/;
  } else {
    loggers::get_instance().error("json_codec::encode: Not supported");
  }

  loggers::get_instance().log("<<< json_codec::encode");
  return 0;
}

int json_codec::decode (const OCTETSTRING& p_data, LibItsHttp__JsonMessageBodyTypes::JsonBody& msg, params* p_params)
{
  loggers::get_instance().log_msg(">>> json_codec::decode: p_data=", p_data);

  // Sanity checks
  params::const_iterator it;
  if (p_params == nullptr) {
    loggers::get_instance().warning("json_codec::decode: Failed to access p_params (null pointer)");
    return -1; // TODO Use p_data instead of return -1
  } else {
    it = p_params->find("decode_str");
    if (it == p_params->cend()) {
      loggers::get_instance().warning("json_codec::decode: Failed to access p_params item (decode_str)");
      return -1; // TODO Use p_data instead of return -1
    }
    loggers::get_instance().log("json_codec::decode: it->second='%c' / '%s'", it->second.c_str()[0], it->second.c_str());
  }

  // Remove data structure name (if present) ...
  std::string str;
  if ((it->second[0] != '[') && (it->second[0] != '{')) {
    int idx_begin = it->second.find(":");
    int idx_end = it->second.rfind("}") - 1; // Remove the last '}'
    str = it->second.substr(idx_begin + 1, idx_end - idx_begin);
  } else {
    str = it->second;
  }
  // ..and create the decoding buffer
  TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_DEFAULT);
  TTCN_EncDec::clear_error();
  loggers::get_instance().log("json_codec::decode: decoding_buffer='%c' / '%s'", str[0], str.c_str());
  TTCN_Buffer decoding_buffer(OCTETSTRING(str.length(), (const unsigned char*)str.c_str()));

 if (it->second.find("\"userList\"") != std::string::npos) { // Be careful to the order
                                                             // TODO To be refined, find("\"userList\"") is not optimal
    int idx_begin = it->second.find(":");
    int idx_end = it->second.rfind("}") - 1; // Remove the last '}'
    str = it->second.substr(idx_begin + 1, idx_end - idx_begin);
    TTCN_Buffer decoding_buffer(OCTETSTRING(str.length(), (const unsigned char*)str.c_str()));
    LocationAPI__TypesAndValues::UserList user_list;
    user_list.decode(LocationAPI__TypesAndValues::UserList_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
    msg.userList() = user_list;
  } else if (it->second.find("\"accessPointList\"") != std::string::npos) { // Be careful to the order
                                                                              // TODO To be refined, find("\"accessPointList\"") is not optimal
    LocationAPI__TypesAndValues::AccessPointList access_point_list;
    access_point_list.decode(LocationAPI__TypesAndValues::AccessPointList_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
    msg.accessPointList() = access_point_list;
  } else if (it->second.find("\"userTrackingSubscription\"") != std::string::npos) {
    int idx_begin = it->second.find(":");
    int idx_end = it->second.rfind("}") - 1; // Remove the last '}'
    str = it->second.substr(idx_begin + 1, idx_end - idx_begin);
    TTCN_Buffer decoding_buffer(OCTETSTRING(str.length(), (const unsigned char*)str.c_str()));
    LocationAPI__TypesAndValues::UserTrackingSubscription user_tracking_subscription;
    user_tracking_subscription.decode(LocationAPI__TypesAndValues::UserTrackingSubscription_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
    msg.userTrackingSubscription() = user_tracking_subscription;
  } else if (it->second.find("\"periodicTrackingSubscription\"") != std::string::npos) {
    int idx_begin = it->second.find(":");
    int idx_end = it->second.rfind("}") - 1; // Remove the last '}'
    str = it->second.substr(idx_begin + 1, idx_end - idx_begin);
    TTCN_Buffer decoding_buffer(OCTETSTRING(str.length(), (const unsigned char*)str.c_str()));
    LocationAPI__TypesAndValues::PeriodicTrackingSubscription periodic_tracking_subscription;
    periodic_tracking_subscription.decode(LocationAPI__TypesAndValues::PeriodicTrackingSubscription_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
    msg.periodicTrackingSubscription() = periodic_tracking_subscription;
  } else if (it->second.find("\"accessPointId\"") != std::string::npos) {
    LocationAPI__TypesAndValues::UserInfo user_info;
    user_info.decode(LocationAPI__TypesAndValues::UserInfo_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
    msg.userInfo() = user_info;
  } else if (it->second.find("\"terminalDistance\"") != std::string::npos) {
    int idx_begin = it->second.find(":");
    int idx_end = it->second.rfind("}") - 1; // Remove the last '}'
    str = it->second.substr(idx_begin + 1, idx_end - idx_begin);
    TTCN_Buffer decoding_buffer(OCTETSTRING(str.length(), (const unsigned char*)str.c_str()));
    LocationAPI__TypesAndValues::TerminalDistance terminal_distance;
    terminal_distance.decode(LocationAPI__TypesAndValues::TerminalDistance_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
    msg.terminalDistance() = terminal_distance;
  } else if (it->second.find("\"enteringLeavingCriteria\"") != std::string::npos) {
    LocationAPI__TypesAndValues::CircleNotificationSubscription notif;
    notif.decode(LocationAPI__TypesAndValues::CircleNotificationSubscription_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
    msg.circleNotificationSubscription() = notif;
  } else if (it->second.find("\"distanceNotificationSubscription\"") != std::string::npos) {
    LocationAPI__TypesAndValues::DistanceNotificationSubscription notif;
    notif.decode(LocationAPI__TypesAndValues::DistanceNotificationSubscription_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
    msg.distanceNotificationSubscription() = notif;
  } else if (it->second.find("\"SubscriptionLinkList\"") != std::string::npos) { // Be careful to the order
                                                                                 // TODO To be refined, find("\"accessPointList\"") is not optimal
    RnisAPI__TypesAndValues::SubscriptionLinkList subscription_link_list;
    subscription_link_list.decode(RnisAPI__TypesAndValues::SubscriptionLinkList_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
    msg.subscriptionLinkList() = subscription_link_list;
  } else if (it->second.find("\"ueIdentityTagInfo\"") != std::string::npos) {
    UEidentityAPI__TypesAndValues::UeIdentityTagInfo ue_identity_tag_info;
    ue_identity_tag_info.decode(UEidentityAPI__TypesAndValues::UeIdentityTagInfo_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
    msg.ueIdentityTagInfo() = ue_identity_tag_info;
  } else if (it->second.find("\"serName\"") != std::string::npos) { // Be careful to the order
                                                                    // TODO To be refined, find("\"accessPointList\"") is not optimal
    if (it->second[0] == '[') {
      AppEnablementAPI__TypesAndValues::ServiceInfoList service_info_list;
      service_info_list.decode(AppEnablementAPI__TypesAndValues::ServiceInfoList_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
      msg.serviceInfoList() = service_info_list;
    } else {
      AppEnablementAPI__TypesAndValues::ServiceInfo service_info;
      service_info.decode(AppEnablementAPI__TypesAndValues::ServiceInfo_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
      msg.serviceInfo() = service_info;
    }
  } else if (it->second.find("\"security\"") != std::string::npos) { // Be careful to the order
                                                                     // TODO To be refined, find("\"accessPointList\"") is not optimal
    AppEnablementAPI__TypesAndValues::TransportInfoList transport_info_list;
    transport_info_list.decode(AppEnablementAPI__TypesAndValues::TransportInfoList_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
    msg.transportInfoList() = transport_info_list;
  } else if (it->second.find("\"trafficRuleId\"") != std::string::npos) {
    if (it->second[0] == '[') {
      AppEnablementAPI__TypesAndValues::TrafficRuleList traffic_rule_list;
      traffic_rule_list.decode(AppEnablementAPI__TypesAndValues::TrafficRuleList_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
      msg.trafficRuleList() = traffic_rule_list;
    } else {
      AppEnablementAPI__TypesAndValues::TrafficRule traffic_rule;
      traffic_rule.decode(AppEnablementAPI__TypesAndValues::TrafficRule_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
      msg.trafficRule() = traffic_rule;
    }
  } else if (it->second.find("\"dnsRuleId\"") != std::string::npos) {
    if (it->second[0] == '[') {
      AppEnablementAPI__TypesAndValues::DnsRuleList dns_rule_list;
      dns_rule_list.decode(AppEnablementAPI__TypesAndValues::DnsRuleList_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
      msg.dnsRuleList() = dns_rule_list;
    } else {
      AppEnablementAPI__TypesAndValues::DnsRule dns_rule;
      dns_rule.decode(AppEnablementAPI__TypesAndValues::DnsRule_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
      msg.dnsRule() = dns_rule;
    }
  } else if ((it->second.find("\"appInstanceId\"") != std::string::npos) && (it->second.find("\"subscriptionType\"") != std::string::npos)) {
    AppEnablementAPI__TypesAndValues::AppTerminationNotificationSubscription app_term;
    app_term.decode(AppEnablementAPI__TypesAndValues::AppTerminationNotificationSubscription_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
    msg.appTerminationNotificationSubscription() = app_term;
  } else if ((it->second.find("\"_links\"") != std::string::npos) && (it->second.find("\"subscriptions\"") != std::string::npos)) {
    AppEnablementAPI__TypesAndValues::SubscriptionLinkList sub_link_list;
    sub_link_list.decode(AppEnablementAPI__TypesAndValues::SubscriptionLinkList_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
    msg.subscriptionLinkList__app__ens() = sub_link_list;
  } else if (it->second.find("\"subscriptionType\"") != std::string::npos) {
    AppEnablementAPI__TypesAndValues::SerAvailabilityNotificationSubscription ser_av;
    ser_av.decode(AppEnablementAPI__TypesAndValues::SerAvailabilityNotificationSubscription_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
    msg.serAvailabilityNotificationSubscription() = ser_av;
  } else if (it->second.find("\"ntpServers\"") != std::string::npos) {
    AppEnablementAPI__TypesAndValues::TimingCaps timing_caps;
    timing_caps.decode(AppEnablementAPI__TypesAndValues::TimingCaps_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
    msg.timingCaps() = timing_caps;
  } else if (it->second.find("\"timeSourceStatus\"") != std::string::npos) {
    AppEnablementAPI__TypesAndValues::CurrentTime current_time;
    current_time.decode(AppEnablementAPI__TypesAndValues::CurrentTime_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
    msg.currentTime() = current_time;
  } else if (it->second.find("\"CellChangeSubscription\"") != std::string::npos) {
//    // Replace "type": "1" by type": "EU_IPV4_ADDRESS", "type": "2"...
//    // TODO Create a method instead of copy/past
//    //loggers::get_instance().log("json_codec::decode: Before, str=%s", str.c_str());
//    std::size_t it_start = str.find("\"type\"");
//    loggers::get_instance().log("json_codec::decode: id_start=%d", it_start);
//    if (it_start != std::string::npos) {
//      std::size_t it_stop = str.find(",", it_start);
//      //loggers::get_instance().log("json_codec::decode: id_stop=%d", it_stop);
//      //loggers::get_instance().log("json_codec::decode: segment=%s", str.substr(it_start, it_stop - it_start).c_str());
//      std::size_t it = str.find("1", it_start, 1);
//      //loggers::get_instance().log("json_codec::decode: it=%d", it);
//      if ((it != std::string::npos) && (it < it_stop)) {
//        str = str.substr(0, it) + "UE_IPV4_ADDRESS" + str.substr(it + 1);
//      } else {
//        it = str.find("2", it_start, 1);
//        //loggers::get_instance().log("json_codec::decode: it=%d", it);
//        if ((it != std::string::npos) && (it < it_stop)) {
//          str = str.substr(0, it) + "UE_IPV6_ADDRESS" + str.substr(it + 1);
//        } else {
//          it = str.find("3", it_start, 1);
//          //loggers::get_instance().log("json_codec::decode: it=%d", it);
//          if ((it != std::string::npos) && (it < it_stop)) {
//            str = str.substr(0, it) + "NATED_IP_ADDRESS" + str.substr(it + 1);
//          } else {
//            it = str.find("4", it_start, 1);
//            //loggers::get_instance().log("json_codec::decode: it=%d", it);
//            if ((it != std::string::npos) && (it < it_stop)) {
//              str = str.substr(0, it) + "GTP_TEID" + str.substr(it + 1);
//            }
//          }
//        }
//      }
//    }
//    //loggers::get_instance().log("json_codec::decode: After, str=%s", str.c_str());
//    decoding_buffer.clear();
//    decoding_buffer.put_os(OCTETSTRING(str.length(), (const unsigned char*)str.c_str()));
    RnisAPI__TypesAndValues::CellChangeSubscription cell_change_subscription;
    cell_change_subscription.decode(RnisAPI__TypesAndValues::CellChangeSubscription_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
    msg.cellChangeSubscription() = cell_change_subscription;
    //TODO Continue with other ChangeSubscription
  } else if (it->second.find("\"RabInfo\"") != std::string::npos) {
//    // Replace "type": "1" by type": "EU_IPV4_ADDRESS", "type": "2"...
//    // TODO Create a method instead of copy/past
//    // loggers::get_instance().log("json_codec::decode: Before, str=%s", str.c_str());
//    std::size_t it_start = str.find("\"type\"");
//    loggers::get_instance().log("json_codec::decode: id_start=%d", it_start);
//    if (it_start != std::string::npos) {
//      std::size_t it_stop = str.find(",", it_start);
//      //loggers::get_instance().log("json_codec::decode: id_stop=%d", it_stop);
//      //loggers::get_instance().log("json_codec::decode: segment=%s", str.substr(it_start, it_stop - it_start).c_str());
//      std::size_t it = str.find("1", it_start, 1);
//      //loggers::get_instance().log("json_codec::decode: it=%d", it);
//      if ((it != std::string::npos) && (it < it_stop)) {
//        str = str.substr(0, it) + "UE_IPV4_ADDRESS" + str.substr(it + 1);
//      } else {
//        it = str.find("2", it_start, 1);
//        //loggers::get_instance().log("json_codec::decode: it=%d", it);
//        if ((it != std::string::npos) && (it < it_stop)) {
//          str = str.substr(0, it) + "UE_IPV6_ADDRESS" + str.substr(it + 1);
//        } else {
//          it = str.find("3", it_start, 1);
//          //loggers::get_instance().log("json_codec::decode: it=%d", it);
//          if ((it != std::string::npos) && (it < it_stop)) {
//            str = str.substr(0, it) + "NATED_IP_ADDRESS" + str.substr(it + 1);
//          } else {
//            it = str.find("4", it_start, 1);
//            //loggers::get_instance().log("json_codec::decode: it=%d", it);
//            if ((it != std::string::npos) && (it < it_stop)) {
//              str = str.substr(0, it) + "GTP_TEID" + str.substr(it + 1);
//            }
//          }
//        }
//      }
//    }
//    //loggers::get_instance().log("json_codec::decode: After, str=%s", str.c_str());
//    decoding_buffer.clear();
//    decoding_buffer.put_os(OCTETSTRING(str.length(), (const unsigned char*)str.c_str()));
    RnisAPI__TypesAndValues::RabInfo rab_info;
    rab_info.decode(RnisAPI__TypesAndValues::RabInfo_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
    msg.rabInfo() = rab_info;
  } else if (it->second.find("\"S1BearerInfo\"") != std::string::npos) {
//    // Replace "type": "1" by type": "EU_IPV4_ADDRESS", "type": "2"...
//    // TODO Create a method instead of copy/past
//    // loggers::get_instance().log("json_codec::decode: Before, str=%s", str.c_str());
//    std::size_t it_start = str.find("\"type\"");
//    loggers::get_instance().log("json_codec::decode: id_start=%d", it_start);
//    if (it_start != std::string::npos) {
//      std::size_t it_stop = str.find(",", it_start);
//      //loggers::get_instance().log("json_codec::decode: id_stop=%d", it_stop);
//      //loggers::get_instance().log("json_codec::decode: segment=%s", str.substr(it_start, it_stop - it_start).c_str());
//      std::size_t it = str.find("1", it_start, 1);
//      //loggers::get_instance().log("json_codec::decode: it=%d", it);
//      if ((it != std::string::npos) && (it < it_stop)) {
//        str = str.substr(0, it) + "UE_IPV4_ADDRESS" + str.substr(it + 1);
//      } else {
//        it = str.find("2", it_start, 1);
//        //loggers::get_instance().log("json_codec::decode: it=%d", it);
//        if ((it != std::string::npos) && (it < it_stop)) {
//          str = str.substr(0, it) + "UE_IPV6_ADDRESS" + str.substr(it + 1);
//        } else {
//          it = str.find("3", it_start, 1);
//          //loggers::get_instance().log("json_codec::decode: it=%d", it);
//          if ((it != std::string::npos) && (it < it_stop)) {
//            str = str.substr(0, it) + "NATED_IP_ADDRESS" + str.substr(it + 1);
//          } else {
//            it = str.find("4", it_start, 1);
//            //loggers::get_instance().log("json_codec::decode: it=%d", it);
//            if ((it != std::string::npos) && (it < it_stop)) {
//              str = str.substr(0, it) + "GTP_TEID" + str.substr(it + 1);
//            }
//          }
//        }
//      }
//    }
//    //loggers::get_instance().log("json_codec::decode: After, str=%s", str.c_str());
//    decoding_buffer.clear();
//    decoding_buffer.put_os(OCTETSTRING(str.length(), (const unsigned char*)str.c_str()));
    RnisAPI__TypesAndValues::S1BearerInfo s1_nearer_info;
    s1_nearer_info.decode(RnisAPI__TypesAndValues::S1BearerInfo_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
    msg.s1BearerInfo() = s1_nearer_info;
  } else if (it->second.find("\"PlmnInfo\"") != std::string::npos) {
    RnisAPI__TypesAndValues::PlmnInfo plmn_info;
    plmn_info.decode(RnisAPI__TypesAndValues::PlmnInfo_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
    msg.plmnInfo() = plmn_info;
  } else if (it->second.find("\"RabEstSubscription\"") != std::string::npos) {
    RnisAPI__TypesAndValues::RabEstSubscription rab_est_subscription;
    rab_est_subscription.decode(RnisAPI__TypesAndValues::RabEstSubscription_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
    msg.rabEstSubscription() = rab_est_subscription;
  } else if (it->second.find("\"RabModSubscription\"") != std::string::npos) {
    RnisAPI__TypesAndValues::RabModSubscription rab_mod_subscription;
    rab_mod_subscription.decode(RnisAPI__TypesAndValues::RabModSubscription_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
    msg.rabModSubscription() = rab_mod_subscription;
  } else if (it->second.find("\"RabRelSubscription\"") != std::string::npos) {
    RnisAPI__TypesAndValues::RabRelSubscription rab_rel_subscription;
    rab_rel_subscription.decode(RnisAPI__TypesAndValues::RabRelSubscription_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
    msg.rabRelSubscription() = rab_rel_subscription;
  } else if (it->second.find("\"AppContext\"") != std::string::npos) {
    UEAppInterfaceAPI__TypesAndValues::AppContext appContext;
    appContext.decode(UEAppInterfaceAPI__TypesAndValues::AppContext_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
    msg.appContext() = appContext;
  } else if (it->second.find("\"AppInfo\"") != std::string::npos) {
    UEAppInterfaceAPI__TypesAndValues::AppInfo appInfo;
    appInfo.decode(UEAppInterfaceAPI__TypesAndValues::AppInfo_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
    msg.appInfo() = appInfo;
  } else if ((it->second.find("\"bwInfo\"") != std::string::npos) || (it->second.find("\"fixedBWPriority\"") != std::string::npos)) {
    // Need to change some enumerated string not supported by TTCN-3 language
    if (str.find("not defined in the present document") != std::string::npos) {
      str = regex_replace(str, regex("not defined in the present document"), "not_defined_in_the_present_document");
    }
    if (str.find("00") != std::string::npos) {
      str = regex_replace(str, regex("00"), "Downlink");
    } else if (str.find("01 = Uplink (towards the application/session)") != std::string::npos) {
      str = regex_replace(str, regex("01"), "Uplink");
    } else if (str.find("10 = Symmetrical") != std::string::npos) {
      str = regex_replace(str, regex("10"), "Symmetrical");
    }
    if (it->second[0] == '[') { // BwInfoList
      TTCN_Buffer decoding_buffer_(OCTETSTRING(str.length(), (const unsigned char*)str.c_str()));
      BwManagementAPI__TypesAndValues::BwInfoList bw_info_list;
      bw_info_list.decode(BwManagementAPI__TypesAndValues::BwInfoList_descr_, decoding_buffer_, TTCN_EncDec::CT_JSON);
      msg.bwInfoList() = bw_info_list;
     } else {
      BwManagementAPI__TypesAndValues::BwInfo bw_info;
       TTCN_Buffer decoding_buffer_(OCTETSTRING(str.length(), (const unsigned char*)str.c_str()));
       bw_info.decode(BwManagementAPI__TypesAndValues::BwInfo_descr_, decoding_buffer_, TTCN_EncDec::CT_JSON);
       msg.bwInfo() = bw_info;
    }
  } else if (it->second.find("\"detail\"") != std::string::npos) {
    LibMec__TypesAndValues::ProblemDetails problem_details;
    problem_details.decode(LibMec__TypesAndValues::ProblemDetails_descr_, decoding_buffer, TTCN_EncDec::CT_JSON);
    msg.problemDetails() = problem_details;
  } else {
    loggers::get_instance().warning("json_codec::decode: Unsupported variant");
    return -1;
  }

  loggers::get_instance().log_msg("<<< json_codec::decode: ", (const Base_Type&)msg);
  return 0;
}

json_codec_factory json_codec_factory::_f;
