#!/usr/bin/env perl
# vim: set sw=4 ts=4 et ai si:
#
use strict;
use warnings;

use Getopt::Long;
use Pod::Usage;
use Text::CSV qw(csv);
use WebService::IdoitAPI::Layer3Net;

our $VERSION = '0.4.3'; # VERSION

sub import_csv {
    my ($config,$known_l3n) = @_;
    my $api = $config->{api};
    my $rows = read_csv($config->{opt}->{import_csv});
    for my $row (@$rows) {
        next    if (exists $known_l3n->{$row->{network}});

        my $id = WebService::IdoitAPI::Layer3Net::create( $api, $row );
        if ($id) {
            $known_l3n->{$row->{network}} = $id;
        }
    }
} # import_csv()

sub initialize {
    my $config = {};
    my %opt = ();
    my @opt_def = qw(
        config=s csv
        help|?
        import_csv|import-csv=s
        json
	list
        man
        pretty
        version
    );
    GetOptions(\%opt, @opt_def);

    pod2usage(-exitstatus => 0, -input => \*DATA)
        if $opt{help};
    pod2usage(-exitstatus => 0, -input => \*DATA, -verbose => 2)
        if $opt{man};
    pod2usage(-exitstatus => 0, -input => \*DATA, -verbose => 99, -sections => 'VERSION')
        if $opt{version};

    $config = WebService::IdoitAPI::read_config($opt{config});

    $config->{opt} = \%opt;

    my $api = WebService::IdoitAPI->new( $config );
    
    $api->login();

    $config->{api} = $api;

    return $config;
} # initialize()

sub print_aoh {
    my ($config,$aoh) = @_;


    if ( $config->{opt}->{json} ) {
        print_aoh_json($config, $aoh);
    }
    elsif ( $config->{opt}->{csv} ) {
        print_aoh_csv($config, $aoh);
    }
    else {
        print_aoh_text($config, $aoh);
    }
} # print_aoh()

sub print_aoh_csv {
    my ($config,$aoh) = @_;

    return unless scalar(@$aoh); # exclude empty array

    my $csv_out = Text::CSV->new({binary => 1, auto_diag => 1});
    my @headers = sort keys %{$aoh->[0]};
    $csv_out->say(\*STDOUT, [@headers]);
    for my $row (@$aoh) {
        $csv_out->say(\*STDOUT, [$row->@{@headers}]);
    }
} # print_aoh_csv()

sub print_aoh_json {
    my ($config,$aoh) = @_;
    my $json = JSON->new();
    $json->canonical();

    if ( $config->{opt}->{pretty} ) {
        print $json->pretty->encode($aoh);
    }
    else {
        print $json->encode($aoh);
    }
} # print_aoh_json()

sub print_aoh_text {
    my ($config,$aoh) = @_;
    print "---------------\n";
    for my $record (@$aoh) {
        for my $key (sort keys %$record) {
            print "$key: $record->{$key}\n";
        }
        print "---------------\n";
    }
} # print_aoh_text()

sub read_csv {
    my ($fname) = @_;
    my ($csv,$fh,@headers,$rows);

    $csv = Text::CSV->new ({ binary => 1, auto_diag => 1 });

    open($fh, "<:encoding(utf8)", $fname)
        or die "read_csv() can't open '$fname' $!";
    @headers = $csv->header($fh);
    while (my $row = $csv->getline_hr ($fh)) {
        push(@$rows, $row);
        next;
    }
    close($fh);
    return $rows;
} # read_csv()

my $config = initialize();

my $l3_nets = WebService::IdoitAPI::Layer3Net::list( $config->{api} );

if ($config->{opt}->{import_csv}) {

    # see 'perldoc -f map' why there is "map {; ..."
    my %known_l3n = map {; "$_->{address}/$_->{cidr_suffix}" => $_->{id} } @$l3_nets;

    import_csv($config,\%known_l3n);
    $l3_nets = WebService::IdoitAPI::Layer3Net::list( $config->{api} );
}

unless ( $l3_nets ) {
    die "Could not get any layer 3 network, exiting!";
}

if ($l3_nets) {
    print_aoh($config, $l3_nets);
}

exit 0;

__END__

=head1 NAME

idoit-layer3-nets - get i-doit layer3 nets

=head1 VERSION

version 0.4.3

=head1 SYNOPSIS

  idoit-layer3-nets [ options ]

=head1 OPTIONS AND ARGUMENTS

=head2 Options

=head3 --config path

Read configuration values from a file found at the given path.

=head3 --help / -?

The program shows a short help text and exits.

=head3 --man

The program shows this man page and exits.

=head3 --csv

The report is printed as CSV.

=head3 --json

The report is printed as JSON.

=head3 --pretty

Given together with option C<< --json >>,
the output is printed as readable formatted JSON.

=head3 --import-csv filename

Import layer3 networks from the named CSV file.

=head3 --version

The program shows its version and exits.

=head1 CONFIGURATION FILE

This file should contain lines with a key and a value
separated by equal sign (I<=>) or colon (I<:>).
The key and the value may be enclosed
in single (I<'>) or double (I<">) quotation marks.
Leading and trailing white space is removed
as well as a comma (I<,>) at the the end of the line.

The program needs the following keys in the file:

=over 4

=item key

The API key for i-doit.

=item url

The URL of the i-doit instance.

=item username

The username for the login (optional).

=item password

The password for the login (optional).

=back

=head1 CSV FILE

The CSV file for the import of networks should have the following columns:

=over 4

=item network

The network to be imported,
optionally followed by a slash and the number of netmask bits.

If the slash and the bits is missing,
the network is considered a single address.

=item title

The title of the network.

If this field or column is missing,
the network is used in CIDR notation.

=item description

The description for the network.

If this field or column is missing,
the description will be empty.

=back

The script will only import networks into i-doit
that were not previously known.

If the same network appears multiple times in the CSV file,
only the first record will be imported.

=head1 AUTHOR

Mathias Weidner C<< mamawe@cpan.org >>

=head1 LICENCE AND COPYRIGHT

Copyright (c) 2023, Mathias Weidner C<< mamawe@cpan.org >>.
All rights reserved.

This software is free software; you can redistribute it and/or
modify it under the same terms as Perl itself. See L<perlartistic>.

=cut
