#
# Copyright 2017 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 centreon::plugins::output;

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

sub new {
    my ($class, %options) = @_;
    my $self  = {};
    bless $self, $class;
    if (!defined($options{options})) {
        print "Class Output: Need to specify 'options' argument to load.\n";
        exit 3;
    }

    $options{options}->add_options(arguments =>
                                {
                                  "explode-perfdata-max:s@" => { name => 'explode_perfdata_max' },
                                  "range-perfdata:s"        => { name => 'range_perfdata' },
                                  "filter-perfdata:s"       => { name => 'filter_perfdata' },
                                  "change-perfdata:s@"      => { name => 'change_perfdata' },
                                  "filter-uom:s"            => { name => 'filter_uom' },
                                  "verbose"                 => { name => 'verbose' },
                                  "debug"                   => { name => 'debug' },
                                  "opt-exit:s"              => { name => 'opt_exit', default => 'unknown' },
                                  "output-xml"              => { name => 'output_xml' },
                                  "output-json"             => { name => 'output_json' },
                                  "output-file:s"           => { name => 'output_file' },
                                  "disco-format"            => { name => 'disco_format' },
                                  "disco-show"              => { name => 'disco_show' },
                                });
    %{$self->{option_results}} = ();

    $self->{option_msg} = [];
    
    $self->{is_output_xml} = 0;
    $self->{is_output_json} = 0;
    $self->{errors} = {OK => 0, WARNING => 1, CRITICAL => 2, UNKNOWN => 3, PENDING => 4};
    $self->{errors_num} = {0 => 'OK', 1 => 'WARNING', 2 => 'CRITICAL', 3 => 'UNKNOWN', 4 => 'PENDING'};
    $self->{myerrors} = {0 => "OK", 1 => "WARNING", 3 => "UNKNOWN", 7 => "CRITICAL"};
    $self->{myerrors_mask} = {CRITICAL => 7, WARNING => 1, UNKNOWN => 3, OK => 0};
    $self->{global_short_concat_outputs} = {OK => undef, WARNING => undef, CRITICAL => undef, UNKNOWN => undef, UNQUALIFIED_YET => undef};
    $self->{global_short_outputs} = {OK => [], WARNING => [], CRITICAL => [], UNKNOWN => [], UNQUALIFIED_YET => []};
    $self->{global_long_output} = [];
    $self->{perfdatas} = [];
    $self->{explode_perfdatas} = {};
    $self->{change_perfdata} = {};
    $self->{explode_perfdata_total} = 0;
    $self->{range_perfdata} = 0;
    $self->{global_status} = 0;
    $self->{encode_utf8_import} = 0;
    $self->{perlqq} = 0;

    $self->{disco_elements} = [];
    $self->{disco_entries} = [];

    $self->{plugin} = '';
    $self->{mode} = '';

    return $self;
}

sub check_options {
    my ($self, %options) = @_;
    # $options{option_results} = ref to options result

    %{$self->{option_results}} = %{$options{option_results}};
    $self->{option_results}->{opt_exit} = lc($self->{option_results}->{opt_exit});
    if (!$self->is_litteral_status(status => $self->{option_results}->{opt_exit})) {
        $self->add_option_msg(short_msg => "Unknown value '" . $self->{option_results}->{opt_exit}  . "' for --opt-exit.");
        $self->option_exit(exit_litteral => 'unknown');
    }
    # Go in XML Mode
    if ($self->is_disco_show() || $self->is_disco_format()) {
        # By Default XML
        if (!defined($self->{option_results}->{output_json})) {
            $self->{option_results}->{output_xml} = 1;
        }
    }
    
    if (defined($self->{option_results}->{range_perfdata})) {
        $self->{range_perfdata} = $self->{option_results}->{range_perfdata};
        $self->{range_perfdata} = 1 if ($self->{range_perfdata} eq '');
        if ($self->{range_perfdata} !~ /^[012]$/) {
            $self->add_option_msg(short_msg => "Wrong range-perfdata option '" . $self->{range_perfdata} . "'");
            $self->option_exit();
        }
    }
    
    if (defined($self->{option_results}->{explode_perfdata_max})) {
        if (${$self->{option_results}->{explode_perfdata_max}}[0] eq '') {
            $self->{explode_perfdata_total} = 2;
        } else {
            $self->{explode_perfdata_total} = 1;
            foreach (@{$self->{option_results}->{explode_perfdata_max}}) {
                my ($perf_match, $perf_result) = split /,/;
                if (!defined($perf_result)) {
                    $self->add_option_msg(short_msg => "Wrong explode-perfdata-max option '" . $_ . "' (syntax: match,value)");
                    $self->option_exit();
                }
                $self->{explode_perfdatas}->{$perf_match} = $perf_result;
            }
        }
    }
    
    if (defined($self->{option_results}->{change_perfdata})) {
        foreach (@{$self->{option_results}->{change_perfdata}}) {
            if (! /^(.+?),(.+)$/) {
                $self->add_option_msg(short_msg => "Wrong change-perfdata option '" . $_ . "' (syntax: match,substitute)");
                $self->option_exit();
            }
            $self->{change_perfdata}->{$1} = $2;
        }
    }
}

