package LATMOS::Accounts::Task::Unusedhosts;

use strict;
use warnings;
use base qw(LATMOS::Accounts::Task);
use LATMOS::Accounts;
use LATMOS::Accounts::Log;
use LATMOS::Accounts::Utils;
use DateTime;

=head1 NAME

LATMOS::Accounts::Task::Unusedhosts - Disable host owned by inactive users

=head1 DESCRIPTION

This module disable nethost when owned by an expired or disabled user account, removing it from network

=head1 PARAMETER

=head2 netzone

The C<netzone> object containing concerned hosts

=head2 filter

A filter limiting host search.

=head2 disableMode

The rules to disable hosts:

=over 4

=item C<owner>: C<owner> is set and is inactive

=item C<user>: C<user> is set and is inactive

=item C<both>: C<owner> or C<user> (if set) is inactive

=item C<effective> (default): If C<user> is set and is inactive otherwise if
C<owner> is inactive

=back

=head2 test

If set only log are emitted but changes are not done and mail not really sent

=cut

# Wait 30 minutes
sub waitDelay { 30 * 60 }

sub init {
    my ($self) = @_;
    my $LA = LATMOS::Accounts->new($self->{config}, noacl => 1);
    my $labase = $self->{base} ? $LA->base($self->{base}) : $LA->base;
    $labase && $labase->load or die "Cannot load base";

    $self->{_la} = $LA;
    $self->{_base} = $labase;

    1;
}

sub run {
    my ($self) = @_;

    $self->_enable;

    $self->_disable;

    1;
}

sub _filters {
    my ($self) = @_;

    my $filteredHosts;

    if (my @cfilters = $self->{syncm}->ini->val($self->{name}, 'filter')) {
        $filteredHosts = {};
        foreach ($self->{_base}->search_objects('nethost', @cfilters)) {
            $filteredHosts->{$_} = 1;
        }
    }

    my $hosts;

    if (my @zones = $self->{syncm}->ini->val($self->{name}, 'netzone')) {

        $hosts = {};

        my @filters;

        foreach my $zone (@zones) {
            la_log(LA_DEBUG, "Limiting affected host to zone %s", $zone);
            my $oZone = $self->{_base}->get_object('netzone', $zone) or do {
                la_log(LA_ERR, "Cannot get zone $zone named in config");
                return;
            };

            my @zonehosts = $oZone->get_attributes('hosts');

            push(@filters, [ 'name=' . join('||', @zonehosts) ]);

            if ($oZone->get_attributes('allow_dyn')) {
                la_log(LA_DEBUG, "Zone %s has allow_dyn set, searching w/o ip", $zone);
                push(@filters, [ 'ip=NULL' ]);
            }
        }

        foreach my $filter (@filters) {
            foreach ($self->{_base}->search_objects('nethost', @$filter)) {
                $filteredHosts && !$filteredHosts->{$_} and next;
                $hosts->{$_} = 1;
            }
        }
    } else {
        $hosts = $filteredHosts;
    }

    return $hosts;
}

