package urpm::msg;


use strict;
no warnings;
use Exporter;
use URPM;
use urpm::util 'append_to_file';

=head1 NAME

urpm::msg - routines to prompt messages from the urpm* tools

=head1 SYNOPSIS

=head1 DESCRIPTION

=head1 METHODS

=over

=cut

my $encoding;
BEGIN {
    eval { require encoding; $encoding = encoding::_get_locale_encoding() };
    eval "use open ':locale'" if $encoding && $encoding ne 'ANSI_X3.4-1968';
}

our @ISA = 'Exporter';
our @EXPORT = qw(N N_ P translate bug_log message_input toMb formatXiB sys_log);

#- I18N.
use Locale::gettext;
use POSIX ();
POSIX::setlocale(POSIX::LC_ALL(), "");
my @textdomains = qw(urpmi rpm-summary-main rpm-summary-contrib rpm-summary-devel);
foreach my $domain (@textdomains) {
	Locale::gettext::bind_textdomain_codeset($domain, 'UTF-8');
}
URPM::bind_rpm_textdomain_codeset();

our $no_translation;

sub from_locale_encoding {
    my ($s) = @_;
    $encoding && eval {
	require Encode;
	Encode::decode($encoding, $s);
    } || do { 
	require utf8;
	utf8::decode($s);
	$s;
    } || $s;
}


=item translate($s, $o_plural, $o_nb)

Actually translate a string using gettext.

=cut

sub translate {
    my ($s, $o_plural, $o_nb) = @_;
    my $res;
    if ($no_translation) {
	$s;
    } elsif ($o_nb) {
        foreach my $domain (@textdomains) {
            eval { $res = Locale::gettext::dngettext($domain, $s || '', $o_plural, $o_nb) || $s };
            return $res if $s ne $res;
        }
        return $s;
    } else {
        foreach my $domain (@textdomains) {
            eval { $res = Locale::gettext::dgettext($domain, $s || '') || $s };
            return $res if $s ne $res;
        }
        return $s;
    }
}

=item P($s_singular, $s_plural, $nb, @para)

Like N(), translate a string but with different singular/plural strings according to $nb

=cut

sub P {
    my ($s_singular, $s_plural, $nb, @para) = @_; 
    sprintf(translate($s_singular, $s_plural, $nb), @para);
}

=item N($format, @params)

Translate the $format string (a la printf using @params)

=cut

sub N {
    my ($format, @params) = @_;
    sprintf(translate($format), @params);
}

=item N_($string)

Unlike N(), it doesn't actually translate $string but serves to tag a string as translatable for extracting into pod catalog.

The string will actually be translated later using translate().

=cut

sub N_ { $_[0] }

my $noexpr = N("Nn");
my $yesexpr = N("Yy");

eval {
    require Sys::Syslog;
    Sys::Syslog->import;
    (my $tool = $0) =~ s!.*/!!;

    #- what we really want is "unix" (?)
    #- we really don't want "console" which forks/exit and thus
    #  run callbacks registered through atexit() : x11, gtk+, rpm, ...
    Sys::Syslog::setlogsock([ 'tcp', 'unix', 'stream' ]);

    openlog($tool, '', 'user');
    END { defined &closelog and closelog() }
};

=item sys_log(...)

Log through syslog if Sys::Syslog is installed.

=cut

sub sys_log { defined &syslog and eval { syslog("info", @_) } }

=item bug_log(...)

Writes only to logfile, not to screen

=cut

sub bug_log {
    append_to_file($::logfile, @_) if $::logfile;
}

sub ask_yes_or_no {
    my ($msg) = @_;
    message_input($msg . N(" (y/N) "), boolean => 1) =~ /[$yesexpr]/;
}