sub add_option_msg {
    my ($self, %options) = @_;
    # $options{short_msg} = string msg
    # $options{long_msg} = string msg
    $options{severity} = 'UNQUALIFIED_YET';
    
    $self->output_add(%options);
}

sub set_status {
    my ($self, %options) = @_;
    # $options{exit_litteral} = string litteral exit

    # Nothing to do for 'UNQUALIFIED_YET'
    if (!$self->{myerrors_mask}->{uc($options{exit_litteral})}) {
        return ;
    }
    $self->{global_status} |= $self->{myerrors_mask}->{uc($options{exit_litteral})};
}

sub output_add {
    my ($self, %params) = @_;
    my %args = (
                severity => 'OK',
                separator => ' - ',
                debug => 0,
                short_msg => undef,
                long_msg => undef
                );
    my $options = {%args, %params};
    
    if (defined($options->{short_msg})) {
        chomp $options->{short_msg};
        if (defined($self->{global_short_concat_outputs}->{uc($options->{severity})})) {
            $self->{global_short_concat_outputs}->{uc($options->{severity})} .= $options->{separator} . $options->{short_msg};
        } else {
            $self->{global_short_concat_outputs}->{uc($options->{severity})} = $options->{short_msg};
        }
        
        push @{$self->{global_short_outputs}->{uc($options->{severity})}}, $options->{short_msg};
        $self->set_status(exit_litteral => $options->{severity});
    }
    if (defined($options->{long_msg}) && 
        ($options->{debug} == 0 || defined($self->{option_results}->{debug}))) {
        chomp $options->{long_msg};
        push @{$self->{global_long_output}}, $options->{long_msg};
    }
}

sub perfdata_add {
    my ($self, %options) = @_;
    my $perfdata = {label => '', value => '', unit => '', warning => '', critical => '', min => '', max => ''}; 
    foreach (keys %options) {
        next if (!defined($options{$_}));
        $perfdata->{$_} = $options{$_};
    }
    $perfdata->{label} =~ s/'/''/g;
    push @{$self->{perfdatas}}, $perfdata;
}

sub change_perfdatas {
    my ($self, %options) = @_;
    
    if ($self->{option_results}->{change_perfdata}) {
        foreach (@{$self->{perfdatas}}) {
            foreach my $filter (keys %{$self->{change_perfdata}}) {
                if ($_->{label} =~ /$filter/) {
                    eval "\$_->{label} =~ s{$filter}{$self->{change_perfdata}->{$filter}}";
                    last;
                }
            }
        }
    }
    
    return if ($self->{explode_perfdata_total} == 0);
    foreach (@{$self->{perfdatas}}) {
        next if ($_->{max} eq '');
        if ($self->{explode_perfdata_total} == 2) {
            $self->perfdata_add(label => $_->{label} . '_max', value => $_->{max});
            next;
        }
        foreach my $regexp (keys %{$self->{explode_perfdatas}}) {
            if ($_->{label} =~ /$regexp/) {
                $self->perfdata_add(label => $self->{explode_perfdatas}->{$regexp}, value => $_->{max});
                last;
            }
        }
    }
}

