#include <SignalManager.hpp>

#include <BacktraceManager.hpp>
#include <ConsoleManager.hpp>

#include <csignal>
#include <rang.hpp>

std::string SignalManager::s_pause_on_error = "auto";
void SignalManager::setPauseForDebug(const std::string& pause_on_error)
{
  s_pause_on_error = pause_on_error;
}

std::string SignalManager::signalName(const int& signal)
{
  switch (signal) {
  case SIGILL:  return "SIGILL";
  case SIGFPE:  return "SIGFPE";
  case SIGABRT: return "SIGABRT";
  case SIGINT:  return "SIGINT";
  case SIGSEGV: return "SIGSEGV";
  case SIGTERM: return "SIGTERM";
  }
  return "SIGNAL undefined!";
}

void SignalManager::pauseForDebug(const int& signal)
{

  std::cout  << "\n======================================\n";
  std::cout << rang::style::reset
	    << rang::fg::reset
	    << rang::style::bold;
  std::cout << "to attach gdb to this process run\n";
  std::cout << "\tgdb -pid "
	    << rang::fg::red
	    << getpid()
	    << rang::fg::reset
	    << '\n';
  std::cout << "else press Control-C to exit\n";
  std::cout << rang::style::reset;
  std::cout  << "======================================\n";
  std::cout << std::flush;

  ::sigset_t sig; 
  ::sigaddset(&sig,SIGSTOP); 
  ::sigsuspend(&sig); 

  std::exit(signal);
}

void SignalManager::handler(int signal)
{
  std::signal(SIGFPE,  SIG_DFL);
  std::signal(SIGSEGV, SIG_IGN);
  std::signal(SIGTERM, SIG_DFL);
  std::signal(SIGINT,  SIG_DFL);
  std::signal(SIGABRT, SIG_DFL);

  std::cerr << "\n *** "
	    << rang::style::reset
	    << rang::fg::reset
	    << rang::style::bold;
  std::cerr << "Signal "
    	    << rang::fgB::yellow
	    << signalName(signal)
    	    << rang::fg::reset
	    << " caught"
	    << rang::style::reset
	    << " ***\n";

  BacktraceManager bm;
  std::cerr << bm << '\n';

  if ((ConsoleManager::isTerminal(std::cout) and
       (s_pause_on_error == "auto")) or
      (s_pause_on_error == "yes")) {
    SignalManager::pauseForDebug(signal);
  } else {
    std::exit(signal);
  }
 }

void SignalManager::init(const bool& enable)
{

  if (enable) {
    std::signal(SIGFPE,  SignalManager::handler);
    std::signal(SIGSEGV, SignalManager::handler);
    std::signal(SIGTERM, SignalManager::handler);
    std::signal(SIGINT,  SignalManager::handler);
    std::signal(SIGABRT, SignalManager::handler);
    std::signal(SIGPIPE, SignalManager::handler);

    std::cout << "Signal management: "
	      << rang::style::bold
	      << rang::fgB::green
	      << "enabled"
	      << rang::fg::reset
	      << rang::style::reset << '\n';
  } else {
    std::cout << "Signal management: "
	      << rang::style::bold
	      << rang::fgB::red
	      << "disabled"
	      << rang::fg::reset
	      << rang::style::reset << '\n';
  }
}