/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */

#include "remote/httputility.hpp"
#include "base/json.hpp"
#include "base/logger.hpp"
#include <map>
#include <vector>

using namespace icinga;

Dictionary::Ptr HttpUtility::FetchRequestParameters(HttpRequest& request)
{
	Dictionary::Ptr result;

	String body;
	char buffer[1024];
	size_t count;

	while ((count = request.ReadBody(buffer, sizeof(buffer))) > 0)
		body += String(buffer, buffer + count);

	if (!body.IsEmpty()) {
		Log(LogDebug, "HttpUtility")
			<< "Request body: '" << body << "'";

		result = JsonDecode(body);
	}

	if (!result)
		result = new Dictionary();

	std::map<String, std::vector<String>> query;
	for (const auto& kv : request.RequestUrl->GetQuery()) {
		query[kv.first].emplace_back(kv.second);
	}

	for (auto& kv : query) {
		result->Set(kv.first, Array::FromVector(kv.second));
	}

	return result;
}

void HttpUtility::SendJsonBody(HttpResponse& response, const Dictionary::Ptr& params, const Value& val)
{
	response.AddHeader("Content-Type", "application/json");

	bool prettyPrint = false;

	if (params)
		prettyPrint = GetLastParameter(params, "pretty");

	String body = JsonEncode(val, prettyPrint);

	response.WriteBody(body.CStr(), body.GetLength());
}

Value HttpUtility::GetLastParameter(const Dictionary::Ptr& params, const String& key)
{
	Value varr = params->Get(key);

	if (!varr.IsObjectType<Array>())
		return varr;

	Array::Ptr arr = varr;

	if (arr->GetLength() == 0)
		return Empty;
	else
		return arr->Get(arr->GetLength() - 1);
}

void HttpUtility::SendJsonError(HttpResponse& response, const Dictionary::Ptr& params,
	int code, const String& info, const String& diagnosticInformation)
{
	Dictionary::Ptr result = new Dictionary();
	response.SetStatus(code, HttpUtility::GetErrorNameByCode(code));
	result->Set("error", code);

	bool verbose = false;

	if (params)
		verbose = HttpUtility::GetLastParameter(params, "verbose");

	if (!info.IsEmpty())
		result->Set("status", info);

	if (verbose) {
		if (!diagnosticInformation.IsEmpty())
			result->Set("diagnostic_information", diagnosticInformation);
	}

	HttpUtility::SendJsonBody(response, params, result);
}

String HttpUtility::GetErrorNameByCode(const int code)
{
	switch(code) {
		case 200:
			return "OK";
		case 201:
			return "Created";
		case 204:
			return "No Content";
		case 304:
			return "Not Modified";
		case 400:
			return "Bad Request";
		case 401:
			return "Unauthorized";
		case 403:
			return "Forbidden";
		case 404:
			return "Not Found";
		case 409:
			return "Conflict";
		case 500:
			return "Internal Server Error";
		default:
			return "Unknown Error Code";
	}
}