#include "LibItsHttp_TypesAndValues.hh"

#include "http_layer_factory.hh"

#include "loggers.hh"

#include "converter.hh"

http_layer::http_layer(const std::string & p_type, const std::string & param) : layer(p_type), _params(), _codec(), _headers(new LibItsHttp__TypesAndValues::HeaderLines)//, _device_mode{false}
{
  loggers::get_instance().log(">>> http_layer::http_layer: %s, %s", to_string().c_str(), param.c_str());
  // Setup parameters
  Params::convert(_params, param);

  // Build basic headers
  int i = 0;
  LibItsHttp__TypesAndValues::charstring__list values;
  values[0] = "application/xml";
  (*_headers)[i++] = LibItsHttp__TypesAndValues::HeaderLine(CHARSTRING("Accept"), values);
  values.set_size(0);
  values[0] = "application/xml";
  values[1] = "charset=utf-8";
  (*_headers)[i++] = LibItsHttp__TypesAndValues::HeaderLine(CHARSTRING("Content-Type"), values);
  values.set_size(0);
  values[0] = "0";
  (*_headers)[i++] = LibItsHttp__TypesAndValues::HeaderLine(CHARSTRING("Content-Length"), values);
  values.set_size(0);
  values[0] = "www.google.com";
  (*_headers)[i++] = LibItsHttp__TypesAndValues::HeaderLine(CHARSTRING("Host"), values);
  values.set_size(0);
}

void http_layer::send_data(OCTETSTRING& data, Params& params) {
  loggers::get_instance().log_msg(">>> http_layer::send_data: ", data);

  Params::const_iterator it = params.find("HttpMethod");
  LibItsHttp__TypesAndValues::HttpMessage msg;
  if (it != params.cend()) {

  } else { // Assume it is a GET
    LibItsHttp__TypesAndValues::Request request;
    request.method() = "GET";
    request.uri() = "/";
    request.version__major() = 1;
    request.version__minor() = 1;
    request.header() = *_headers.get();
    std::vector<uint8_t> buf(static_cast<const unsigned char *>(data), data.lengthof() + static_cast<const unsigned char *>(data));
    CHARSTRING c(converter::get_instance().bytes_to_string(buf).c_str());
    request.body() = OPTIONAL<CHARSTRING>(c);
    msg.request() = request;
  }
  loggers::get_instance().log_msg("http_layer::send_data: HttpMessage: ", msg);
  OCTETSTRING os;
  _codec.encode(msg, os);
  send_to_all_layers(os, params);
}

void http_layer::receive_data(OCTETSTRING& data, Params& params)
{
  loggers::get_instance().log_msg(">>> http_layer::receive_data: ", data);

  // Decode HTTP message
  LibItsHttp__TypesAndValues::HttpMessage httpMessage;
  if (_codec.decode(data, httpMessage) == -1) {
	  loggers::get_instance().warning("http_layer::receive_data: Failed to decode data");
	  return;
  }
  // Extract payload
  OCTETSTRING payload;
  if (httpMessage.ischosen(LibItsHttp__TypesAndValues::HttpMessage::ALT_request)) {
	  if (httpMessage.request().body().is_present()) {
		  const CHARSTRING& body = static_cast<OPTIONAL<CHARSTRING>&>(*(httpMessage.request().body().get_opt_value()));
		  std::vector<uint8_t> buf = converter::get_instance().string_to_bytes(static_cast<const char*>(body));
		  payload = OCTETSTRING(buf.size(), buf.data());
	  } else {
		  loggers::get_instance().warning("http_layer::receive_data: No payload in HTTP request");
		  return;
	  }
  } else if (httpMessage.ischosen(LibItsHttp__TypesAndValues::HttpMessage::ALT_response)) {
	  if (httpMessage.response().body().is_present()) {
		  const CHARSTRING& body = static_cast<OPTIONAL<CHARSTRING>&>(*(httpMessage.response().body().get_opt_value()));
		  std::vector<uint8_t> buf = converter::get_instance().string_to_bytes(static_cast<const char*>(body));
		  payload = OCTETSTRING(buf.size(), buf.data());
	  } else {
		  loggers::get_instance().warning("http_layer::receive_data: No payload in HTTP response");
		  return;
	  }
  } else {
	  loggers::get_instance().warning("http_layer::receive_data: Unexpected HTTP message");
	  return;
  }

  receive_to_all_layers(payload, params);
}

http_layer_factory http_layer_factory::_f;

