#!/usr/bin/perl
#
# explain-lintian-tags -- transform lintian tags into descriptive text
#
# Copyright (C) 1998 Christian Schwarz and Richard Braakman
# Copyright (C) 2013 Niels Thykier
# Copyright (C) 2017 Chris Lamb <lamby@debian.org>
# Copyright (C) 2020 Felix Lechner
#
# This program is free software.  It is distributed under the terms of
# the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any
# later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, you can find it on the World Wide
# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free
# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
# MA 02110-1301, USA.

use v5.20;
use warnings;
use utf8;

use Cwd qw(realpath);
use File::Basename qw(dirname);

# neither Path::This nor lib::relative are in Debian
use constant THISFILE => realpath __FILE__;
use constant THISDIR => dirname realpath __FILE__;

# use Lintian modules that belong to this program
use lib THISDIR . '/../lib';

# substituted during package build
my $LINTIAN_VERSION;

use Const::Fast;
use Getopt::Long ();
use IO::Interactive qw(is_interactive);
use List::SomeUtils qw(any);
use Term::ReadKey;
use Unicode::UTF8 qw(encode_utf8);

use Lintian::Output::EWI;
use Lintian::Output::HTML;
use Lintian::Output::JSON;
use Lintian::Profile;
use Lintian::Version qw(guess_version);

const my $EMPTY => q{};
const my $SPACE => q{ };

const my $DEFAULT_OUTPUT_WIDTH => 80;

const my $NEW_PROGRAM_NAME => q{lintian-explain-tags};

my $TERMINAL_WIDTH;
($TERMINAL_WIDTH, undef, undef, undef) = GetTerminalSize()
  if is_interactive;
$TERMINAL_WIDTH //= $DEFAULT_OUTPUT_WIDTH;

if (my $coverage_arg = $ENV{'LINTIAN_COVERAGE'}) {
    my $p5opt = $ENV{'PERL5OPT'}//$EMPTY;
    $p5opt .= $SPACE if $p5opt ne $EMPTY;
    $ENV{'PERL5OPT'} = "${p5opt} ${coverage_arg}";
}

$ENV{LINTIAN_BASE} = realpath(THISDIR . '/..')
  // die encode_utf8('Cannot resolve LINTIAN_BASE');

$ENV{LINTIAN_VERSION} = $LINTIAN_VERSION // guess_version($ENV{LINTIAN_BASE});
die encode_utf8('Unable to determine the version automatically!?')
  unless length $ENV{LINTIAN_VERSION};

my $format = 'ewi';
my @INCLUDE_DIRS;
my $list_tags;
my $profile_name;
my $tags;
my $user_dirs = 1;

my %options = (
    'format|f=s' => \$format,
    'help|h' => \&show_help,
    'include-dir=s' => \@INCLUDE_DIRS,
    'list-tags|l' => \$list_tags,
    'output-width=i' => \$TERMINAL_WIDTH,
    'profile=s' => \$profile_name,
    'tags|tag|t' => \$tags,
    'user-dirs!' => \$user_dirs,
    'version' => \&show_version,
);

Getopt::Long::Configure('gnu_getopt');
Getopt::Long::GetOptions(%options)
  or die encode_utf8("error parsing options\n");

my $profile = Lintian::Profile->new;
$profile->load($profile_name, \@INCLUDE_DIRS, $user_dirs);

my $output;

$format = lc $format;
if ($format eq 'ewi') {
    $output = Lintian::Output::EWI->new;

} elsif ($format eq 'json') {
    $output = Lintian::Output::JSON->new;

} elsif ($format eq 'html') {
    $output = Lintian::Output::HTML->new;

} else {
    die encode_utf8("Invalid output format $format\n");
}

if ($list_tags) {
    say encode_utf8($_) for sort { lc($a) cmp lc($b) } $profile->enabled_tags;
    exit;
}

# show all tags when none were specified
my @selected = @ARGV;
@selected = $profile->enabled_tags
  unless @selected;

my @available = grep { defined} map { $profile->get_tag($_) } @selected;

my @sorted = sort { lc($a->name) cmp lc($b->name) } @available;

$output->describe_tags($profile->data, \@sorted, $TERMINAL_WIDTH);

exit any { !defined $profile->get_tag($_) } @selected;

sub show_version {
    say encode_utf8("$NEW_PROGRAM_NAME v$ENV{LINTIAN_VERSION}");

    exit;
}

sub show_help {
    my $message =<<"EOT";
Usage: $NEW_PROGRAM_NAME [log-file...] ...
       $NEW_PROGRAM_NAME [--tags] tag ...

Options:
    -l, --list-tags    list all tags Lintian knows about
    -t, --tag, --tags  display tag descriptions
    --include-dir DIR  check for Lintian data in DIR
    --profile X        use vendor profile X to determine severities
    --output-width NUM set output width instead of probing terminal
    --[no-]user-dirs   whether to include profiles from user directories
    --version          show version info and exit
EOT

    print encode_utf8($message);

    exit;
}

# Local Variables:
# indent-tabs-mode: nil
# cperl-indent-level: 4
# End:
# vim: syntax=perl sw=4 sts=4 sr et
