#!/usr/bin/perl

###############################################################################
## Copyright (c) 2007-2012 SUSE LINUX Products GmbH, Nuernberg, Germany.
###############################################################################

use strict;
use warnings;
use FindBin;
BEGIN { unshift @INC, "$FindBin::Bin/../www/perl-lib" }

use SMT::CLI;
use File::Basename;
use SMT::Utils;
use Text::ASCIITable;

use Locale::gettext ();
use POSIX ();                   # Needed for setlocale()

POSIX::setlocale(&POSIX::LC_MESSAGES, "");

if(!SMT::Utils::dropPrivileges())
{
    print STDERR __("Unable to drop privileges. Abort!\n");
    exit 1;
}

my $enable;
my $disable;
my $delete;
my $enableByProduct = "";
my $disableByProduct = "";
my $namespace="";
my $enableStaging = 0;
my $disableStaging = 0;
my $mirrorable;
my $domirror;
my $verbose;
my $help;
my $batchMode;

use Getopt::Long;
&Getopt::Long::Configure( 'no_auto_abbrev', 'no_ignore_case');
my $optres = &Getopt::Long::GetOptions(
                                       'enable-mirror|e'      => \$enable,
                                       'disable-mirror|d'     => \$disable,
                                       'enable-by-prod|p=s'   => \$enableByProduct,
                                       'disable-by-prod|P=s'  => \$disableByProduct,
                                       'enable-staging|s'     => \$enableStaging,
                                       'disable-staging|S'    => \$disableStaging,
                                       'only-mirrorable|m'    => \$mirrorable,
                                       'only-enabled|o'       => \$domirror,
                                       'verbose|v'            => \$verbose,
                                       'batch-mode|b'         => \$batchMode,
                                       'delete'               => \$delete,
                                       'namespace=s'          => \$namespace,
                                       'help|h'               => \$help
                                      );


if ( (defined $help && $help == 1 ) || (defined $optres && $optres == 0) )
{
    # can't use basename($0) because if called via the smt-catalogs symlink
    # smt-catalogs would be shown - that would not inform the user about
    # renaming of the script
    print "smt-repos [name] [target]: " . __("Enable or disable mirroring of a repository\n");
    print "   --enable-mirror   (-e)     : " . __("enable repository mirorring for \$repository\n");
    print "   --disable-mirror  (-d)     : " . __("disable repository mirroring for \$repository\n");
    print "   --enable-by-prod  (-p) arg : " . __("enable repository mirroring by giving product data\n");
    print "                                Product[,Version[,Architecture[,Release]]]\n";
    print "                                (call smt list-products to get a list of known products)\n";
    print "   --disable-by-prod (-P) arg : " . __("disable repository mirroring by giving product data\n");
    print "                                Product[,Version[,Architecture[,Release]]]\n";
    print "                                (call smt list-products to get a list of known products)\n";
    print "   --enable-staging  (-s)     : " . __("Enable staging for a repository\n");
    print "   --disable-staging (-S)     : " . __("Disable staging for a repository\n");
    print "   --only-mirrorable (-m)     : " . __("only show mirrorable repositories\n");
    print "   --only-enabled    (-o)     : " . __("only show repositories set to be mirrored\n");
    print "   --delete                   : " . __("delete the repository from disk\n");
    print "   --namespace            arg : " . __("specify the namespace of the repository which should be deleted\n");
    print "   --verbose         (-v)     : " . __("show detailed repository information\n");
    print "   --help            (-h)     : " . __("show this help\n");
    exit 0;
}

if ( $enableByProduct ne "" )
{
    my $ret = SMT::CLI::setCatalogsByProduct( verbose => $verbose, prodStr => $enableByProduct, enable => 1);
    exit $ret;
}
elsif ( $disableByProduct ne "" )
{
    my $ret = SMT::CLI::setCatalogsByProduct( verbose => $verbose, prodStr => $disableByProduct, enable => 0);
    exit $ret;
}

my $name = shift(@ARGV);

if ( defined $disable && defined $enable )
{
    die __("Neurosis is the inability to tolerate ambiguity. Sigmund Freud.\n");
}

if ( $disableStaging && $enableStaging )
{
    die __("Neurosis is the inability to tolerate ambiguity. Sigmund Freud.\n");
}

my $bool;
if ( defined $disable )
{
    $bool = ( $disable == 1 ? 0 : 1 );
}

if ( defined $enable )
{
    $bool = ( $enable == 1 ? 1 : 0 );
}

my $boolStaging;
if ( defined $disableStaging )
{
    $boolStaging = ( $disableStaging == 1 ? 0 : 1 );
}

if ( defined $enableStaging )
{
    $boolStaging = ( $enableStaging == 1 ? 1 : 0 );
}

my $target = shift(@ARGV);

my ($cfg, $dbh, $nuri) = SMT::CLI::init();

my $count = 0;
my @catalogs;
my $sql = "select * from Catalogs";

