//=============================================================================
//
// file :               DServerSignal.h
//
// description :        Include for the DServer class. This class implements
//                      all the commands which are available for device
//            of the DServer class. There is one device of the
//            DServer class for each device server process
//
// project :            TANGO
//
// author(s) :          A.Gotz + E.Taurel
//
// Copyright (C) :      2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015
//                        European Synchrotron Radiation Facility
//                      BP 220, Grenoble 38043
//                      FRANCE
//
// This file is part of Tango.
//
// Tango is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Tango is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Tango.  If not, see <http://www.gnu.org/licenses/>.
//
//
//=============================================================================

#ifndef _DSERVERSIGNAL_H
#define _DSERVERSIGNAL_H

#include <tango/tango.h>
#include <signal.h>

namespace Tango
{

//=============================================================================
//
//            The DServerSignal class
//
// description :    Class to implement all data members and commands for
//            signal management in a TANGO device server.
//
//=============================================================================

#if(defined(_TG_WINDOWS_) || (defined __APPLE__) || (defined __freebsd__))
  #define _NSIG NSIG
#endif

typedef struct
{
    std::vector<DeviceClass *> registered_classes;
    std::vector<DeviceImpl *> registered_devices;
    bool own_handler;
} DevSigAction;

class DServerSignal : public TangoMonitor
{
  public:
    static DServerSignal *instance();
    static void cleanup_singleton();

    ~DServerSignal();

#ifndef _TG_WINDOWS_
    void register_class_signal(long, bool, DeviceClass *);
    void register_dev_signal(long, bool, DeviceImpl *);

    void register_handler(long, bool);
    pid_t get_sig_thread_pid();
#else
    void register_class_signal(long, DeviceClass *);
    void register_dev_signal(long, DeviceImpl *);

    void register_handler(long);
#endif

    void unregister_class_signal(long, DeviceClass *);
    void unregister_class_signal(DeviceClass *);
    void unregister_dev_signal(long, DeviceImpl *);
    void unregister_dev_signal(DeviceImpl *);

    void unregister_handler(long);

    static void main_sig_handler(int);

    class ThSig : public omni_thread
    {
        DServerSignal *ds;

      public:
        ThSig(DServerSignal *d) :
            ds(d),
            my_pid(0)

        {
        }

        ~ThSig() override { }

        TangoSys_Pid my_pid;
        bool th_data_created{false};
#ifndef _TG_WINDOWS_
        pthread_t my_thread;
#endif
        void *run_undetached(void *) override;

        void start()
        {
            start_undetached();
        }
    };
    friend class ThSig;
    ThSig *sig_th;

  protected:
    DServerSignal();
    static DevSigAction reg_sig[_NSIG];

    bool sig_to_install;
    bool sig_to_remove;
    bool sig_th_should_stop = false;
    int inst_sig;
    int rem_sig;
#ifdef _TG_WINDOWS_
    static HANDLE win_ev;
    static int win_signo;
#endif

  private:
    static std::unique_ptr<DServerSignal> _instance;
    std::vector<DeviceImpl *>::iterator find_device(long, DeviceImpl *);
    std::vector<DeviceImpl *>::iterator find_delayed_device(long, DeviceImpl *);

    std::vector<DeviceClass *>::iterator find_class(long, DeviceClass *);
    std::vector<DeviceClass *>::iterator find_delayed_class(long, DeviceClass *);

#ifdef _TG_WINDOWS_
    static inline bool auto_signal(long s)
    {
        if((s == SIGINT) || (s == SIGTERM) || (s == SIGABRT) || (s == SIGBREAK))
        {
            return true;
        }
        else
        {
            return false;
        }
    }
#else
    static bool auto_signal(long s)
    {
        return (s == SIGQUIT) || (s == SIGINT) || (s == SIGHUP) || (s == SIGTERM);
    }
#endif

    static std::string sig_name[_NSIG];
};

} // End of namespace Tango

#endif
