#!/usr/bin/perl -w

use strict;
use warnings;

use File::Path qw(make_path remove_tree);
use Data::Array2ArrayMap::Hash::XSTree;
use autodie qw/open close/;
use Test::Repocop::Log;
use Test::Repocop::Workdir;
use Test::Repocop::TestDB;
use Test::Repocop::Metadata;
use Test::Repocop::ACLWrapper;
use Test::Repocop::CLI::Base;
use Test::Repocop::CLI::Report;
our @ISA=qw/Test::Repocop::CLI/;
our @LONGOPT_POD2USAGE=qw/-verbose 1 -exitval 1/;

my $report_all_in_one=0;
my ($by_srpm,$by_test,$by_leader,$by_acl)=(1,1,1,1);
our @LONGOPT=(
    "by-acl!"  => \$by_acl,
    "by-leader!"  => \$by_leader,
    "by-srpm!"  => \$by_srpm,
    "by-test!"  => \$by_test,
    'all-in-one!'=> \$report_all_in_one,
);
__PACKAGE__->get_and_process_cli_options();
&Test::Repocop::Workdir::die_if_nothing_to_report();
&Test::Repocop::CLI::Report::process_arguments();

my $repocop_reportdir="$repocop_workdir/reports/txt";

&repocop_note("creating reports in $repocop_reportdir...");

my $TEST2RPM=Data::Array2ArrayMap::Hash::XSTree->new();
my $RPM2TEST=Data::Array2ArrayMap::Hash::XSTree->new();
my $SRPM2RPM=Data::Array2ArrayMap::Hash::XSTree->new();
my $ACL2TEST=Data::Array2ArrayMap::Hash::XSTree->new();
my $LEADER2TEST=Data::Array2ArrayMap::Hash::XSTree->new();
my %TEST;

my $aclmap=Test::Repocop::ACLWrapper->new();
unless ($aclmap) {
    &repocop_note("acl is not available. Disabled reports by acl/leader.") if $by_leader or $by_acl;
    $by_acl=0;
    $by_leader=0;
}
my $metadata=Test::Repocop::Metadata->new();
my $testdb=Test::Repocop::TestDB->new();
my $cache=$testdb->get_pkg_test_status_result_iterator();
while (my ($rpm,$test,$status,$result)=$cache->iterate4_filtered()) {
    warn "got undef: rpm=[$rpm] test=[$test] status=[$status] result=[$result]\n" unless defined($rpm) and defined($test) and defined($status) and defined($result);
    # linearize
    $result=~s/\n/; /gs;
    my $srpm=$metadata->sourceid($rpm);
    $TEST{$test}=1;
    warn "got undef:[$srpm] for $rpm" unless defined($srpm);
    if ($aclmap) {
	my $srcname=$metadata->name($srpm);
	if (! defined($srcname)) {
	    warn "source name is not defined for $srpm";
	} else {
	    my @acls=$aclmap->name2acl($srcname);
	    # p8 does not have acls now
	    if (scalar @acls) {
		my $leader=$acls[0];
		$LEADER2TEST->append([$leader,$rpm,$test],[$status,$result]);
		foreach my $acl (@acls) {
		    $ACL2TEST->set([$acl,$leader,$rpm,$test],[$status,$result]);
		}
	    }
	}
    }
    $TEST2RPM->set([$test,$status,$rpm],[$result]);
    $RPM2TEST->set([$rpm,$test],[$status,$result]);
    $SRPM2RPM->set([$srpm,$rpm],[1]);
}


my @tests=sort keys %TEST;

if ($report_all_in_one) {
    my $dir_all_in_one=&prepare_report_subdir('');
    open (CURFILE, ">", "$dir_all_in_one/all_in_one.txt");
    foreach my $srpm (sort $SRPM2RPM->keys_at([])) {
	my @rpms = sort $SRPM2RPM->keys_at([$srpm]);
	foreach my $rpm (@rpms) {
	    foreach my $test (@tests) {
		my ($status,$result)= $RPM2TEST->get([$rpm,$test]);
		print CURFILE "$rpm\t$test\t$status\t$result\n" if $status;
	    }
	}
    }
    close (CURFILE);
}

if ($by_test) {
    my $dir_by_test=&prepare_report_subdir('by-test');
    foreach my $test (sort $TEST2RPM->keys_at([])) {
	open (CURFILE, ">", "$dir_by_test/$test.txt");
	foreach my $status (sort $TEST2RPM->keys_at([$test])) {
	    foreach my $rpm (sort $TEST2RPM->keys_at([$test,$status])) {
		my ($result)=$TEST2RPM->get([$test,$status,$rpm]);
		chomp $result;
		print CURFILE "$status\t$rpm\t$result\n";
	    }
	}
	close (CURFILE);
    }
}

if ($by_srpm) {
    my $dir_by_srpm=&prepare_report_subdir('by-srpm');
    foreach my $srpm (sort $SRPM2RPM->keys_at([])) {
	open (CURFILE, ">", "$dir_by_srpm/$srpm.txt");
	my @rpms = sort $SRPM2RPM->keys_at([$srpm]);
	foreach my $rpm (@rpms) {
	    foreach my $test (@tests) {
		my ($status,$result)= $RPM2TEST->get([$rpm,$test]);
		print CURFILE "$rpm\t$test\t$status\t$result\n" if $status;
	    }
	}
	close (CURFILE);
    }
}

