#define _GNU_SOURCE
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include "xsignal.h"
#include "xassert.h"
#include "xatexit.h"
#include "timer.h"
#include "opts.h"
#include "port.h"

extern const char * const sys_siglist[];
extern int cur_state;

int flag_term = 0;

void hnd_alrm (int signo);
void hnd_term (int signo);
void hnd_hangup (int signo);
void hnd_usr1 (int signo);
void hnd_usr2 (int signo);

struct sig_t {
	int signo;
	void (*handler) (int);
} signals[] = {
	{SIGALRM, hnd_alrm},
	{SIGTERM, hnd_term},
	{SIGINT, hnd_term},
	{SIGHUP, hnd_hangup},
	{SIGUSR1, hnd_usr1},
	{SIGUSR2, hnd_usr2},
	{0, NULL}
};

void hnd_alrm (int signo)
{
	timer_handler();
}

void hnd_term (int signo)
{
	flag_term = signo;
}

void hnd_hangup (int signo)
{
}

void hnd_usr1 (int signo)
{
	if (cur_state == STATE_MANUAL) {
		timer_init();
		cur_state = STATE_AUTO;
	}
}

void hnd_usr2 (int signo)
{
	if (cur_state == STATE_AUTO) {
		timer_cleanup();
		port_set (0);
		cur_state = STATE_MANUAL;
	} else
		port_set ((port_get() + 1) & 7);
}

void hnd_generic (int signo)
{
	struct sig_t *sig = signals;

	while (sig) {
		if (sig->signo == signo) {
			sig->handler (signo);
			break;
		}

		sig++;
	}

	signal (signo, hnd_generic);
}

void xsignal_cleanup (void)
{
	struct sig_t *sig = signals;

	while (sig->signo)
		signal ((sig++)->signo, SIG_DFL);
}

void xsignal_init (void)
{
	struct sig_t *sig = signals;

	while (sig->signo) {
		xassert (signal(sig->signo, hnd_generic) != SIG_ERR, 
			"Przechwytywanie sygnału %s: %m.", strsignal(sig->signo));
		sig++;
	}

	xatexit (xsignal_cleanup);
}
