#
# Copyright 2024 Centreon (http://www.centreon.com/)
#
# Centreon is a full-fledged industry-strength solution that meets
# the needs in IT infrastructure and application monitoring for
# service performance.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

package storage::emc::symmetrix::vmax::local::mode::hardware;

use base qw(centreon::plugins::templates::hardware);

use strict;
use warnings;
use centreon::plugins::misc;
use centreon::plugins::statefile;

sub set_system {
    my ($self, %options) = @_;
    
    $self->{regexp_threshold_numeric_check_section_option} = '^(sparedisk)$';
    
    $self->{cb_hook1} = 'read_files';
    $self->{cb_hook4} = 'send_email';
    
    $self->{thresholds} = {
        default => [
            ['Recoverable Error', 'OK'], # Fabric
            ['Online', 'OK'],
            ['Up', 'OK'],
            ['OK', 'OK'],
            ['.*', 'CRITICAL'],
        ],
    };
    
    $self->{components_path} = 'storage::emc::symmetrix::vmax::local::mode::components';
    $self->{components_module} = ['module', 'temperature', 'director', 'cabling', 'power', 'fabric', 'voltage', 'sparedisk'];
}

sub find_files {
    my ($self, %options) = @_;

    if (!opendir(DIR, $self->{option_results}->{health_directory})) {
        $self->{output}->add_option_msg(short_msg => "Cannot open directory: $!");
        $self->{output}->option_exit();
    }
    
    my $save_value = 0;
    while (my $file = readdir(DIR)) {
        next if (! -d $self->{option_results}->{health_directory} . '/' . $file || 
            $file !~ /$self->{option_results}->{health_directory_pattern}/);
        if (hex($1) > $save_value) {
            $self->{option_results}->{file_health} = $self->{option_results}->{health_directory} . '/' . $file . '/' . $self->{option_results}->{file_health_name};
            $self->{option_results}->{file_health_env} = $self->{option_results}->{health_directory} . '/' . $file . '/' . $self->{option_results}->{file_health_env_name};
            $save_value = hex($1);
        }
    }

    closedir(DIR);
}

sub check_options {
    my ($self, %options) = @_;
    $self->SUPER::check_options(%options);
    
    $self->{statefile_cache}->check_options(%options);
   
   if (!defined($self->{option_results}->{file_health_name}) || !defined($self->{option_results}->{file_health_env_name})) {
        $self->{output}->add_option_msg(short_msg => "Please set option --file-health-name and --file-health-env-name.");
        $self->{output}->option_exit();
    }
    if (!defined($self->{option_results}->{health_directory}) || ! -d $self->{option_results}->{health_directory}) {
        $self->{output}->add_option_msg(short_msg => "Please set right option for --health-directory.");
        $self->{output}->option_exit();
    }
    if (!defined($self->{option_results}->{health_directory_pattern})) {
        $self->{output}->add_option_msg(short_msg => "Please set option for --health-directory-pattern.");
        $self->{output}->option_exit();
    }
    
    $self->find_files();
}

sub new {
    my ($class, %options) = @_;
    my $self = $class->SUPER::new(package => __PACKAGE__, %options, no_absent => 1);
    bless $self, $class;
    
    $options{options}->add_options(arguments => {
        'health-directory:s'         => { name => 'health_directory' },
        'health-directory-pattern:s' => { name => 'health_directory_pattern' },
        'file-health-name:s'         => { name => 'file_health_name', default => 'HealthCheck.log' },
        'file-health-env-name:s'     => { name => 'file_health_env_name', default => 'sympl_env_health.log' },
        # Email
        'email-warning:s'       => { name => 'email_warning' },
        'email-critical:s'      => { name => 'email_critical' },
        'email-smtp-host:s'     => { name => 'email_smtp_host' },
        'email-smtp-username:s' => { name => 'email_smtp_username' },
        'email-smtp-password:s' => { name => 'email_smtp_password' },
        'email-smtp-from:s'     => { name => 'email_smtp_from' },
        'email-smtp-options:s@' => { name => 'email_smtp_options' },
        'email-memory'          => { name => 'email_memory' },
    });

    $self->{statefile_cache} = centreon::plugins::statefile->new(%options);
    $self->{components_exec_load} = 0;
    return $self;
}