sub _disable {
    my ($self) = @_;

    my $test = $self->{syncm}->ini->val($self->{name}, 'test');
    my $mode = $self->{syncm}->ini->val($self->{name}, 'disableMode', 'effective');

    la_log(LA_DEBUG, "Checking for host to disable using %s method", $mode);

    my $hosts = $self->_filters;

    my @HostToDisable;
    for ($mode) {
        /owner/i and do {
            my @HostNoOwner = $self->{_base}->search_objects('nethost', 'exported=1', 'owner.active=0');
            foreach (@HostNoOwner) {
                push(@HostToDisable, $_);
            }
            last;
        };
        /user/i and do {
            my @HostNoUser = $self->{_base}->search_objects('nethost', 'exported=1', 'user.active=0');
            foreach (@HostNoUser) {
                push(@HostToDisable, $_);
            }
            last;
        };
        /both/i and do {
            my %HostNoUser  = map { $_ => } (
                $self->{_base}->search_objects('nethost', 'exported=1', 'user.active=0'),
                $self->{_base}->search_objects('nethost', 'exported=1', 'owner.active=0'),
            );
            foreach (keys %HostNoUser) {
                push(@HostToDisable, $_);
            }
            last;
        };
        /effective/i and do {
            my %HostNoUser  = map { $_ => } (
                $self->{_base}->search_objects('nethost', 'exported=1', 'user.active=0'),
                $self->{_base}->search_objects('nethost', 'exported=1', 'user=NULL', 'owner.active=0'),
            );
            foreach (keys %HostNoUser) {
                push(@HostToDisable, $_);
            }
            last;
        };

        la_log(LA_ERR, "Unknown host check method `%s'", $mode);
    }

    foreach my $hostname (sort @HostToDisable) {
        if ($hosts) {
            $hosts->{$hostname} or next;
        }
        my $Host = $self->{_base}->get_object('nethost', $hostname) or next;
        $self->{_base}->log(
            LA_NOTICE,
            '%sHost %s disable because owner or user is inactive',
            ($test ? '(Test) ' : ''),
            $hostname,
        );
        $Host->ReportChange('Update', "Disabling because user/owner is inactive");
        $Host->_set_c_fields( unexported => 1 );
    }

    $self->{_base}->commit()
        unless($test);
}

sub _enable {
    my ($self) = @_;

    my $test = $self->{syncm}->ini->val($self->{name}, 'test');
    my $mode = $self->{syncm}->ini->val($self->{name}, 'disableMode', 'effective');

    la_log(LA_DEBUG, "Checking for host to disable using %s method", $mode);

    my $hosts = $self->_filters;

    my @HostToEnable;
    for ($mode) {
        /owner/i and do {
            my @HostNoOwner = $self->{_base}->search_objects('nethost', 'exported=0', 'owner.active=1');
            foreach (@HostNoOwner) {
                push(@HostToEnable, $_);
            }
            last;
        };
        /user/i and do {
            my @HostNoUser = $self->{_base}->search_objects('nethost', 'exported=0', 'user.active=1');
            foreach (@HostNoUser) {
                push(@HostToEnable, $_);
            }
            last;
        };
        /both/i and do {
            my %HostNoUser  = map { $_ => } (
                $self->{_base}->search_objects('nethost', 'exported=0', 'user.active=1', 'owner.active=1'),
                $self->{_base}->search_objects('nethost', 'exported=0', 'user=NULL', 'owner.active=1'),
            );
            foreach (keys %HostNoUser) {
                push(@HostToEnable, $_);
            }
            last;
        };
        /effective/i and do {
            my %HostNoUser  = map { $_ => } (
                $self->{_base}->search_objects('nethost', 'exported=0', 'user.active=1'),
                $self->{_base}->search_objects('nethost', 'exported=0', 'user=NULL', 'owner.active=1'),
            );
            foreach (keys %HostNoUser) {
                push(@HostToEnable, $_);
            }
            last;
        };

        la_log(LA_ERR, "Unknown host check method `%s'", $mode);
    }

    foreach my $hostname (sort @HostToEnable) {
        if ($hosts) {
            $hosts->{$hostname} or next;
        }
        my $Host = $self->{_base}->get_object('nethost', $hostname) or next;
        $self->{_base}->log(
            LA_INFO,
            '%sHost %s enable because owner or user is active',
            ($test ? '(Test) ' : ''),
            $hostname,
        );
        $Host->ReportChange('Update', "Enabling because user/owner is active");
        $Host->_set_c_fields( unexported => 0 );
    }

    $self->{_base}->commit()
        unless($test);
}

1;

__END__

=head1 SEE ALSO

L<LATMOS::Accounts>, L<LATMOS::Accounts::Task>

=head1 AUTHOR

Olivier Thauvin, E<lt>olivier.thauvin@latmos.ipsl.frE<gt>

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2012 CNRS SA/CETP/LATMOS

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.10.0 or,
at your option, any later version of Perl 5 you may have available.

=cut

