#!/usr/bin/perl

use strict;
use warnings;
use Getopt::Long;
use Pod::Usage;
use Config::IniFiles;
use LATMOS::Accounts;
use LATMOS::Accounts::SyncManager;
use LATMOS::Accounts::Log;
use LATMOS::Accounts::Task;

GetOptions(
    'nodaemon' => \my $nodaemon,
    'c|config=s'   => \my $config,
    'help'         => sub { pod2usage(0) },
    'test'         => \my $test,
    'wait=i'       => \my $wait,
    'r|run=s'      => \my $run,
) or pod2usage();

my $needsync = 2;
my $pidfile = undef;
$wait ||= 5; # default in minutes

my $syncm = LATMOS::Accounts::SyncManager->new($config) or do {
    la_log LA_ERR, "Cannot instanciate Sync Manager";
    exit(1);
};

if ($run) {
    my $res = $syncm->process_module($run);
    exit($res ? 0 : 1);
}

la_set_log(
    syslog => [],
    console => ($nodaemon ? LA_NOTICE : undef),
);


{
    my $LA = LATMOS::Accounts->new($config, noacl => 1);
    if ($LA->val('_default_', 'state_dir')) {
        $pidfile = $LA->val('_default_', 'state_dir') . '/sync-manager.pid';
    }
    if (my $mail = $LA->val('_network_', 'maillog')) {
            la_set_log(mail => $mail);
    }
}

# Daemonize
if (!$nodaemon) {
    my $pid = fork;
    if ($pid) {
        exit 0;
    }
}

if ($pidfile) {
    # maybe we want to lock here !!
    open(my $fh, '>', $pidfile) or die "Cannot open pidfile $pidfile\n";
    print $fh "$$\n";
    close($fh);
}

$SIG{INT} = sub {
    unlink($pidfile) if ($pidfile);
    exit 0;
};

$SIG{'HUP'} = sub {
    $needsync = 1;
    la_log LA_NOTICE, "SigHup received, synchronise now";
};

sub process {
    my ($module, $baserev) = @_;
    my $pid = fork;
    if ($pid == 0) {
        $SIG{INT} = 'DEFAULT';
        my $res = $syncm->process_module($module, $baserev);
        exit($res ? 0 : 1);
    }
    my $retpid;
    while(($retpid = waitpid(-1, 0)) <= 0) {}
    local $SIG{HUP} = 'IGNORE';
    if ($retpid) {
        my $res = $? >> 8;
        if ($res) {
            la_log LA_ERR, "Sync process exit with $res";
            return;
        }
    }
    return 1;
}

my $lasttout;
my %revs;
while (1) {
    if ($needsync) {
        my $levelsync = $needsync;
        $needsync = 0;
        {
            local $SIG{HUP} = 'IGNORE';
            $syncm->updrev;
            # listing module to run in this loop
            $lasttout = scalar(time) if ($levelsync == 2);
        }
        foreach my $module ($syncm->list_modules()) {
            next if ($syncm->ini->val($module, 'lazy') && $levelsync < 2);
            my $res = process($module, $revs{$module} || 0);
            if ($res) {
                $revs{$module} = $syncm->dbrev;
            }
        }
    }

    # waiting, to perform next sync
    sleep(15) unless($needsync);
    # if it is not time yet:
    next if($lasttout + ($wait * 60) > scalar(time));
    $needsync = 2;
}