$sql = $sql . " where 1";

if ( defined($mirrorable) )
{
    if (  $mirrorable == 1 )
    {
        $sql = $sql . " and MIRRORABLE='Y'";
    }
    else
    {
        $sql = $sql . " and MIRRORABLE='N'";
    }
}

if ( defined($domirror) )
{
    if (  $domirror == 1 )
    {
        $sql = $sql . " and DOMIRROR='Y'";
    }
    else
    {
        $sql = $sql . " and DOMIRROR='N'";
    }
}

if (defined $name && $name ne "")
{
    $sql = $sql . sprintf(" and NAME=%s", $dbh->quote($name) );
}
# if target was given, limit the search even more
if (defined $target && $target ne "")
{
    $sql = $sql . sprintf(" and TARGET=%s", $dbh->quote($target) );
}

$sql = $sql . " order by NAME, TARGET";

# hash to associate order with id.
my @idnumbers;
my $sth = $dbh->prepare($sql);
$sth->execute();

my $output = "";

my $t = new Text::ASCIITable;
$t->setCols(__("Mirror?"), __("ID"), __("Type"), __("Name"), __("Target"), __("Description"), __("Can be Mirrored"), __("Staging"));

while ( my $v = $sth->fetchrow_hashref() ) {
    $count++;
    my $catId = $v->{ID};
    push(@idnumbers, $catId);
    my $catName = $v->{NAME};
    my $catTarget = $v->{TARGET};
    my $catType = $v->{CATALOGTYPE};
    my $catDesc = $v->{DESCRIPTION};
    my $catMA   = $v->{MIRRORABLE};
    my $catStaging = $v->{STAGING};

    if (defined($verbose)) {
        my $st = sprintf("select p.ID, p.PRODUCT, p.VERSION, p.ARCH, p.REL, pc.OPTIONAL from Products p, ProductCatalogs pc where pc.CATALOGID=%s and p.ID = pc.PRODUCTID order by p.PRODUCT, p.VERSION, p.ARCH, p.REL",
                         $dbh->quote($catId));
        my $products = $dbh->selectall_arrayref($st,{Slice=>{}} );

        $output .= "[" . (( $v->{DOMIRROR} eq "Y" ) ? "*] " : " ] ") . "[" . sprintf("%3d", $count) . "] " . $catName ." " . ( defined($catTarget) ? $catTarget : "--") ."\n";
        $output .= "          (" . $v->{DESCRIPTION} .")\n";
        $output .= "          " . $v->{EXTURL} ."\n";
        $output .= "          " . $v->{LOCALPATH} ."\n";
        $output .= "          Repository ID: " . $v->{ID} ."\n";
        $output .= "          Staging  : " . $catStaging ."\n";
        foreach my $h (@{$products}) {
            my $product = (defined $h->{PRODUCT}?$h->{PRODUCT}:"");
            my $version = (defined $h->{VERSION}?$h->{VERSION}:"");
            my $arch    = (defined $h->{ARCH}?$h->{ARCH}:"");
            my $rel     = (defined $h->{REL}?$h->{REL}:"");

            $output .= "          Assigned to product: $product $version $arch $rel\n";
        }
    } else {
        $t->addRow( (( $v->{DOMIRROR} eq "Y" ) ? __("Yes") :  __("No")), $count, $catType, $catName, ( defined($catTarget) ? $catTarget : "--"),
                    $catDesc,  (( $catMA eq "Y" ) ? __("Yes") : __("No")), (( $catStaging eq "Y" ) ? __("Yes") : __("No")));
    }
}


if (not defined $verbose) {
    # easy-to-parse output
    if (defined $batchMode && $batchMode == 1) {
        $t->setOptions('hide_HeadLine', 1);
        $t->setOptions('hide_HeadRow', 1);
        $output .= $t->draw(
                            ['', '', '', ''],
                            ['|', '|', '|'],
                            ['', '', '', ''],
                            ['|', '|', '|'],
                            ['', '', '', '']
                           );
        # common human-readable output
    } else {
        $output .= $t->draw();
    }
}

if ( ! defined $disable && ! defined $enable &&
     ! $disableStaging && ! $enableStaging && ! $delete )
{
    print $output;
    # not do any action, display was enough
    exit 0;
}

