package GLPI::Agent::Event;

use strict;
use warnings;

use English qw(-no_match_vars);

sub new {
    my ($class, %params) = @_;

    my $self = {};

    # Initialize from content generated by dump_for_message if required
    %params = %{$params{from_message}} if $params{from_message};

    # Check for supported events
    # 1. init:
    #  - init event are triggered when the service starts
    #  - can't be triggered via http request
    # 2. runnow:
    #  - can be trigerred by /now http requests from agent HTTP UI or GLPI
    #  - must be evaluated before partial inventory as it can use "partial" param
    #  - can be used to trigger one or more tasks via task or tasks param
    #  - can be delayed using delay param to provide a delay value in seconds
    #  - inventory task can be forced to full by setting full param to "1" or "yes"
    # 3. taskrun:
    #  - can be trigerred by /now http requests or following a runnow event
    #  - must be evaluated before partial inventory as it can use "partial" param
    #  - task is mandatory and can only be used to trigger a planned task
    #  - can be delayed using delay param to provide a delay value in seconds
    #  - for inventory task:
    #    - full or partial params can be to "1" or "yes"
    #    - full default is 1 and has precedence other partial if the 2 are defined
    # 4. partial inventory:
    #  - can be trigerred by /now http requests
    #  - can be requested by glpi-inventory run via --partial parameter
    # 5. maintenance: internal event to trigger maintenance needs
    #  - for deploy, it cleans up storage from file parts when too old
    #  - can't be triggered via http request
    # 6. job:
    #  - job events are created by toolbox managed inventory tasks
    #  - can't be triggered via http request
    if ($params{init} && $params{init} =~ /^yes|1$/i) {
        # Partial inventory request on given categories
        $self = {
            _init    => 1,
            _task    => $params{task} // '',
            _name    => "init",
            _rundate => $params{rundate} // 0,
            _httpd   => 0,
        };
    } elsif ($params{runnow} && $params{runnow} =~ /^yes|1$/i) {
        # Run now request
        $self = {
            _runnow  => 1,
            _name    => "run now",
            _task    => $params{task} || $params{tasks} || 'all',
            _delay   => $params{delay} // 0,
            _httpd   => 1,
        };
        # Store any other params
        foreach my $key (grep { $_ !~ /^runnow|tasks?|delay$/ } keys(%params)) {
            $self->{_params}->{$key} = $params{$key} // "";
        }
    } elsif ($params{taskrun} && $params{taskrun} =~ /^yes|1$/i) {
        # Run task request eventually following a runnow event
        $self = {
            _taskrun => 1,
            _name    => "run",
            _task    => $params{task} // '',
            _delay   => $params{delay} // 0,
            _httpd   => 1,
            _params  => {
                # Support parameter to reset target next rundate on task run
                reschedule => $params{reschedule} // 0,
            }
        };
        # Store any other supported params
        if ($params{task} && $params{task} eq "inventory") {
            if (defined($params{full})) {
                $self->{_params}->{full} = $params{full} =~ /^yes|1$/i ? 1 : 0;
            } elsif (defined($params{partial})) {
                $self->{_params}->{full} = $params{partial} =~ /^yes|1$/i ? 0 : 1;
            } else {
                # Always default to full when full and partial are not set
                $self->{_params}->{full} = 1;
            }
        }
    } elsif ($params{partial} && $params{partial} =~ /^yes|1$/i) {
        # Partial inventory request on given categories
        $self = {
            _partial  => 1,
            _task     => "inventory",
            _name     => "partial inventory",
            _category => $params{category} // '',
            _httpd    => 1,
        };
        # Store any other params (can be used by database partial inventory requests)
        foreach my $key (grep { $_ ne 'partial' } keys(%params)) {
            $self->{_params}->{$key} = $params{$key} // "";
        }
    } elsif ($params{maintenance} && $params{maintenance} =~ /^yes|1$/i) {
        # Maintenance event on given task
        $self = {
            _maintenance => 1,
            _task        => $params{task} // '',
            _name        => $params{name} // "maintenance",
            _delay       => $params{delay} // 0,
            _httpd       => 0,
        };
    } elsif ($params{name} && $params{job} && $params{job} =~ /^yes|1$/i) {
        $self = {
            _job     => 1,
            _name    => $params{name},
            _rundate => $params{rundate} // 0,
            _task    => $params{task} // 'unknown',
            _httpd   => 0,
        };
    }

    $self->{_target} = $params{target} if defined($params{target});

    bless $self, $class;

    return $self;
}

# Mandatory, event is invalid if not present
sub name {
    my ($self) = @_;
    return $self->{_name} // '';
}

# Event types

sub init {
    my ($self) = @_;
    return $self->{_init} // 0;
}

sub partial {
    my ($self) = @_;
    return $self->{_partial} // 0;
}

sub maintenance {
    my ($self) = @_;
    return $self->{_maintenance} // 0;
}

sub job {
    my ($self) = @_;
    return $self->{_job} // 0;
}

sub runnow {
    my ($self) = @_;
    return $self->{_runnow} // 0;
}

sub taskrun {
    my ($self) = @_;
    return $self->{_taskrun} // 0;
}

# Event attributes

sub task {
    my ($self) = @_;
    return $self->{_task} // '';
}

sub category {
    my ($self) = @_;
    return $self->{_category} // '';
}

sub target {
    my ($self) = @_;
    return $self->{_target} // '';
}

sub params {
    my ($self) = @_;
    return $self->{_params} // {};
}

sub get {
    my ($self, $key) = @_;
    return unless $key && ref($self->{_params}) eq "HASH";
    return $self->{_params}->{$key};
}

sub delay {
    my ($self) = @_;
    return $self->{_delay} // 0;
}

sub rundate {
    my ($self, $rundate) = @_;

    $self->{_rundate} = $rundate if $rundate;

    return $self->{_rundate} // 0;
}

sub httpd_support {
    my ($self) = @_;
    return $self->{_httpd} // 0;
}

sub dump_as_string {
    my ($self) = @_;
    my $dump = $self->dump_for_message();
    return join("&", map { $_."=".(ref($dump->{$_}) || $dump->{$_}) } grep { ! ref($dump->{$_}) } keys(%{$dump}));
}

sub dump_for_message {
    my ($self) = @_;
    my $dump = {};
    foreach my $key (keys(%{$self})) {
        my ($name) = $key =~ /^_?(.*)$/;
        $dump->{$name} = $self->{$key} // "";
    }
    return $dump;
}

1;
