#!/usr/bin/perl

package Cog; # persistant Gearman Worker - see the pun?

use Moose;
use JSON::XS qw();
extends 'Gearman::Driver::Worker::Base';

use lib 'lib';
with 'APKPM::Gearman';
with 'APKPM::Gearman::Client';

sub prefix { '' }

package main;

use Gearman::Driver;
use Data::Dump qw(dump);

use Regexp::Common qw(net);
use Redis;

use lib 'lib';
use H1::ZTEDSLAM;

my $driver = Gearman::Driver->new(
	server   => 'localhost:4730',
	interval => 60,
	loglevel   => 'DEBUG',
	logfile    => 'log/persistant.log',
) || die $!;

my $w1 = 'Cog';
my $worker = $w1->new();


my $crm = $worker->do( 'CRM_search' => "TIP_UREDJAJA:ZTEDSLAM" );


my $poll;

foreach my $user ( @$crm ) {
	next unless $user->{IP_UREDAJA} =~ /$RE{net}{IPv4}/;
	$poll->{ $user->{IP_UREDAJA} }->{ $user->{SHELF_SLOT_PORT} }++;
}

warn "# poll = ", dump($poll);

foreach my $ip ( keys %$poll ) {

	my $method = "ZTEDSLAM_$ip";

	my $zte = H1::ZTEDSLAM->new( ip => $ip );

	$driver->add_job({
		max_processes => 1, # FIXME increase?
		min_processes => 1,
		name		=> $method,
		worker		=> $worker,
		methods	   => [
			{
				decode => 'd_json',
#				encode => 'e_json',
				name   => $method,
				body   => sub {

		my ( $self, $job, $crm ) = @_;

		if ( exists $crm->{logout} ) {
			$zte->logout;
			return;
		}

		my $hash;
		eval { $hash = $zte->hash( $crm->{SHELF_SLOT_PORT} ) };

		my $redis = Redis->new;

		if ( $@ ) {
			$redis->sadd("ZTEDSLAM.error" => $@);
			return { error => $@ };
		} else {
			$redis->sadd("ZTEDSLAM.ok" => $crm->{USERNAME});
		}

		$self->do_background_json( 'Store_insert', {
			_table => 'dslam_h',
			ip => $crm->{IP_MANAGEMENT}, # FIXME IP_UREDAJA ?
			username => $crm->{USERNAME},
			timestamp => $self->datetime_now,
			h => $self->to_hstore($hash),
		});

#		return $hash; # body end

				},
			},
		]
	});

	warn "$method added\n";

}

$driver->add_job({
	max_processes => 1,
	min_processes => 1,
	worker		=> $worker,
	name		=> 'poll_ZTEDSLAM',
	methods	   => [ {
		name		=> 'poll_ZTEDSLAM',
		body   => sub {

		my ( $self, $job, $workload ) = @_;

		my $crm = $self->do( 'CRM_search' => "TIP_UREDJAJA:ZTEDSLAM" );

		warn "# crm $crm";

		my $gc = Gearman::Client->new;
		$gc->job_servers( $self->server || 'localhost:4730' );
		my $taskset = $gc->new_task_set;
		my $seen;

		my $redis = Redis->new;
		$redis->del( $_ ) foreach $redis->keys("ZTEDSLAM.*");

		foreach my $user ( @$crm ) {
			my $ip   = $user->{IP_UREDAJA};
			my $port = $user->{SHELF_SLOT_PORT};

			if ( $ip !~ /$RE{net}{IPv4}/ ) {
				$redis->sadd("ZTEDSLAM.invalid.IP_UREDAJA" => $ip);
				next;
			} elsif ( $port !~ m{\d+(/\d+)+} ) {
				$redis->sadd("ZTEDSLAM.invalid.PORT" => $port);
				next;
			}
			$redis->sadd("ZTEDSLAM.queued" => "$ip $port");

			my $name = 'ZTEDSLAM_' . $ip;
			$taskset->add_task( $name, $self->e_json( $user ), {
				on_complete => sub { $redis->sadd("ZTEDSLAM.complete", "$ip $port") },
				on_fail     => sub { $redis->sadd("ZTEDSLAM.fail", "$ip $port") },
			} )
			if ! $seen->{ $ip }->{ $port }++;
		}

		warn "# queue logouts";
		foreach my $ip ( keys %$seen ) {
			$taskset->add_task( "ZTEDSLAM_$ip", $self->e_json( { logout => 1 } ) );
		}

		warn "# wait";
		$taskset->wait;

		warn "# seen ", dump($seen);

		return; # body end
		}
	} ],
});

$driver->run;

