/*
 * Gets statistics from lowlevel backend and writes it to "backend" section
 */
static void fill_backend_backend(rapidjson::Value &stat_value,
                                 rapidjson::Document::AllocatorType &allocator,
                                 const struct dnet_backend_io *backend,
                                 const dnet_backend_info *config_backend) {
	char *json_stat = NULL;
	size_t size = 0;
	struct dnet_backend_callbacks *cb = backend->cb;
	if (cb->storage_stat_json) {
		cb->storage_stat_json(cb->command_private, &json_stat, &size);
		if (json_stat && size) {
			rapidjson::Document backend_value(&allocator);
			backend_value.Parse<0>(json_stat);
			auto &config_value = backend_value["config"];
			config_value.AddMember("group", config_backend->group, allocator);
			config_value.AddMember("queue_timeout", config_backend->queue_timeout, allocator);

			rapidjson::Document initial_config(&allocator);
			initial_config.Parse<0>(config_backend->initial_config.c_str());
			backend_value.AddMember("initial_config",
			                        static_cast<rapidjson::Value&>(initial_config),
			                        allocator);

			stat_value.AddMember("backend",
			                     static_cast<rapidjson::Value&>(backend_value),
			                     allocator);
		}
	}

	free(json_stat);
}
/*
 * Fills config with common backend info like config, group id
 */
static void fill_disabled_backend_config(rapidjson::Value &stat_value,
                                         rapidjson::Document::AllocatorType &allocator,
					 const dnet_backend_info &config_backend) {
	rapidjson::Value backend_value(rapidjson::kObjectType);
	rapidjson::Value config_value(rapidjson::kObjectType);

	for (auto it = config_backend.options.begin(); it != config_backend.options.end(); ++it) {
		const dnet_backend_config_entry &entry = *it;

		rapidjson::Value tmp_val(entry.value_template.data(), allocator);
		config_value.AddMember(entry.entry->key, tmp_val, allocator);
	}

	backend_value.AddMember("config", config_value, allocator);
	stat_value.AddMember("backend", backend_value, allocator);
}
/*
 * This function is called to fill in config values read from the config for non-enabled (yet) backends.
 *
 * If config template provides API for serializing parsed config values to json
 * it fills 'backend::config' section otherwise it uses unparsed values from original config
 * and fills 'backend::config_template'.
 *
 * After backend has been enabled, @fill_backend_backend() is called instead.
 */
static void fill_disabled_backend_config(rapidjson::Value &stat_value,
                                         rapidjson::Document::AllocatorType &allocator,
                                         const dnet_backend_info *config_backend) {
	rapidjson::Value backend_value(rapidjson::kObjectType);

	/* If config template provides API for serializing parsed config values to json - use it */
	if (config_backend->config_template.to_json) {
		char *json_stat = NULL;
		size_t size = 0;

		dnet_config_backend config = config_backend->config_template;
		std::vector<char> data(config.size, '\0');
		config.data = data.data();
		config.log = config_backend->log.get();

		for (auto it = config_backend->options.begin(); it != config_backend->options.end(); ++it) {
			const dnet_backend_config_entry &entry = *it;
			entry.entry->callback(&config, entry.entry->key, entry.value_template.data());
		}

		config.to_json(&config, &json_stat, &size);
		if (json_stat && size) {
			rapidjson::Document config_value(&allocator);
			config_value.Parse<0>(json_stat);
			config_value.AddMember("group", config_backend->group, allocator);
			backend_value.AddMember("config",
			                        static_cast<rapidjson::Value&>(config_value),
			                        allocator);
		}
		free(json_stat);
		config.cleanup(&config);
	} else {
		rapidjson::Value config_value(rapidjson::kObjectType);
		for (auto it = config_backend->options.begin(); it != config_backend->options.end(); ++it) {
			const dnet_backend_config_entry &entry = *it;

			rapidjson::Value tmp_val(entry.value_template.data(), allocator);
			config_value.AddMember(entry.entry->key, tmp_val, allocator);
		}
		config_value.AddMember("group", config_backend->group, allocator);
		backend_value.AddMember("config_template", config_value, allocator);
	}

	stat_value.AddMember("backend", backend_value, allocator);
}
/*
 * Gets statistics from lowlevel backend and writes it to "backend" section
 */
static void fill_backend_backend(rapidjson::Value &stat_value,
                                 rapidjson::Document::AllocatorType &allocator,
                                 const struct dnet_backend_io &backend) {
	char *json_stat = NULL;
	size_t size = 0;
	struct dnet_backend_callbacks *cb = backend.cb;
	if (cb->storage_stat_json) {
		cb->storage_stat_json(cb->command_private, &json_stat, &size);
		if (json_stat && size) {
			rapidjson::Document backend_value(&allocator);
			backend_value.Parse<0>(json_stat);
			stat_value.AddMember("backend",
			                     static_cast<rapidjson::Value&>(backend_value),
			                     allocator);
		}
	}

	free(json_stat);
}