sub range_perfdata {
    my ($self, %options) = @_;
    
    return if ($self->{range_perfdata} == 0);
    if ($self->{range_perfdata} == 1) {
        for (my $i = 0; $i < scalar(@{$options{ranges}}); $i++) {
            ${${$options{ranges}}[$i]} =~ s/^(@?)-?[0\.]+:/$1/;
        }
    } else {
        for (my $i = 0; $i < scalar(@{$options{ranges}}); $i++) {
            ${${$options{ranges}}[$i]} = '';
        }
    }
}

sub output_json {
    my ($self, %options) = @_;
    my $force_ignore_perfdata = (defined($options{force_ignore_perfdata}) && $options{force_ignore_perfdata} == 1) ? 1 : 0;
    my $force_long_output = (defined($options{force_long_output}) && $options{force_long_output} == 1) ? 1 : 0;
    my $json_content = {plugin => {
                                   name => $self->{plugin},
                                   mode => $self->{mode},
                                   exit => $options{exit_litteral},
                                   outputs => [],
                                   perfdatas => []
                                  }
                        };    

    foreach my $code_litteral (keys %{$self->{global_short_outputs}}) {
        foreach (@{$self->{global_short_outputs}->{$code_litteral}}) {
            my ($child_output, $child_type, $child_msg, $child_exit);
            my $lcode_litteral = ($code_litteral eq 'UNQUALIFIED_YET' ? uc($options{exit_litteral}) : $code_litteral);

            push @{$json_content->{plugin}->{outputs}}, {
                                                           type => 1,
                                                           msg => ($options{nolabel} == 0 ? ($lcode_litteral . ': ') : '') . $_,
                                                           exit => $lcode_litteral
                                                        };
        }
    }

    if (defined($self->{option_results}->{verbose}) || $force_long_output == 1) {
        foreach (@{$self->{global_long_output}}) {
            push @{$json_content->{plugin}->{outputs}}, {
                                                           type => 2,
                                                           msg => $_,
                                                        };
        }
    }

    if ($options{force_ignore_perfdata} == 0) {
        $self->change_perfdatas();
        foreach my $perf (@{$self->{perfdatas}}) {
            next if (defined($self->{option_results}->{filter_perfdata}) &&
                     $perf->{label} !~ /$self->{option_results}->{filter_perfdata}/);
            $self->range_perfdata(ranges => [\$perf->{warning}, \$perf->{critical}]);
            
            my %values = ();
            foreach my $key (keys %$perf) {
                $perf->{$key} = '' if (defined($self->{option_results}->{filter_uom}) && $key eq 'unit' &&
                    $perf->{$key} !~ /$self->{option_results}->{filter_uom}/);
                $values{$key} = $perf->{$key};
            }
            
            push @{$json_content->{plugin}->{perfdatas}}, {
                                                           %values
                                                        };
        }
    }

    print $self->{json_output}->encode($json_content);
}