if ( $count == 0 )
{
    die __(sprintf("no repository named %s\n", $name));
}
elsif ( $count == 1 )
{
    # we are lucky, only one
    if ( $disable || $enable )
    {
        my $rows = SMT::CLI::setCatalogDoMirror(enabled => $bool, id => $idnumbers[0]);
        if ($bool)
        {
            print sprintf(__N(
                    '%d repository enabled.',
                    '%d repositories enabled.',
                    $rows),
                $rows) . "\n";
        }
        else
        {
            print sprintf(__N(
                    '%d repository disabled.',
                    '%d repositories disabled.',
                    $rows),
                $rows) . "\n";
        }
        exit 0;
    }
    elsif( $disableStaging || $enableStaging)
    {
        my $rows = SMT::CLI::setCatalogStaging(enabled => $boolStaging, id => $idnumbers[0]);
        if ($boolStaging)
        {
            print sprintf(__N(
                    'Staging enabled for %d repository.',
                    'Staging enabled for %d repositories.',
                    $rows),
                $rows) . "\n";
        }
        else
        {
            print sprintf(__N(
                    'Staging disabled for %d repository.',
                    'Staging disabled for %d repositories.',
                    $rows),
                $rows) . "\n";
        }
        exit 0;
    }
    elsif( $delete )
    {
        my $ret = SMT::CLI::deleteCatalogs(id => $idnumbers[0], namespace => $namespace);
        exit $ret;
    }
}
else
{
    print $output;
    print sprintf(__("Select repository number (or all) to change,  (1-%d,a) :"), $count);

    my $answer = <STDIN>;
    chomp($answer);

    if (lc($answer) eq __("a"))
    {
        if ( $disable || $enable )
        {
            my $rows = SMT::CLI::setCatalogDoMirror(enabled => $bool, name => $name, target => $target);
            # FIXME this should use gettext for variable mutliplicity
            print sprintf(__("%d Repo(s) %s.\n"), $rows, ($bool?__("enabled"):__("disabled")) );
            exit 0;
        }
        elsif( $disableStaging || $enableStaging)
        {
            my $rows = SMT::CLI::setCatalogStaging(enabled => $boolStaging, name => $name, target => $target);
            # FIXME this should use gettext for variable mutliplicity
            print sprintf(__("%d Repo(s) %s.\n"), $rows, ($boolStaging?__("staging enabled"):__("staging disabled")) );
            exit 0;
        }
        elsif( $delete )
        {
            my $ret = SMT::CLI::deleteCatalogs(name => $name, target => $target, namespace => $namespace);
            exit $ret;
        }
    }
    elsif ( $answer =~ /^[0-9]+$/ && int($answer) <= $count && int($answer) > 0 )
    {
        my $number = int($answer);

        if ( $disable || $enable )
        {
            my $rows = SMT::CLI::setCatalogDoMirror(enabled => $bool, id => $idnumbers[$number-1]);
            # FIXME this should use gettext for variable mutliplicity
            print sprintf(__("%d Repo(s) %s.\n"), $rows, ($bool?__("enabled"):__("disabled")) );
            exit 0;
        }
        elsif( $disableStaging || $enableStaging)
        {
            my $rows = SMT::CLI::setCatalogStaging(enabled => $boolStaging, id => $idnumbers[$number-1]);
            # FIXME this should use gettext for variable mutliplicity
            print sprintf(__("%d Repo(s) %s.\n"), $rows, ($boolStaging?__("staging enabled"):__("staging disabled")) );
            exit 0;
        }
        elsif( $delete )
        {
            my $ret = SMT::CLI::deleteCatalogs(id => $idnumbers[$number-1], namespace => $namespace);
            exit $ret;
        }
    }
    else
    {
        print __("canceled.\n");
    }
}

exit 0;

#
# Manpage
#

=head1 NAME

smt repos

=head1 SYNOPSIS

smt repos [options] [name] [target]

=head1 DESCRIPTION

C<smt repos> shows information about known repositories allowing filtering by varous criteria, and allows to activate or deactivate repositories for mirroring.

=head1 OPTIONS


=head2 COMMANDLINE

=over

=item [name]

Filters by repository name.

=item [target]

Additionally to repository name, filter by repository target.

=item --enable-mirror -e

Enables mirroring of a repository.

=item --disable-mirror -d

Disables mirroring of a repository.

=item --enable-by-prod -p arg

Enables repository mirroring by giving product data.

Product[,Version[,Architecture[,Release]]]
(call smt list-products to get a list of known products)

=item --disable-by-prod -P arg

Disables repository mirroring by giving product data.

Product[,Version[,Architecture[,Release]]]
(call smt list-products to get a list of known products)

=item --enable-staging -s

Enable staging for a repository.

=item --disable-staging -S

Disable staging for a repository.

=item --only-mirrorable -m

Shows mirrorable repositories only.

=item --only-enabled -o

Shows repositories set to be mirrored only.

=item --verbose -v

Shows detailed repository information.

=item --delete

Delete the repository from disk.

=item --namespace arg

Specify the namespace of the repository which should be deleted.

=back

=head1 AUTHORS and CONTRIBUTORS

Duncan Mac-Vicar Prett, Lukas Ocilka, Jens Daniel Schmidt, Michael Calmer, Jan Kupec

=head1 LICENSE

Copyright (c) 2007-2012 SUSE LINUX Products GmbH, Nuernberg, Germany.

This program is free software; you can redistribute it and/or modify it 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, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.

=cut


