#!/usr/local/bin/perl -w
use strict;

our $VERSION = '0.5.0'; # VERSION

$0 = "wubot-monitor";

use AnyEvent::Watchdog autorestart => 1, heartbeat => 300;

$| = 1;

use AnyEvent;
use AnyEvent::Watchdog::Util;
use Date::Manip;
use File::Path;
use FindBin;
use Getopt::Long;
use Log::Log4perl qw(:easy);
use YAML::XS;

use lib "$FindBin::Bin/../lib";

use App::Wubot::Logger;
my $logger = Log::Log4perl::get_logger( 'default' );

use App::Wubot::Check;
use App::Wubot::Config;
use App::Wubot::LocalMessageStore;
use App::Wubot::Util::TimeLength;
use App::Wubot::Wubotrc;
use App::Wubot::WubotX;

my $wubotrc = App::Wubot::Wubotrc->new();

# load plugin library paths
my $wubotx = App::Wubot::WubotX->new();
$wubotx->get_plugins();

our $plugin_objs;
my $schedule;

my $config  = App::Wubot::Config->new();

my $reactor = App::Wubot::Reactor->new();

my $timelength = App::Wubot::Util::TimeLength->new();

use App::Wubot::Scheduler;
my $scheduler = App::Wubot::Scheduler->new();

# all the plugins share a message store object rather than letting
# each create their own
my $message_store = App::Wubot::LocalMessageStore->new();

my $end = AnyEvent->condvar;

my $now = time;

my $checks;
my $check_sub = sub {
    my $plugin = shift;

    $checks++;

    my $plugin_config = $config->get_plugin_config( $plugin );

    my $results = $plugin_objs->{$plugin}->check( $plugin_config );

    my $delay = $plugin_config->{delay} || 60;
    if ( ref $results eq "HASH" && $results->{delay} ) {
        unless ( $delay == $results->{delay} ) {
            $logger->debug( "Check $plugin rescheduled itself in $results->{delay} seconds" );
            $scheduler->reschedule( $plugin,
                                    $results->{delay},
                                );
        }
    }

    # if ( $ENV{LIMIT} ) {
    #     print "CHECKS: $checks\n";
    #     if ( $checks > $ENV{LIMIT} ) {
    #         $end->recv;
    #         exit;
    #     }
    # }
};

my $count;
PLUGIN:
for my $plugin ( $config->get_plugins() ) {
    if ( create_plugin_instance( $plugin, $check_sub ) ) {
        $count++;
    }
}

if ( $count ) {
    $logger->info( "Initialized $count enabled plugin instances" );
}
else {
    my $config_directory = $wubotrc->get_config( 'config_home' );
    $logger->logdie( "ERROR: no plugin config files processed in $config_directory" );
}

# restarts daily slightly after midnigh
my $restart = UnixDate( ParseDate( "tomorrow 00:00:01" ), '%s' ) - UnixDate( ParseDate( "now" ), '%s' );
my $restart_duration = $timelength->get_human_readable( $restart );
$logger->error( "Scheduling daily restart in $restart_duration" );
$scheduler->schedule( 'restart',
                      sub { $logger->warn( "Restarting now..." );
                            AnyEvent::Watchdog::Util::restart;
                        },
                      $restart
                  );


$logger->error( "Running..." );
$end->recv;
$logger->error( "Ended..." );




#############################################################################
sub create_plugin_instance {
    my ( $plugin, $cb ) = @_;

    $logger->debug( "Creating check instance for plugin: $plugin" );

    my $plugin_config = $config->get_plugin_config( $plugin );

    if ( exists $plugin_config->{enabled} ) {
        unless ( $plugin_config->{enabled} ) {
            $logger->warn( "Plugin disabled: $plugin" );
            return;
        }
    }

    $plugin_objs->{ $plugin }
        = App::Wubot::Check->new( { class         => $plugin_config->{plugin},
                                    key           => $plugin,
                                    wubotrc       => $wubotrc,
                                    reactor_queue => $message_store,
                                    wubot_reactor => $reactor,
                                } );

    $plugin_objs->{ $plugin }->init( $plugin_config );

    my $delay      = $plugin_config->{delay} || 1;

    if ( $delay =~ m|[a-zA-Z]| ) {
        $delay = $timelength->get_seconds( $delay );
        $plugin_config->{delay} = $delay;
    }

    my $cache = $plugin_objs->{ $plugin }->instance->get_cache;

    my $lastupdate = 0;
    if ( $cache && $cache->{lastupdate} ) {
        $lastupdate = $plugin_objs->{ $plugin }->instance->get_cache->{lastupdate};
    }

    my $schedule_time;
    if ( ! $lastupdate && $plugin_config->{rand} ) {
        $schedule_time = $now + int rand( $plugin_config->{rand} );
    }
    elsif ( $lastupdate + $delay > $now ) {
        $schedule_time = $lastupdate + $delay + int rand( $plugin_config->{rand} || 0 );
    }
    else {
        $schedule_time = $now;
    }

    my $diff = $schedule_time - $now;
    $logger->debug( "Scheduling next run of $plugin in $diff seconds" );

    $scheduler->schedule( $plugin,
                          $cb,
                          $diff,
                          $plugin_config->{delay},
                      );

    return 1;
}

__END__

=head1 NAME

 wubot-monitor - start the wubot monitoring process

=head1 VERSION

version 0.5.0

=head1 SYNOPSIS

  wubot-monitor
  wubot-monitor -v

=head1 DESCRIPTION

Start up the wubot monitoring process.