sub output_xml {
    my ($self, %options) = @_;
    my $force_ignore_perfdata = (defined($options{force_ignore_perfdata}) && $options{force_ignore_perfdata} == 1) ? 1 : 0;
    my $force_long_output = (defined($options{force_long_output}) && $options{force_long_output} == 1) ? 1 : 0;
    my ($child_plugin_name, $child_plugin_mode, $child_plugin_exit, $child_plugin_output, $child_plugin_perfdata); 

    my $root = $self->{xml_output}->createElement('plugin');
    $self->{xml_output}->setDocumentElement($root);

    $child_plugin_name = $self->{xml_output}->createElement("name");
    $child_plugin_name->appendText($self->{plugin});

    $child_plugin_mode = $self->{xml_output}->createElement("mode");
    $child_plugin_mode->appendText($self->{mode});

    $child_plugin_exit = $self->{xml_output}->createElement("exit");
    $child_plugin_exit->appendText($options{exit_litteral});

    $child_plugin_output = $self->{xml_output}->createElement("outputs");
    $child_plugin_perfdata = $self->{xml_output}->createElement("perfdatas");

    $root->addChild($child_plugin_name);
    $root->addChild($child_plugin_mode);
    $root->addChild($child_plugin_exit);
    $root->addChild($child_plugin_output);
    $root->addChild($child_plugin_perfdata);

    foreach my $code_litteral (keys %{$self->{global_short_outputs}}) {
        foreach (@{$self->{global_short_outputs}->{$code_litteral}}) {
            my ($child_output, $child_type, $child_msg, $child_exit);
            my $lcode_litteral = ($code_litteral eq 'UNQUALIFIED_YET' ? uc($options{exit_litteral}) : $code_litteral);

            $child_output = $self->{xml_output}->createElement("output");
            $child_plugin_output->addChild($child_output);

            $child_type = $self->{xml_output}->createElement("type");
            $child_type->appendText(1); # short

            $child_msg = $self->{xml_output}->createElement("msg");
            $child_msg->appendText(($options{nolabel} == 0 ? ($lcode_litteral . ': ') : '') . $_);
            $child_exit = $self->{xml_output}->createElement("exit");
            $child_exit->appendText($lcode_litteral);

            $child_output->addChild($child_type);
            $child_output->addChild($child_exit);
            $child_output->addChild($child_msg);
        }
    }

    if (defined($self->{option_results}->{verbose}) || $force_long_output == 1) {
        foreach (@{$self->{global_long_output}}) {
            my ($child_output, $child_type, $child_msg);
        
            $child_output = $self->{xml_output}->createElement("output");
            $child_plugin_output->addChild($child_output);

            $child_type = $self->{xml_output}->createElement("type");
            $child_type->appendText(2); # long

            $child_msg = $self->{xml_output}->createElement("msg");
            $child_msg->appendText($_);

            $child_output->addChild($child_type);
            $child_output->addChild($child_msg);
        }
    }

    if ($options{force_ignore_perfdata} == 0) {
        $self->change_perfdatas();
        foreach my $perf (@{$self->{perfdatas}}) {
            next if (defined($self->{option_results}->{filter_perfdata}) &&
                     $perf->{label} !~ /$self->{option_results}->{filter_perfdata}/);
            $self->range_perfdata(ranges => [\$perf->{warning}, \$perf->{critical}]);
        
            my ($child_perfdata);
            $child_perfdata = $self->{xml_output}->createElement("perfdata");
            $child_plugin_perfdata->addChild($child_perfdata);
            foreach my $key (keys %$perf) {
                $perf->{$key} = '' if (defined($self->{option_results}->{filter_uom}) && $key eq 'unit' &&
                    $perf->{$key} !~ /$self->{option_results}->{filter_uom}/);
                my $child = $self->{xml_output}->createElement($key);
                $child->appendText($perf->{$key});
                $child_perfdata->addChild($child);
            }
        }
    }

    print $self->{xml_output}->toString(1);
}

sub output_txt {
    my ($self, %options) = @_;
    my $force_ignore_perfdata = (defined($options{force_ignore_perfdata}) && $options{force_ignore_perfdata} == 1) ? 1 : 0;
    my $force_long_output = (defined($options{force_long_output}) && $options{force_long_output} == 1) ? 1 : 0;

    if (defined($self->{global_short_concat_outputs}->{UNQUALIFIED_YET})) {
        $self->output_add(severity => uc($options{exit_litteral}), short_msg => $self->{global_short_concat_outputs}->{UNQUALIFIED_YET});
    }

    if (defined($self->{global_short_concat_outputs}->{CRITICAL})) {
        print (($options{nolabel} == 0 ? 'CRITICAL: ' : '') . $self->{global_short_concat_outputs}->{CRITICAL} . " ");
    }
    if (defined($self->{global_short_concat_outputs}->{WARNING})) {
        print (($options{nolabel} == 0 ? 'WARNING: ' : '') . $self->{global_short_concat_outputs}->{WARNING} . " ");
    }
    if (defined($self->{global_short_concat_outputs}->{UNKNOWN})) {
        print (($options{nolabel} == 0 ? 'UNKNOWN: ' : '') . $self->{global_short_concat_outputs}->{UNKNOWN} . " ");
    }
    if (uc($options{exit_litteral}) eq 'OK') {
        print (($options{nolabel} == 0 ? 'OK: ' : '') . (defined($self->{global_short_concat_outputs}->{OK}) ? $self->{global_short_concat_outputs}->{OK} : '') . " ");
    }

    if ($force_ignore_perfdata == 1) {
        print "\n";
    } else {
        print "|";
        $self->change_perfdatas();
        foreach my $perf (@{$self->{perfdatas}}) {
            next if (defined($self->{option_results}->{filter_perfdata}) &&
                     $perf->{label} !~ /$self->{option_results}->{filter_perfdata}/);
            $perf->{unit} = '' if (defined($self->{option_results}->{filter_uom}) &&
                $perf->{unit} !~ /$self->{option_results}->{filter_uom}/);
            $self->range_perfdata(ranges => [\$perf->{warning}, \$perf->{critical}]);
            print " '" . $perf->{label} . "'=" . $perf->{value} . $perf->{unit} . ";" . $perf->{warning} . ";" . $perf->{critical} . ";" . $perf->{min} . ";" . $perf->{max};
        }
        print "\n";
    }
    
    if (defined($self->{option_results}->{verbose}) || $force_long_output == 1) {
        if (scalar(@{$self->{global_long_output}})) {
            print join("\n", @{$self->{global_long_output}});
            print "\n";
        }
    }
}