sub message_input {
    my ($msg, %o_opts) = @_;
    _message_input($msg, undef, %o_opts);
}
sub _message_input {
    my ($msg, $o_default_input, %o_opts) = @_;
    my $input;
    while (1) {
	print $msg;
	if ($o_default_input) {
	    #- deprecated argument. don't you want to use $o_opts{default} instead?
	    $urpm::args::options{bug} and bug_log($o_default_input);
	    return $o_default_input;
	}
	$input = <STDIN>;
	defined $input or return undef;
	chomp $input;
	$urpm::args::options{bug} and bug_log($input);
	if ($o_opts{boolean}) {
	    $input =~ /^[$noexpr$yesexpr]?$/ and last;
	} elsif ($o_opts{range}) {
	    $input eq "" and $input = $o_opts{default} || 1; #- defaults to first choice
	    (defined $o_opts{range_min} ? $o_opts{range_min} : 1) <= $input && $input <= $o_opts{range} and last;
	} else {
	    last;
	}
	print N("Sorry, bad choice, try again\n");
    }
    return $input;
}


=item toMb($nb)

Convert a number of bytes into Mb

=cut

sub toMb {
    my $nb = $_[0] / 1024 / 1024;
    int $nb + 0.5;
}

my @format_line_field_sizes = (30, 12, 13, 7, 0);
my $format_line_format = '  ' . join(' ', map { '%-' . $_ . 's' } @format_line_field_sizes);

sub format_line_selected_packages {
    my ($urpm, $state, $pkgs) = @_;

    my (@pkgs, @lines, $prev_medium);
    my $flush = sub {
	push @lines, _format_line_selected_packages($state, $prev_medium, \@pkgs);
	@pkgs = ();
    };
    foreach my $pkg (@$pkgs) {
	my $medium = URPM::pkg2media($urpm->{media}, $pkg);
	if ($prev_medium && $prev_medium ne $medium) {
	    $flush->();
	}
	push @pkgs, $pkg;
	$prev_medium = $medium;
    }
    $flush->();

    (sprintf($format_line_format, N("Package"), N("Version"), N("Release"), N("Arch")),
     @lines);
}
sub _format_line_selected_packages {
    my ($state, $medium, $pkgs) = @_;

    my @l = map {
	my @name_and_evr = $_->fullname;
	if ($state->{selected}{$_->id}{recommended}) {
	    push @name_and_evr, N("(recommended)");
	}
	\@name_and_evr;
    } sort { $a->name cmp $b->name } @$pkgs;

    my $i;
    foreach my $max (@format_line_field_sizes) { 
	foreach (@l) {
	    if ($max && length($_->[$i]) > $max) {
		$_->[$i] = substr($_->[$i], 0, $max-1) . '>';
	    }
	}
	$i++;
    }

    ('(' . ($medium ? N("medium \"%s\"", $medium->{name}) : N("command line")) . ')',
     map { sprintf($format_line_format, @$_) } @l);
}


=item formatXiB($number [, $o_newbase])

Returns a nicely human size. eg:

  2097152 => "2MB"

The optional parameter enables to provide the unit size (default is one).
eg for a 2000 512 sized sectors:

  formatXiB(2000, 512)

Duplicated from L<common> (drakx/perl-install/common.pm)

=cut

sub formatXiB {
    my ($newnb, $o_newbase) = @_;
    my $newbase = $o_newbase || 1;
    my ($nb, $base);
    my $decr = sub { 
	($nb, $base) = ($newnb, $newbase);
	$base >= 1024 ? ($newbase = $base / 1024) : ($newnb = $nb / 1024);
    };
    my $suffix;
    foreach (N("B"), N("KB"), N("MB"), N("GB"), N("TB")) {
	$decr->(); 
	if ($newnb < 1 && $newnb * $newbase < 1) {
	    $suffix = $_;
	    last;
	}
    }
    my $v = $nb * $base;
    my $s = $v < 10 && int(10 * $v - 10 * int($v));
    int($v) . ($s ? ".$s" : '') . ($suffix || N("TB"));
}

sub localtime2changelog { scalar(localtime($_[0])) =~ /(.*) \S+ (\d{4})$/ && "$1 $2" }

1;

=back

=head1 COPYRIGHT

Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 MandrakeSoft SA

Copyright (C) 2005-2010 Mandriva SA

Copyright (C) 2011-2020 Mageia

=cut
