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

#include "sip_codec_response.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_response::encode (const LibSip__SIPTypesAndValues::Response& msg, OCTETSTRING& data)
{
  loggers::get_instance().log_msg(">>> sip_codec_response::encode: ", (const Base_Type&)msg);

  osip_message_t* sip_message = nullptr; // TODO Use smart pointer
  ::parser_init();
  int result = ::osip_message_init(&sip_message);
  if (result != 0) {
    loggers::get_instance().warning("sip_codec_response::encode: Failed to initialise internal data structures");
    return -1;
  }

  if (encode_response(msg, sip_message) == -1) {
    loggers::get_instance().warning("sip_codec_response::encode: Failed to encode Response");
    ::osip_message_free(sip_message);
    sip_message = nullptr;
    return -1;
  }
  
  char* buffer = nullptr;
  size_t length = 0;
  result = ::osip_message_to_str(sip_message, &buffer, &length);
  if (result != 0) {
    loggers::get_instance().warning("sip_codec_response::encode: Failed to encode data structures: return code=%d", result);
    ::osip_message_free(sip_message);
    return -1;
  }
  loggers::get_instance().log("sip_codec_response::encode: Message:%s", buffer);
  data = OCTETSTRING(length, (const unsigned char*)buffer);
  osip_free(buffer);
  ::osip_message_free(sip_message);
  
  loggers::get_instance().log_msg("<<< sip_codec_response::encode: data=", data);
  return result;
}

int sip_codec_response::decode (const OCTETSTRING& data, LibSip__SIPTypesAndValues::Response& msg, params* p_params)
{
  loggers::get_instance().log_msg(">>> sip_codec_response::decode: data=", data);

  // Sanity checks
  if (data.lengthof() == 0) {
    loggers::get_instance().warning("sip_codec_response::decode: Wrong parameters");
    return -1;
  }

  osip_message_t* sip_message;
  ::parser_init();
  int result = ::osip_message_init(&sip_message);
  if (result != 0) {
    loggers::get_instance().warning("sip_codec_response::decode: Failed to initialise internal data structures");
    return -1;
  }
  result = ::osip_message_parse(sip_message, (const char*)static_cast<const unsigned char*>(data), data.lengthof());
  if (result != 0) {
    loggers::get_instance().warning("sip_codec_response::decode: Failed to parse SIP message");
    ::osip_message_free(sip_message);
    return -1;
  }

  // Fill StatusLine
  decode_status_line(sip_message, msg);

  // Fill Headers
  decode_response_headers(sip_message, msg);

  // Fill MessageBody
  decode_message_body(sip_message, msg.messageBody());
  
  // Fill Payload
  decode_payload(sip_message, msg);
  
  ::osip_message_free(sip_message);
  loggers::get_instance().log_msg("sip_codec_response::decode: ", msg);
  
  return 0;
}

int sip_codec_response::encode_response(const LibSip__SIPTypesAndValues::Response& p_response, osip_message_t* p_sip_message)
{
  loggers::get_instance().log(">>> sip_codec_response::encode_response");
  
  encode_status_line(p_response.statusLine(), p_sip_message);
  
  encode_response_headers(p_response.msgHeader(), p_sip_message);
  
  if (p_response.messageBody().is_present()) {
    const LibSip__MessageBodyTypes::MessageBody& m = static_cast<const LibSip__MessageBodyTypes::MessageBody&>(*p_response.messageBody().get_opt_value());
    encode_message_body(m, p_sip_message);
  }
  
  if (p_response.payload().is_present()) {
    const LibSip__SIPTypesAndValues::Payload& p = static_cast<const LibSip__SIPTypesAndValues::Payload&>(*p_response.payload().get_opt_value());
    encode_response_payload(p, p_sip_message);
  }

  return 0;
} // End of method encode_response