sub display {
    my ($self, %options) = @_;
    my $nolabel = defined($options{nolabel}) ? 1 : 0;
    my $force_ignore_perfdata = (defined($options{force_ignore_perfdata}) && $options{force_ignore_perfdata} == 1) ? 1 : 0;
    my $force_long_output = (defined($options{force_long_output}) && $options{force_long_output} == 1) ? 1 : 0;
    $force_long_output = 1 if (defined($self->{option_results}->{debug}));

    if (defined($self->{option_results}->{output_file})) {
        if (!open (STDOUT, '>', $self->{option_results}->{output_file})) {
            $self->output_add(severity => 'UNKNOWN',
                              short_msg => "cannot open file  '" . $self->{option_results}->{output_file} . "': $!");
        }
    }
    if (defined($self->{option_results}->{output_xml})) {
        $self->create_xml_document();
        if ($self->{is_output_xml}) {
            $self->output_xml(exit_litteral => $self->get_litteral_status(), 
                              nolabel => $nolabel, 
                              force_ignore_perfdata => $force_ignore_perfdata, force_long_output => $force_long_output);
            return ;
        }
    } elsif (defined($self->{option_results}->{output_json})) {
        $self->create_json_document();
        if ($self->{is_output_json}) {
            $self->output_json(exit_litteral => $self->get_litteral_status(), 
                               nolabel => $nolabel,
                               force_ignore_perfdata => $force_ignore_perfdata, force_long_output => $force_long_output);
            return ;
        }
    } 
    
    $self->output_txt(exit_litteral => $self->get_litteral_status(), 
                      nolabel => $nolabel,
                      force_ignore_perfdata => $force_ignore_perfdata, force_long_output => $force_long_output);
}

sub die_exit {
    my ($self, %options) = @_;
    # $options{exit_litteral} = string litteral exit
    # $options{nolabel} = interger label display
    my $exit_litteral = defined($options{exit_litteral}) ? $options{exit_litteral} : $self->{option_results}->{opt_exit};
    my $nolabel = defined($options{nolabel}) ? 1 : 0;
    # ignore long output in the following case
    $self->{option_results}->{verbose} = undef;

    if (defined($self->{option_results}->{output_xml})) {
        $self->create_xml_document();
        if ($self->{is_output_xml}) {
            $self->output_xml(exit_litteral => $exit_litteral, nolabel => $nolabel, force_ignore_perfdata => 1);
            $self->exit(exit_litteral => $exit_litteral);
        }
    } elsif (defined($self->{option_results}->{output_json})) {
        $self->create_json_document();
        if ($self->{is_output_json}) {
            $self->output_json(exit_litteral => $exit_litteral, nolabel => $nolabel, force_ignore_perfdata => 1);
            $self->exit(exit_litteral => $exit_litteral);
        }
    } 

    $self->output_txt(exit_litteral => $exit_litteral, nolabel => $nolabel, force_ignore_perfdata => 1);
    $self->exit(exit_litteral => $exit_litteral);
}

