#!/usr/bin/env perl

# Use mandatory external modules
use strict;
use Cwd;
use File::Basename;
use Data::Dumper;
use POSIX;
use Config;
use Getopt::Long;
use threads;
use threads::shared;
use Thread::Queue;
#use Thread::Semaphore;
use IO::Socket;
use Proc::Daemon;
use Time::HiRes;
use DBI;

# Check perl for threads support
$Config{useithreads} or die "Recompile Perl with threads to run this program.";

# Determine installation dir name
our $SELF_DIR = dirname(dirname(Cwd::abs_path(__FILE__)));

# Include semaphores bug fix
require $SELF_DIR . '/lib/semaphore.pm';

# Include parts of the system
require $SELF_DIR . '/lib/version.pm';
require $SELF_DIR . '/lib/config.pm';
require $SELF_DIR . '/lib/log.pm';
require $SELF_DIR . '/lib/checkers.pm';
require $SELF_DIR . '/lib/mon_commands.pm';
require $SELF_DIR . '/lib/daemon.pm';
require $SELF_DIR . '/lib/commands.pm';

#-----------------------------------------------------------------
# Say hello
PrintVersion();

#-----------------------------------------------------------------
# Read config file
my $postfix = "";
our $cluster_name : shared = "";
if (scalar(@ARGV) && $ARGV[0] =~ /^@(.*)/) {
    shift(@ARGV);
    $postfix = "_$1";
    $cluster_name = $1;
}

my $cfg_file = "mmm_mon$postfix.conf";
print "Reading config file: '$cfg_file'\n";
our $config : shared = ReadConfig($cfg_file);

# Status changing semaphore
our $status_sem = new Thread::Semaphore;

# We need to know how previous session has been finished
our $unclean_start : shared = CheckPidFile();

# Roles list
our $roles : shared = CreateRolesList();

# Catch SIGCHLD
$SIG{CHLD} = \&REAPER;

# Checks status data
our $checks_status : shared = CreateChecksStatus();

# Servers status data
our $servers_status : shared = CreateServersStatus();

# Failover method
our $failover_method : shared = CreateFailoverMethod();

#print Dumper($servers_status);

# Go to background
Proc::Daemon::Init if ($config->{debug} =~ /^(off|no|0)$/i);
CreatePidFile();

# Shutdown flag
our $shutdown : shared = 0;

# Start time to calculate uptime
our $start_time : shared = time();

# Catch signals
$SIG{INT} = \&SignalHandler;
$SIG{TERM} = \&SignalHandler;
$SIG{PIPE} = 'IGNORE';

# XXX ugly, try to collect all childs before spawning threads
# see: http://rt.perl.org/rt3/Public/Bug/Display.html?id=60724
sleep(3);

#-----------------------------------------------------------------
# Creating message queues
my $status_queue = new Thread::Queue();
my $command_queue = new Thread::Queue();

# ???
sleep(1);

# Creating command worker
my $command_thread = new threads(\&CommandMain, $command_queue, $status_queue);

# Creating status monitoring thread
my $checker_threads = StartCheckerThreads($command_queue, $status_queue);

# Creating main thread
DaemonMain($command_queue, $status_queue);

# Waiting for threads shutdown
$command_thread->join();
ShutdownCheckerThreads($checker_threads);

# Delete pid file and update status file
unlink($config->{pid_path});
UpdateStatusFile();

exit(0);

#-----------------------------------------------------------------
sub SignalHandler() {
    LogDebug("Core: Signal received: exiting...");
    $shutdown = 1;
}

sub REAPER {
    local $!;   # don't let waitpid() overwrite current error
    while ((my $pid = waitpid(-1, WNOHANG)) > 0 && WIFEXITED($?)) {
        LogDebug("Core: reaped child $pid" . ($? ? " with exit $?" : ''));
    }
    $SIG{CHLD} = \&REAPER;  # loathe sysV
}

