
#include <classes/Exec/Signals.h>

#include <pragma/exec_lib.h>

SignalC::SignalC(LONG signalNum)
	: ShareC()
{
	sigNum = AllocSignal(signalNum);
	if (sigNum == -1)
		throw SignalX(signalNum);
}

SignalC::~SignalC()
{
	if (only())
		if (sigNum != -1)
			FreeSignal(sigNum);
}

SignalC &SignalC::operator = (const SignalC &s)
{
	if (this != &s)
	{
		if (only())
			if (sigNum != -1)
				FreeSignal(sigNum);
		ShareC::operator=(s);
		sigNum = s.sigNum;
	};
	return *this;
}

// ****************************************************************

SignalHandlerC::SignalHandlerC(LONG signalNum)
	: NodeC()
{
	if (signalNum == -1)
		mask = 0
	else
		mask = 1L << signalNum;
}

SignalHandlerC::SignalHandlerC(SignalC &signal)
	: NodeC()
{
	mask = 1L << signal.number();
}

SignalHandlerC::SignalHandlerC(const SignalHandlerC &s)
{
	mask = s.mask;
}

SignalHandlerC::~SignalHandlerC()
{
}

SignalHandlerC &SignalHandlerC::operator = (const SignalHandlerC &s)
{
	if (this != &s)
	{
		mask = s.mask;
	}
	return *this;
}

// *****************************************************************

SignalsC::SignalsC()
	: ListC()
{
	mask = 0;
}

SignalsC::~SignalsC()
{
}

VOID SignalsC::add(SignalHandlerC &handler)
{
	addTail(handler);
}

ULONG SignalsC::wait()
{
	buildMask();
	// Wenn keine Signale erwartet werden, wird nicht gewartet, logisch.
	// Wenn die Maske == ~0 ist, wird auch nicht gewartet. Da einige Signale
	// dem Benutzer nicht zur Verfügung stehen, also auch nicht in der Maske
	// auftauchen können, steht damit eine Art "Notausgang" vor dem Wait()
	// zur Verfügung. Dieses Feature ist jedoch nicht dokumentiert und im
	// wesentlichen für so abstruses Signalhandling wie von MUI gedacht, wo
	// die eigentliche Arbeit in der signals() Methode des SignalHandlerCs
	// steckt (und damit auch der Abbruch der Wait() Schleife).
	if ((mask) && (mask != ~0))
		return Wait(mask);
	return 0;
}

BOOL SignalsC::handle(ULONG signals)
{
	ListCursorC lc(*this);
	BOOL r = FALSE;
	BOOL b;
	while (!lc.isDone()) {
		if (((SignalHandlerC *) lc.item())->forMe(signals))
		{
			b = ((SignalHandlerC *) lc.item())->handle(signals);
			r = r || b;
		};
		lc.next();
	};
	return r;
}

VOID SignalsC::loop()
{
	ULONG signals;
	for (;;) {
		signals = wait();
		if (handle(signals))
			return;
	};
}

VOID SignalsC::buildMask()
{
	ListCursorC lc(*this);
	while (!lc.isDone()) {
		mask |= ((SignalHandlerC *) lc.item())->signals();
		lc.next();
	};
}