sub option_exit {
    my ($self, %options) = @_;
    # $options{exit_litteral} = string litteral exit
    # $options{nolabel} = interger label display
    my $exit_litteral = defined($options{exit_litteral}) ? $options{exit_litteral} : $self->{option_results}->{opt_exit};
    my $nolabel = defined($options{nolabel}) ? 1 : 0;

    if (defined($self->{option_results}->{output_xml})) {
        $self->create_xml_document();
        if ($self->{is_output_xml}) {
            $self->output_xml(exit_litteral => $exit_litteral, nolabel => $nolabel, force_ignore_perfdata => 1, force_long_output => 1);
            $self->exit(exit_litteral => $exit_litteral);
        }
    } elsif (defined($self->{option_results}->{output_json})) {
        $self->create_json_document();
        if ($self->{is_output_json}) {
            $self->output_json(exit_litteral => $exit_litteral, nolabel => $nolabel, force_ignore_perfdata => 1, force_long_output => 1);
            $self->exit(exit_litteral => $exit_litteral);
        }
    } 

    $self->output_txt(exit_litteral => $exit_litteral, nolabel => $nolabel, force_ignore_perfdata => 1, force_long_output => 1);
    $self->exit(exit_litteral => $exit_litteral);
}

sub exit {
    my ($self, %options) = @_;
    # $options{exit_litteral} = exit
    
    if (defined($options{exit_litteral})) {
        exit $self->{errors}->{uc($options{exit_litteral})};
    }
    exit $self->{errors}->{$self->{myerrors}->{$self->{global_status}}};
}

sub get_most_critical {
    my ($self, %options) = @_;
    my $current_status = 0; # For 'OK'

    foreach (@{$options{status}}) {
        if ($self->{myerrors_mask}->{uc($_)} > $current_status) {
            $current_status = $self->{myerrors_mask}->{uc($_)};
        }
    }
    return $self->{myerrors}->{$current_status};
}

sub get_litteral_status {
    my ($self, %options) = @_;
    
    if (defined($options{status})) {
        if (defined($self->{errors_num}->{$options{status}})) {
            return $self->{errors_num}->{$options{status}};
        }
        return $options{status};
    } else {
        return $self->{myerrors}->{$self->{global_status}};
    }
}

sub is_status {
    my ($self, %options) = @_;
    # $options{value} = string status 
    # $options{litteral} = value is litteral
    # $options{compare} = string status 

    if (defined($options{litteral})) {
        my $value = defined($options{value}) ? $options{value} : $self->get_litteral_status();
    
        if (uc($value) eq uc($options{compare})) {
            return 1;
        }
        return 0;
    }

    my $value = defined($options{value}) ? $options{value} : $self->{global_status};
    my $dec_val = $self->{myerrors_mask}->{$value};
    my $lresult = $value & $dec_val;
    # Need to manage 0
    if ($lresult > 0 || ($dec_val == 0 && $value == 0)) {
        return 1;
    }
    return 0;
}

sub is_litteral_status {
    my ($self, %options) = @_;
    # $options{status} = string status

    if (defined($self->{errors}->{uc($options{status})})) {
        return 1;
    }

    return 0;
}

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

    if (centreon::plugins::misc::mymodule_load(no_quit => 1, module => 'JSON',
                                           error_msg => "Cannot load module 'JSON'.")) {
        print "Cannot load module 'JSON'\n";
        $self->exit(exit_litteral => 'unknown');
    }
    $self->{is_output_json} = 1;
    $self->{json_output} = JSON->new->utf8();
}

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

    if (centreon::plugins::misc::mymodule_load(no_quit => 1, module => 'XML::LibXML',
                                           error_msg => "Cannot load module 'XML::LibXML'.")) {
        print "Cannot load module 'XML::LibXML'\n";
        $self->exit(exit_litteral => 'unknown');
    }
    $self->{is_output_xml} = 1;
    $self->{xml_output} = XML::LibXML::Document->new('1.0', 'utf-8');
}

sub plugin {
    my ($self, %options) = @_;
    # $options{name} = string name
    
    if (defined($options{name})) {
        $self->{plugin} = $options{name};
    }
    return $self->{plugin};
}

