// -*- c++ -*-
//------------------------------------------------------------------------------
//                            SigHandler.h
//------------------------------------------------------------------------------
//  Copyright (c) 1997 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 _SigHandler_h
#define _SigHandler_h

// System includes

#include <signal.h>
#include <errno.h>

#include "assa/Logger.h"
#include "assa/IdSet.h"
#include "assa/SigSet.h"
#include "assa/SigAction.h"
#include "assa/EventHandler.h"

namespace ASSA {

/** @file SigHandler.h 

   Class SigHandler is a  UNIX signal handlers manager/dispatcher class.
   It plays a role of centralized signal dispatcher for the 
   running application. It is based on Callback pattern that
   overcomes two major difficulties of using UNIX signals in C++ programs:

      - lack of encapsulation 
	  - limited functionality in the signal handler 

   SigHandler class allows to install one EventHandler object in order to
   manage application's reaction for UNIX signals. When this registered
   signal is delivered by OS to the running application, handle_signal()
   method of the installed EventHandler will be called for service.

   If conventional C-like signal handler has been installed prior to
   calling sh.install(), it will be lost irreversibly.
*/

class SigHandler
{
public:
	/** Add new signal handler and new disposition for the signal.
	    Note that although new_disp_ might keep C-like
	    handler for the action, new_hand_ will really be
	    handling delivered signal. In other words,
	    new_disp_.sa_handler is ignored.

	    @param signum_ signal number new disposition is installed for.
	    @param new_hand_ pointer to new EventHandler that will be
	    handling the signal
	    @param new_disp_ new disposition to use in handling the signal
	    @param old_hand_ return old handler for the signal
	    @param old_disp_ return old disposition for the signal

	    @return 0 on success, -1 on error
	*/
	virtual int install (int            signum_,
			     EventHandler*  new_hand_,
			     SigAction*     new_disp_ = 0,
			     EventHandler** old_hand_ = 0,
			     SigAction*     old_disp_ = 0);

	/** Remove EventHandler associated with signum_. Also,
	    install new disposition and return an old one (if given).

	    @param signum_ signal number new disposition is installed for.
	    @param eh_ pointer to EventHandler that is uninstalled.
	    If eh_ is 0 (by default), all event handlers associated with
	    signum_ will be removed.
	    @param new_disp_ new disposition to use in handling the signal
	    @param old_disp_ return old disposition for the signal

	    @return 0 on success, -1 on error
	*/
	virtual int remove (int signum_,
			    EventHandler* eh_       = 0,
			    SigAction*    new_disp_ = 0,
			    SigAction*    old_disp_ = 0);

	/** Here is the heart of SigHandler class. This callback function
	    is really registered with OS to catch all of the signals 
	    EventHandlers have been installed for. dispatch ()
	    catches the signal and then calls sends the signal to
	    the appropriate EventHandler object.

	    @param signum_ signal delivered by OS.
	    @return 0 on success, -1 on error
	*/
	static void dispatch (int signum_);
    
	/** Set new event handler for signal signum_ and return
	    an existing one.

	    @return Pointer to the old event handler, or 0 if signum_
	    is out of range.
	*/
	EventHandler* handler (int signum_, EventHandler* new_);

	/** Retrieve current event handler for signum_.
	 */
	EventHandler* handler (int signum_);
    
protected:
	/** Check that signum_ is in valid range.
	    @return 0 if in range; -1 otherwise.
	*/
	int in_range(int signum_);
    
private:
	/** Static array that stores one user-defined event handler pointer
	    for every signal.
	*/
	static EventHandler* m_signal_handlers [NSIG];
};

} // end namespace ASSA

#endif /* _SigHandler_h */