sub read_files {
    my ($self, %options) = @_;
    
    foreach (('file_health', 'file_health_env')) {
        $self->{'content_' . $_} = do {
            local $/ = undef;
            if (!open my $fh, "<", $self->{option_results}->{$_}) {
                $self->{output}->add_option_msg(short_msg => "Could not open file $self->{option_results}->{$_} : $!");
                $self->{output}->option_exit();
            }
            <$fh>;
        };
        # We remove color syntax
        $self->{'content_' . $_} =~ s/\x{1b}\[.*?m|\r//msg;
    }
    
    #Health Check Results Log:
    #Service Processor Date: 06/15/2016 09:26:41
    #Symmetrix Date from director 07c: 06/15/2016 09:33:45
    #The time difference between Service Processor and Symmetrix is : 00:07:03.672
    #System SN: 000292602920
    #System Model: VMAX20K
    #mCode Level: 5876.288
    my ($serial) = ('unknown');
    $serial = $1 if ($self->{content_file_health} =~ /System SN:\s*(\S+)/msi);

    $self->{output}->output_add(long_msg => sprintf('serial number: %s', $serial));
}

#
# maybe we should add it in core (with cleaner code ;)
#

sub send_email {
    my ($self, %options) = @_;
    
    #######
    # Check SMTP options
    return if (!((defined($self->{option_results}->{email_warning}) && $self->{option_results}->{email_warning} ne '')
        || (defined($self->{option_results}->{email_critical}) && $self->{option_results}->{email_critical} ne '')));
    
    if (!defined($self->{option_results}->{email_smtp_host})) {
        $self->{output}->add_option_msg(short_msg => "Please set the --email-smtp-host option");
        $self->{output}->option_exit();
    }
    if (!defined($self->{option_results}->{email_smtp_from})) {
        $self->{output}->add_option_msg(short_msg => "Please set --email-smtp-from option");
        $self->{output}->option_exit();
    }
    
    my %smtp_options = ('-auth' => 'none');
    if (defined($self->{option_results}->{email_smtp_username}) && $self->{option_results}->{email_smtp_username} ne '') {
        $smtp_options{-login} = $self->{option_results}->{email_smtp_username};
        delete $smtp_options{-auth};
    }
    if (defined($self->{option_results}->{email_smtp_username}) && defined($self->{option_results}->{email_smtp_password})) {
        $smtp_options{-pass} = $self->{option_results}->{email_smtp_password};
    }    
    
    #######
    # Get current data
    my $stdout;
    {
        local *STDOUT;
        open STDOUT, '>', \$stdout;
        $self->{output}->display(force_long_output => 1);
    }
    
    $stdout =~ /^(.*?)(\||\n)/msi;
    my $subject = $1;
    my $status = lc($self->{output}->get_litteral_status());
    
    foreach my $option (@{$self->{option_results}->{email_smtp_options}}) {
        next if ($option !~ /^(.+?)=(.+)$/);
        my ($label, $value) = ($1, $2);
        if ($label =~ /subject/i) {
            $value =~ s/%\{status\}/$status/g;
            $value =~ s/%\{short_msg\}/$subject/g;
            $label = lc($label);
        }
        $smtp_options{-$label} = $value;
    }
    
    my $send_email = 0;
    $send_email = 1 if ($status ne 'ok');
    #######
    # Check memory file
    if (defined($self->{option_results}->{email_memory})) {
        $self->{new_datas} = { status => $status, output => $subject };
        $self->{statefile_cache}->read(statefile => "cache_emc_symmetrix_vmax_email");
        my $prev_status = $self->{statefile_cache}->get(name => 'status');
        my $prev_output = $self->{statefile_cache}->get(name => 'output');
        # non-ok output is the same
        $send_email = 0 if ($status ne 'ok' && defined($prev_output) && $prev_output eq $subject);
        # recovery email
        $send_email = 1 if ($status eq 'ok' && defined($prev_status) && $prev_status ne 'ok');
        $self->{statefile_cache}->write(data => $self->{new_datas});
    }
    
    my $smtp_to = '';
    $smtp_to = $self->{option_results}->{email_warning} if ($status eq 'warning' && defined($self->{option_results}->{email_warning} && $self->{option_results}->{email_warning}) ne '');
    $smtp_to = $self->{option_results}->{email_critical} if ($status eq 'critical' && defined($self->{option_results}->{email_critical} && $self->{option_results}->{email_critical}) ne '');
    if ($send_email == 1 && $status eq 'ok') {
        my $append = '';
        foreach (('email_warning', 'email_critical')) {
            if (defined($self->{option_results}->{$_}) && $self->{option_results}->{$_} ne '') {
                $smtp_to .= $append . $self->{option_results}->{$_};
                $append .= ',';
            }
        }
    }
    
    if ($send_email == 0) {
        $self->{output}->add_option_msg(severity => 'OK', short_msg => "No email to send");
        return ;
    }
    
    centreon::plugins::misc::mymodule_load(
        output => $self->{output},
        module => 'Email::Send::SMTP::Gmail',
        error_msg => "Cannot load module 'Email::Send::SMTP::Gmail'."
    );
    my ($mail, $error) = Email::Send::SMTP::Gmail->new(
        -smtp => $self->{option_results}->{email_smtp_host},
        %smtp_options
    );
    if ($mail == -1) {
        $self->{output}->add_option_msg(short_msg => "session error: " . $error);
        $self->{output}->option_exit();
    }
    my $result = $mail->send(
        -to => $smtp_to,
        -from => $self->{option_results}->{email_smtp_from},
        -subject => defined($smtp_options{-subject}) ? $smtp_options{-subject} : $subject,
        -body => $stdout,
        -attachments => $self->{option_results}->{file_health} . "," . $self->{option_results}->{file_health_env}
    );
    $mail->bye();
    if ($result == -1) {
        $self->{output}->add_option_msg(severity => 'UNKNOWN', short_msg => "problem to send the email");
    } else {
        $self->{output}->add_option_msg(severity => 'OK', short_msg => "email sent");
    }
}

1;

__END__

=head1 MODE

Check hardware.

=over 8

=item B<--component>

Which component to check (default: '.*').
Can be: 'module', 'temperature', 'director, 'cabling', 'power', 'voltage', 'sparedisk'.

=item B<--filter>

Exclude the items given as a comma-separated list (example: --filter=temperature --filter=module).
You can also exclude items from specific instances: --filter=temperature,ES-PWS-A ES-4

=item B<--no-component>

Define the expected status if no components are found (default: critical).

=item B<--threshold-overload>

Use this option to override the status returned by the plugin when the status label matches a regular expression (syntax: section,[instance,]status,regexp).
Example: --threshold-overload='director,WARNING,^(?!(OK)$)'

=item B<--warning>

Set warning threshold for disk (syntax: type,regexp,threshold)
Example: --warning='sparedisk,.*,5:'

=item B<--critical>

Set critical threshold for disk (syntax: type,regexp,threshold)
Example: --critical='sparedisk,.*,3:'

=item B<--health-directory>

Location of health files.

=item B<--health-directory-pattern>

Set pattern to match the most recent directory (getting the hexa value).

=item B<--file-health-name>

Name of the global storage file status (default: HealthCheck.log).

=item B<--file-health-env-name>

Name of the environment storage file status (default: sympl_env_health.log).

=back

=cut
