
#include "sys/sys"
#include "config/config"
#include "balancer/balancer"
#include "error/error"
#include "profiler/profiler"
#include "ThreadsAndMutexes/mutex/mutex"
#include "ThreadsAndMutexes/mutextable/mutextable"

using namespace std;

// Global variables (definition)
Config config;
Balancer balancer;
MutexTable mt(100);
Mutex cout_lock, cerr_lock;

static void showlimits() {
    typedef struct {
	int resource;
	string description;
    } Limit;
    static Limit limit[] = {
	{ RLIMIT_CORE, 		"coredump size (bytes)" },
	{ RLIMIT_CPU,		"cpu time (sec)" },
	{ RLIMIT_DATA,		"data segment size (bytes)" },
	{ RLIMIT_FSIZE,		"max file size (bytes)" },
#	ifdef RLIMIT_MEMLOCK	
	{ RLIMIT_MEMLOCK,	"locked mem size (bytes)" },
#	endif	
	{ RLIMIT_NOFILE,	"max open files" },
#	ifdef RLIMIT_NPROC	
	{ RLIMIT_NPROC,		"max processes" },
#	endif
#	ifdef RLIMIT_RSS	
	{ RLIMIT_RSS,		"max resident set size (bytes)" },
#	endif
	{ RLIMIT_STACK,		"max stack size (bytes)" }
    };
    
    for (unsigned i = 0; i < sizeof(limit) / sizeof(Limit); i++) {
	struct rlimit rl;
	if (getrlimit(limit[i].resource, &rl))
	    throw Error(string("Failed to request limit: ") +
			strerror(errno));
	ostringstream o;
	o << "Limits for " << limit[i].description
	  << ": hard limit " << unsigned(rl.rlim_max)
	  << ", soft limit " << unsigned(rl.rlim_cur) << '\n';
	msg(o.str());
    }
}

static int org_argc;
static char **org_argv;
static void sigcatcher (int sig) {
    debugmsg("Seen signal " << sig << '\n');
    switch (sig) {
	
    case SIGHUP:
	// Generate a report to the log.
	balancer.report(true);
	break;
	
    case SIGUSR1:
	// Toggle verbosity.
	if (config.verbose())
	    config.verbose(false);
	else
	    config.verbose(true);
	break;
    case SIGUSR2:
	
	// Toggle debugging.
	if (config.debug())
	    config.debug(false);
	else
	    config.debug(true);
	break;
	
    case SIGINT:
    case SIGQUIT:
    case SIGABRT:
    case SIGTERM:
    case SIGSTOP:
	// Stop the balancer
	balancer.terminate(true);
	break;
	
    default:
	// Ignore
	ostringstream o;
	o << "Signal " << sig << " ignored\n";
	msg(o.str());
	break;
    }
}

int main (int argc, char **argv) {

    PROFILE("main");
    
    static int relevant_sig[] = {
	SIGHUP,						// Back end states to log
	SIGINT, SIGQUIT, SIGABRT, SIGTERM, SIGSTOP,	// Terminate
	SIGUSR1, SIGUSR2,				// Toggle verbose/debug
	SIGPIPE,					// Ignore
    };
    
    try {
	// Save original commandline
	org_argc = argc;
	org_argv = argv;
	
	// Load configuration from the commandline, promote verbosity
	config.parsecmdline (argc, argv);

	if (config.verbose())
	    showlimits();
	
	msg("XR running as PID " << getpid() << '\n');
	
	// Load the signal handler.
	for (unsigned i = 0; i < sizeof(relevant_sig) / sizeof(int); i++)
	    signal (relevant_sig[i], sigcatcher);
	
	// Configure the balancer and start serving.
	balancer.init();
	balancer.serve();
    } catch (Error const &e) {
	cerr << e.what() << endl;
	return (1);
    } catch (...) {
	cerr << "ERROR: Unidentified exception caught" << endl;
    }
    
    return (0);
}