int sip_codec_response::encode_status_line(const LibSip__SIPTypesAndValues::StatusLine& p_status_line, osip_message_t* p_sip_message)
{
  loggers::get_instance().log(">>> sip_codec_response::encode_status_line");

  // Sip version
  char* p = (char*)osip_malloc(p_status_line.sipVersion().lengthof() + 1); // Will be freed by osip_message_free
  ::strcpy(p, (char*)static_cast<const char*>(p_status_line.sipVersion()));
  ::osip_message_set_version(p_sip_message, p);

  // Status code
  loggers::get_instance().log("sip_codec_response::encode_status_line: status code=%d", static_cast<const int>(p_status_line.statusCode()));
  ::osip_message_set_status_code(p_sip_message, static_cast<const int>(p_status_line.statusCode()));
  
  // Reason phrase
  p = (char*)osip_malloc(p_status_line.reasonPhrase().lengthof() + 1); // Will be freed by osip_message_free
  ::strcpy(p, (char*)static_cast<const char*>(p_status_line.reasonPhrase()));
  ::osip_message_set_reason_phrase(p_sip_message, p);

  return 0;
} // End of method encode_status_line

int sip_codec_response::encode_response_headers(const LibSip__SIPTypesAndValues::MessageHeader& p_msg_header, osip_message_t* p_sip_message)
{ // TODO Rename to encode_headers and call sip_codec_headers::encode_headers
  loggers::get_instance().log_msg(">>> sip_codec_response::encode_response_headers: ", p_msg_header);
  
  if (encode_headers(p_msg_header, p_sip_message) == -1) {
    loggers::get_instance().warning("sip_codec_response::encode_response_headers: Failed to encode headers");
    return -1;
  }
  
  return 0;
} // End of method encode_response_headers

int sip_codec_response::encode_response_payload(const LibSip__SIPTypesAndValues::Payload& p_payload, osip_message_t* p_sip_message)
{
  loggers::get_instance().log(">>> sip_codec_response::encode_response_payload");

  return 0;
} // End of method encode_response_payload

void sip_codec_response::decode_status_line(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::Response& p_response)
{
  loggers::get_instance().log(">>> sip_codec_response::decode_status_line");
  
  LibSip__SIPTypesAndValues::StatusLine status_line;
  status_line.sipVersion() = CHARSTRING(::osip_message_get_version(p_sip_message));
  loggers::get_instance().log_msg("sip_codec_response::decode_status_line: sipVersion: ", status_line.sipVersion());
  status_line.statusCode() = INTEGER(osip_message_get_status_code(p_sip_message));
  loggers::get_instance().log_msg("sip_codec_response::decode_status_line: statusCode: ", status_line.statusCode());
  status_line.reasonPhrase() = CHARSTRING(::osip_message_get_reason_phrase(p_sip_message));
  loggers::get_instance().log_msg("sip_codec_response::decode_status_line: reasonPhrase: ", status_line.reasonPhrase());
  p_response.statusLine() = status_line;

  loggers::get_instance().log_msg("<<< sip_codec_response::decode_status_line: ", p_response.statusLine());
} // End of method decode_status_line

void sip_codec_response::decode_response_headers(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::Response& p_response)
{ // TODO rename into decode_headers and call sip_code_headers::decode_headers
  loggers::get_instance().log(">>> sip_codec_response::decode_response_headers");
  
  LibSip__SIPTypesAndValues::MessageHeader& headers = p_response.msgHeader();
  decode_headers(p_sip_message, headers);
  if (!headers.is_bound()) {
    loggers::get_instance().warning("sip_codec_response::decode_response_headers: Failed to decode headers");
    return;
  }
  
  loggers::get_instance().log_msg("<<< sip_codec_response::decode_response_headers: ", p_response);
} // End of method decode_response_headers

void sip_codec_response::decode_payload(const osip_message_t* p_sip_message, LibSip__SIPTypesAndValues::Response& p_response)
{
  loggers::get_instance().log(">>> sip_codec_response::decode_payload");

  p_response.payload().set_to_omit();
  
} // End of method decode_payload