if ($by_acl and $aclmap) {
    my $dir_by_acl=&prepare_report_subdir('by-acl');
    foreach my $acl (sort $ACL2TEST->keys_at([])) {
	open (CURFILE, ">", "$dir_by_acl/$acl.txt");
	my @packager = sort $ACL2TEST->keys_at([$acl]);
	foreach my $packager (@packager) {
	    my @rpms = sort $ACL2TEST->keys_at([$acl,$packager]);
	    foreach my $rpm (@rpms) {
		my @tests = sort $ACL2TEST->keys_at([$acl,$packager,$rpm]);
		foreach my $test (@tests) {
		    my ($status,$result)=$ACL2TEST->get([$acl,$packager,$rpm,$test]);
		    print CURFILE "$packager\t$rpm\t$test\t$status\t$result\n";
		}
	    }
	}
	close (CURFILE);
    }
}

if ($by_leader and $aclmap) {
    &__triplet_by_1($LEADER2TEST,'by-leader');
}

sub __triplet_by_1 {
    my ($KEYSTORE,$subdirname)=@_;
    my $dir_by_leader=&prepare_report_subdir($subdirname);
    foreach my $leader (sort $KEYSTORE->keys_at([])) {
	open (CURFILE, ">", "$dir_by_leader/$leader.txt");
	my @rpms = sort $KEYSTORE->keys_at([$leader]);
	foreach my $rpm (@rpms) {
	    my @tests = sort $KEYSTORE->keys_at([$leader,$rpm]);
	    foreach my $test (@tests) {
		my ($status,$result)=$KEYSTORE->get([$leader,$rpm,$test]);
		print CURFILE "$rpm\t$test\t$status\t$result\n";
	    }
	}
	close (CURFILE);
    }
}

sub prepare_report_subdir {
    my ($name)=@_;
    &repocop_note("$name...");
    my $dir_by_name="$repocop_reportdir/$name";
    remove_tree($dir_by_name);
    make_path($dir_by_name);
    return $dir_by_name;
}

&repocop_note("done.");

=head1	NAME

repocop-report-txt - a tool that creates txt reports on repocop unit tests results.

=head1	SYNOPSIS

B<repocop-report-txt>
[B<-h|--help>]
[B<-v|--verbose>]
[B<-q|--quiet>]
[B<--workdir> I<workdir>]
[B<--acl-file> I<file>]
[B<--acl-altlinux> [B<--acl-branch I<sisyphus|t7|...>] [B<--acl-expire> I<time>] ]
[B<--report> I<warn|fail|skip|experimental|ok>]
[B<--report-et|--report-exclude-test> I<comma separated list of tests>]
[B<--report-it|--report-include-test> I<comma separated list of tests>]
[B<--report-include-distrotests>]
[B<--except>]
[B<--given>]
[B<--last-run>]
[B<--by-src-name> name ...]
[repocop_id ...]

=head1	DESCRIPTION

B<repocop-report-txt> processes results of repocop unit tests, created with 
repocop-run command, stored in I<repocop workdir> and creates results in txt form.


=head1 ARGUMENTS

The arguments are the set of repocop ids. The repocop ID is a string
<NAME>-<VERSION>-<RELEASE>.ARCH for binary rpm packages and is a string
<NAME>-<VERSION>-<RELEASE>.src for source rpm packages.

Also repocop IDs can be extracted from file names,
so you can give an arument like /path/to/rpm/files/*.rpm.


=head1	OPTIONS

=over


=item	B<-r, --report> I<skip|experimental|ok|warn|fail>

The level of test results reported. Test results below this level
are not reported. Default is warn.

=item	B<--except>, B<--given>

Control processing of rpm arguments. 
B<--given> (default) means processing only given rpm arguments.
B<--except>  means processing all data except given rpm arguments.

=item	B<--report-et, --report-exclude-test> I<comma separated list of tests>

Include all tests exept the given excluded set.

=item	B<--report-it, --report-include-test> I<comma separated list of tests>

Include the given set of tests.

=item	B<--report-include-distrotests>

Include all distrotests.

=item	B<-l, --last-run>

Use the repocop ids of packages processed at last run as an input.

=item	B<--by-src-name>

Input arguments are expected to be src.rpm names, not repocop ids.
Repocop ids are calculated from given src.rpm names.



=item	B<--acl-file> I<file>

The file content is ACL db,
which is used to sort result by ACL.
The argument is generic acl file compatible with Sisyphus' list.src.classic.

Alternatively, you can provide B<--acl-altlinux>.

=item	B<--acl-altlinux>

This option is ALTLinux-specific. if provided, repocop use ALTLinux::ACL
(perl-ALTLinux-ACL is required). Also, the following options of ALTLinux::ACL
become available:

B<--acl-branch> I<sisyphus|t7|...> Name of branch. Default is sisyphus.

B<--acl-expire> I<days> Cache expiration time, float, in days. Default is 1/5 day.


=item	B<--workdir> I<dir>

Provides alternative location for the Repocop workdir. Repocop workdir
is a place where test results and packages metadata information are stored.
Default is I<~/.repocop>.

=item	B<-h, --help>

Display this help and exit.

=item	B<-v, --verbose>, B<-q, --quiet>

Verbosity level. Multiple -v increase the verbosity level, -q sets it to 0.


=back

=head1	AUTHOR

Written by Igor Vlasenko <viy@altlinux.org>.

=head1	ACKNOWLEGEMENTS

To Alexey Torbin <at@altlinux.org>, whose qa-robot package
had a strong influence on repocop. 

=head1	COPYING

Copyright (c) 2008-2018 Igor Vlasenko, ALT Linux Team.

This 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.

=cut

