/*
 * Fills all sections of one backend
 */
static rapidjson::Value& backend_stats_json(uint64_t categories,
                                            rapidjson::Value &stat_value,
                                            rapidjson::Document::AllocatorType &allocator,
                                            struct dnet_node *node,
                                            size_t backend_id) {
	dnet_backend_status status;
	memset(&status, 0, sizeof(status));

	const auto &config_backend = node->config_data->backends->backends[backend_id];

	stat_value.AddMember("backend_id", backend_id, allocator);
	fill_backend_status(stat_value, allocator, node, status, backend_id);

	if (status.state == DNET_BACKEND_ENABLED && node->io) {
		const struct dnet_backend_io & backend = node->io->backends[backend_id];

		if (categories & DNET_MONITOR_COMMANDS) {
			const command_stats *stats = (command_stats *)(backend.command_stats);
			rapidjson::Value commands_value(rapidjson::kObjectType);
			stat_value.AddMember("commands", stats->commands_report(NULL, commands_value, allocator), allocator);
		}

		if (categories & DNET_MONITOR_BACKEND) {
			fill_backend_backend(stat_value, allocator, backend);
		}
		if (categories & DNET_MONITOR_IO) {
			fill_backend_io(stat_value, allocator, backend);
		}
		if (categories & DNET_MONITOR_CACHE) {
			fill_backend_cache(stat_value, allocator, backend);
		}
	} else if (categories & DNET_MONITOR_BACKEND) {
		fill_disabled_backend_config(stat_value, allocator, config_backend);
	}

	if (categories & DNET_MONITOR_BACKEND) {
		stat_value["backend"]["config"].AddMember("group", config_backend.group, allocator);
	}

	return stat_value;
}
/*
 * Fills all sections of one backend
 */
static rapidjson::Value& backend_stats_json(uint64_t categories,
                                            rapidjson::Value &stat_value,
                                            rapidjson::Document::AllocatorType &allocator,
                                            struct dnet_node *node,
                                            const dnet_backend_info *config_backend) {
	dnet_backend_status status;
	memset(&status, 0, sizeof(status));

	auto backend_id = config_backend->backend_id;
	stat_value.AddMember("backend_id", backend_id, allocator);
	fill_backend_status(stat_value, allocator, node, status, config_backend);

	struct dnet_backend_io *backend_io = nullptr;
	if (status.state == DNET_BACKEND_ENABLED && node->io) {
		backend_io = dnet_get_backend_io(node->io, backend_id);
	}

	if (backend_io) {
		if (categories & DNET_MONITOR_COMMANDS) {
			const command_stats *stats = (command_stats *)(backend_io->command_stats);
			rapidjson::Value commands_value(rapidjson::kObjectType);
			stat_value.AddMember("commands", stats->commands_report(NULL, commands_value, allocator), allocator);
		}

		if (categories & DNET_MONITOR_BACKEND) {
			fill_backend_backend(stat_value, allocator, backend_io, config_backend);
		}
		if (categories & DNET_MONITOR_IO) {
			fill_backend_io(stat_value, allocator, backend_io);
		}
		if (categories & DNET_MONITOR_CACHE) {
			fill_backend_cache(stat_value, allocator, backend_io);
		}
	} else if (categories & DNET_MONITOR_BACKEND) {
		fill_disabled_backend_config(stat_value, allocator, config_backend);
	}

	return stat_value;
}
/*
 * Fills all sections of one backend
 */
static rapidjson::Value& backend_stats_json(uint64_t categories,
                                            rapidjson::Value &stat_value,
                                            rapidjson::Document::AllocatorType &allocator,
                                            struct dnet_node *node,
                                            size_t backend_id) {
	dnet_backend_status status;
	memset(&status, 0, sizeof(status));

	const auto &config_backend = node->config_data->backends->backends[backend_id];
	std::lock_guard<std::mutex> guard(*config_backend.state_mutex);

	stat_value.AddMember("backend_id", backend_id, allocator);
	fill_backend_status(stat_value, allocator, node, status, backend_id);

	if (status.state == DNET_BACKEND_ENABLED && node->io) {
		const struct dnet_backend_io & backend = node->io->backends[backend_id];

		if (categories & DNET_MONITOR_BACKEND) {
			fill_backend_backend(stat_value, allocator, backend);
		}
		if (categories & DNET_MONITOR_IO) {
			fill_backend_io(stat_value, allocator, backend);
		}
		if (categories & DNET_MONITOR_CACHE) {
			fill_backend_cache(stat_value, allocator, backend);
		}
	} else if (categories & DNET_MONITOR_BACKEND) {
		fill_disabled_backend_config(stat_value, allocator, config_backend);
	}

	if (categories & DNET_MONITOR_BACKEND) {
		stat_value["backend"]["config"].AddMember("group", config_backend.group, allocator);
	}

	return stat_value;
}