sub mode {
    my ($self, %options) = @_;
    # $options{name} = string name

    if (defined($options{name})) {
        $self->{mode} = $options{name};
    }
    return $self->{mode};
}

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

    push @{$self->{disco_elements}}, @{$options{elements}};
}

sub display_disco_format {
    my ($self, %options) = @_;
    
    if (defined($self->{option_results}->{output_xml})) {
        $self->create_xml_document();
    
        my $root = $self->{xml_output}->createElement('data');
        $self->{xml_output}->setDocumentElement($root);

        foreach (@{$self->{disco_elements}}) {
            my $child = $self->{xml_output}->createElement("element");
            $child->appendText($_);
            $root->addChild($child);
        }

        print $self->{xml_output}->toString(1);
    } elsif (defined($self->{option_results}->{output_json})) {
        $self->create_json_document();
        my $json_content = {data => [] };
        foreach (@{$self->{disco_elements}}) {
            push @{$json_content->{data}}, $_;
        }
        
        print $self->{json_output}->encode($json_content);
    }
}

sub display_disco_show {
    my ($self, %options) = @_;
    
     if (defined($self->{option_results}->{output_xml})) {
        $self->create_xml_document();
        
        my $root = $self->{xml_output}->createElement('data');
        $self->{xml_output}->setDocumentElement($root);

        foreach (@{$self->{disco_entries}}) {
            my $child = $self->{xml_output}->createElement("label");
            foreach my $key (keys %$_) {
                $child->setAttribute($key, $_->{$key});
            }
            $root->addChild($child);
        }

        print $self->{xml_output}->toString(1);
    } elsif (defined($self->{option_results}->{output_json})) {
        $self->create_json_document();
        my $json_content = {data => [] };
        foreach (@{$self->{disco_entries}}) {
            my %values = ();
            foreach my $key (keys %$_) {
                $values{$key} = $_->{$key};
            }
            push @{$json_content->{data}}, {%values};
        }
        
        print $self->{json_output}->encode($json_content);
    }
}

sub to_utf8 {
    my ($self, $value) = @_;
    
    if ($self->{encode_utf8_import} == 0) {
        
        
        # Some Perl version dont have the following module (like Perl 5.6.x)
        if (centreon::plugins::misc::mymodule_load(no_quit => 1, module => 'Encode',
                                                   error_msg => "Cannot load module 'Encode'.")) {
            print "Cannot load module 'Encode'\n";
            $self->exit(exit_litteral => 'unknown');
        }
        
        $self->{encode_utf8_import} = 1;
        eval '$self->{perlqq} = Encode::PERLQQ';
    }
    
    return centreon::plugins::misc::trim(Encode::decode('UTF-8', $value, $self->{perlqq}));
}

sub add_disco_entry {
    my ($self, %options) = @_;
    
    push @{$self->{disco_entries}}, {%options};
}

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

    if (defined($self->{option_results}->{disco_format})) {
        return 1;
    }
    return 0;
}

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

    if (defined($self->{option_results}->{disco_show})) {
        return 1;
    }
    return 0;
}

1;

__END__

=head1 NAME

Output class

=head1 SYNOPSIS

-

=head1 OUTPUT OPTIONS

=over 8

=item B<--verbose>

Display long output.

=item B<--debug>

Display also debug messages.

=item B<--filter-perfdata>

Filter perfdata that match the regexp.

=item B<--explode-perfdata-max>

Put max perfdata (if it exist) in a specific perfdata 
(without values: same with '_max' suffix) (Multiple options)

=item B<--change-perfdata>

Change perfdata name (Multiple option)
Syntax: regexp_matching,regexp_substitute

=item B<--range-perfdata>

Change perfdata range thresholds display: 
1 = start value equals to '0' is removed, 2 = threshold range is not display.

=item B<--filter-uom>

Filter UOM that match the regexp.

=item B<--opt-exit>

Exit code for an option error, usage (default: unknown).

=item B<--output-xml>

Display output in XML Format.

=item B<--output-json>

Display output in JSON Format.

=item B<--output-file>

Write output in file (can be used with json and xml options)

=item B<--disco-format>

Display discovery arguments (if the mode manages it).

=item B<--disco-show>

Display discovery values (if the mode manages it).

=head1 DESCRIPTION

B<output>.

=cut
