// -*- c++ -*-
//------------------------------------------------------------------------------
//                            Handlers.h
//------------------------------------------------------------------------------
//  Copyright (c) 2000 by Vladislav Grinchenko
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Library General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//------------------------------------------------------------------------

#ifndef _Handlers_h
#define _Handlers_h

#include <sys/types.h>
#include <sys/wait.h>

#include "assa/EventHandler.h"
#include "assa/Assert.h"

namespace ASSA {

/** @file Handlers.h

    A collection of various most popular signal handlers.
 */

/**
   SIGINTHandler handles SIGINT signal.
*/

class SIGINTHandler : public EventHandler
{
public:
	/// constructor
	SIGINTHandler();

	/** Receive SIGINT signal
	    @return 0 if valid signum_ was used, -1 otherwise.
	*/
	int handle_signal (int signum_);

	/** Indicates whether graceful quit signal has been raised by
	    the signal handler.
	    @return 0 if not, 1 othewise.
	*/
	sig_atomic_t graceful_quit();

	///  Reset state of the object to initial
	void resetState();

private:
	/// flag that indicates whether signal was caught.
	sig_atomic_t m_graceful_quit;
};
 
inline
SIGINTHandler::
SIGINTHandler ()
	: m_graceful_quit (0)
{
	trace_with_mask("SIGINTHandler::SIGINTHandler", SIGHAND);
}

inline int
SIGINTHandler::
handle_signal (int signum_)
{
	trace_with_mask("SIGINTHandler::handle_signal", SIGHAND);

	if (signum_ == SIGINT) {
		m_graceful_quit = 1;
		return 0;
	}
	return -1;
}

inline sig_atomic_t
SIGINTHandler::
graceful_quit ()
{
	return m_graceful_quit;
}

inline void
SIGINTHandler::
resetState()
{
	trace_with_mask("SIGINTHandler::resetState", SIGHAND);

	m_graceful_quit = 0;
}

/** 
	Class SIGUSR1Handler.
	Handle SIGUSR1 signal.
*/

class SIGUSR1Handler : public EventHandler
{
public:
	/** Constructor 
	 */
	SIGUSR1Handler() : m_count(0) {
		trace_with_mask("SIGUSR1Handler::SIGUSR1Handler", SIGHAND);
	}
    
	/** Catch USR1 signal and increment count.
	 */
	int handle_signal(int signum_) {
		trace_with_mask("SIGUSR1Handler::handle_signal()", SIGHAND);
	    
		if (signum_ == SIGUSR1) { 
			m_count++; 
			DL((TRACE, "signal count = %d\n", m_count));
			return 0; 
		}
		return -1;
	}
    
	/** Report count of received signals.
	 */
	sig_atomic_t received_count() const { return m_count; }
    
	/** Set received signals count back to 0.
	 */
	void resetState() { m_count = 0; }

private:
	/// Received signals count
	sig_atomic_t m_count;
};


/** Class SIGUSR2Handler handles SIGUSR2 signal.
 */
class SIGUSR2Handler : public EventHandler
{
public:
	/** Constructor 
	 */
	SIGUSR2Handler() : m_count(0) {
		trace_with_mask("SIGUSR2Handler::SIGUSR2Handler", SIGHAND);
	}
    
	/** Catch USR2 signal and increment count.
	 */
	int handle_signal(int signum_) {
		trace_with_mask("SIGUSR2Handler::handle_signal()", SIGHAND);
	    
		if (signum_ == SIGUSR2) { 
			m_count++; 
			DL((TRACE, "signal count = %d\n", m_count));
			return 0; 
		}
		return -1;
	}
    
	/** Report count of received signals.
	 */
	sig_atomic_t received_count() const { return m_count; }
    
	/** Set received signals count back to 0.
	 */
	void resetState() { m_count = 0; }

private:
	/// Received signals count
	sig_atomic_t m_count;
};

/** Class SIGCHLDHandler handles SIGCHLD signal.
 */
class SIGCHLDHandler : public EventHandler
{
public:
	/// Constructor
	SIGCHLDHandler() : m_child_exit_flag(0) {
		trace_with_mask("SIGCHLDHandler::SIGCHLDHandler", SIGHAND);
	}

	/** Receive CHLD signal
	 */
	int handle_signal(int signum_) {
		trace_with_mask("SIGCHLDHandler::handle_signal", SIGHAND);

		if (signum_ == SIGCHLD && wait(NULL) != -1) { 
			m_child_exit_flag = 1;
			return 0;
		}
		return -1;
	}
	/** Did child exit?
	 */
	sig_atomic_t child_exited() { return m_child_exit_flag; }

	/** Reset child's exit state
	 */
	void resetState() { m_child_exit_flag = 0; }

private:
	/// Child exit's state
	sig_atomic_t m_child_exit_flag;
};

/** Class SIGALRMHandler handles SIGALRM signal.
 */
class SIGALRMHandler : public EventHandler
{
public:
	/// Constructor
	SIGALRMHandler() : m_alarm_flag(0) {
		trace_with_mask("SIGALRMHandler::SIGALRMHandler", SIGHAND);
	}

	/** Receive ALRM signal
	 */
	int handle_signal(int signum_) {
		trace_with_mask("SIGALRMHandler::handle_signal", SIGHAND);

		if (signum_ == SIGALRM) {
			m_alarm_flag = 1; // notice that we have seen alarm
			return 0;
		}
		return -1;
	}

	/// Has alarm gone off?
	sig_atomic_t alarmed () { return m_alarm_flag; }

	/// Reset internal state
	void resetState () { m_alarm_flag = 0; }

private:
	/// Indicator whether alarm gone off yet.
	sig_atomic_t m_alarm_flag;
};


/** Class SIGPOLLHandler handles SIGPOLL signal.

SIGPOLLHandler Implementations of dummy handler to *swallow* SIGPOLL caused
sometimes by select(3) being called on false socket file descriptor.
*/
class SIGPOLLHandler : public EventHandler
{
public:
	/** Constructor
	 */
	SIGPOLLHandler () {
		trace_with_mask("SIGPOLLHandler", SIGHAND);
	}
	/** Catch and absorb SIGPOLL signal.
	 */
	int handle_signal ( int signum_ ) { 
		trace_with_mask("SIGPOLLHandler::handle_signal", SIGHAND);
			
		return (signum_ == SIGIO) ? 0 : -1; 
	}
};

} // end namespace ASSA

#endif
