/*
 * \brief  Init component
 * \author Norman Feske
 * \date   2010-04-27
 */

/*
 * Copyright (C) 2010-2017 Genode Labs GmbH
 *
 * This file is part of the Genode OS framework, which is distributed
 * under the terms of the GNU Affero General Public License version 3.
 */

/* Genode includes */
#include <base/component.h>
#include <base/attached_rom_dataspace.h>
#include <sandbox/sandbox.h>
#include <os/reporter.h>

namespace Init {

	using namespace Genode;

	struct Main;
}


struct Init::Main : Sandbox::State_handler
{
	Env &_env;

	Sandbox _sandbox { _env, *this };

	Attached_rom_dataspace _config { _env, "config" };

	void _handle_resource_avail() { }

	Signal_handler<Main> _resource_avail_handler {
		_env.ep(), *this, &Main::_handle_resource_avail };

	Constructible<Reporter> _reporter { };

	size_t _report_buffer_size = 0;

	void _handle_config()
	{
		_config.update();

		Node const config = _config.node();

		bool reporter_enabled = false;
		config.with_optional_sub_node("report", [&] (Node const &report) {

			reporter_enabled = true;

			/* (re-)construct reporter whenever the buffer size is changed */
			Number_of_bytes const buffer_size =
				report.attribute_value("buffer", Number_of_bytes(4096));

			if (buffer_size != _report_buffer_size || !_reporter.constructed()) {
				_report_buffer_size = buffer_size;
				_reporter.construct(_env, "state", "state", _report_buffer_size);
			}
		});

		if (_reporter.constructed())
			_reporter->enabled(reporter_enabled);

		_sandbox.apply_config(config);
	}

	Signal_handler<Main> _config_handler {
		_env.ep(), *this, &Main::_handle_config };

	/**
	 * Sandbox::State_handler interface
	 */
	void handle_sandbox_state() override
	{
		Reporter::Result const result =
			_reporter->generate([&] (Generator &g) {
				_sandbox.generate_state_report(g); });

		if (result == Buffer_error::EXCEEDED) {

			error("state report exceeds maximum size");

			/* try to reflect the error condition as state report */
			(void)_reporter->generate([&] (Generator &g) {
				g.attribute("error", "report buffer exceeded"); });
		}
	}

	Main(Env &env) : _env(env)
	{
		_config.sigh(_config_handler);

		/* restart children raising a heartbeat alarm */
		_sandbox.heartbeat_alarm_sigh(_config_handler);

		/* prevent init to block for resource upgrades (never satisfied by core) */
		_env.parent().resource_avail_sigh(_resource_avail_handler);

		_handle_config();
	}
};


void Component::construct(Genode::Env &env) { static Init::Main main(env); }

