package AllPkg;
use warnings;
use strict;
use integer;
use DebSrcBin;
use AllProv;
use AllSrc;
use AllBin;

# Warning threshold:
#   100 to disable the stdout progress messages entirely;
#    50 for typical use;
#     0 for pedantic messages or debugging.
our $wth =  50;

our %relationship_string = (
  'xPre-Depends'          => 'pre-depends on',
  'xDepends'              => 'depends on',
  'xRecommends'           => 'recommends',
  'xSuggests'             => 'suggests',
  'renh'                  => 'is enhanced by',
  'xBuild-Depends'        => 'build-depends on',
  'xBuild-Depends-Indep'  => 'build-depends for indep on',
  'xConflicts'            => 'conflicts against',
  'xReplaces'             => 'replaces',
  'xBuild-Conflicts'      => 'build-conflicts against',
  'xBuild-Conflicts-Indep'=> 'build-conflicts for indep against',
);

# Verbosity:
#    60 - Print even trivial pnames.
#    50 - Omit trivial pnames.
#    30 - Omit all pnames.
our $verbosity = 50;

# Instantiate and initialize.
sub new {

  # Instantiate.
  my $class = shift;
  my( $src_filename, $bin_filename ) = @_;
  warn "reading files:\n"                                 if $wth <= 70;
  warn "    Sources...\n"                                 if $wth <= 60;
  my $src  = AllSrc->new( $src_filename );
  warn "    Packages...\n"                                if $wth <= 60;
  my $bin  = AllBin->new( $bin_filename );
  my $self = { src => $src, bin => $bin };
  bless $self, $class;

  # Build out.
  warn "building the data structures out:\n"              if $wth <= 70;
  warn "    referencing build-deps by binary...\n"        if $wth <= 50;
  $bin->add_build_dep( $src );
  warn "    referring sources to their binaries...\n"     if $wth <= 50;
  $src->refer_to_bin ( $bin );
  warn "    hashing package provisions...\n"              if $wth <= 60;
  my $prov      = AllProv->new( $bin );
  $self->{prov} = $prov;
  warn "    reversing package enhancements...\n"          if $wth <= 50;
  $bin->reverse_enhance();
  warn "done initializing\n"                              if $wth <= 65;

  return $self;

}

sub check {
  my( $self, $levels, $sel ) = @_;
  $self->{bin}->are_selections_consistent( $levels, $sel );
}

# Transform error hashes into outputtable error strings.
sub errstr {

  my $self = shift;
  my $sel  = shift;
  map {

    # Here is a single error hash, including the pname whose dependency
    # is not satisfied, the relationship (Recommends, Conflicts, etc)
    # unsatisfied, and the altern which fails the test.
    #
    # The local flags $any_passes and $any_fails refer not to the larger
    # test outside this local loop, but rather to the $$xpname relevance
    # test by &AllProv::pnames_provided within the loop.
    #
    my $any_passes  = 0;
    my $any_fails   = 0;
    my $pname1      = $_->{pname       };
    my $altern1     = $_->{altern      };
    my $relat1      = $_->{relationship};
    my $rel_str1    = $relationship_string{$relat1};
    my $is_cfl      = $AllBin::dep_cfl    {$relat1};
    my $test_xpname =                  $is_cfl;
    my $test_xsel   = defined($sel) && $is_cfl;
    my $line        = "$pname1 $rel_str1 " . join(
      ' | ', map {

        # Here is a single alternative from the altern.
        my $xpname     = $pname1;
        my $xsel       = $sel   ;
        my $xpname_ref = $test_xpname ? \$xpname : undef;
        my $xsel_ref   = $test_xsel   ? \$xsel   : undef;
        my $vname_str  =
          $_->{vname}
          . ( $_->{ver} ? ( " ($_->{rel} $_->{ver})" ) : '' )
          . (
            $verbosity >= 40
            ? $self->{prov}->pnames_provided_str(
              $_->{vname}, $_->{rel}, $_->{ver},
              $verbosity < 60, $xpname_ref, $xsel_ref
            )
            : ''
          );
        if (
          ( !$test_xpname || defined($xpname) ) &&
          ( !$test_xsel   || defined($xsel  ) )
        )    { $any_passes = 1 }
        else { $any_fails  = 1 }
        $vname_str;

      } @$altern1
    ) . "\n";
    !$any_passes && $any_fails ? () : ( $line );

  } @_;

}

# Perform a complete analysis.  Return a complete discrepancy report.
sub analyze_and_report {
  my( $self, $levels, $sel ) = @_;
  $self->errstr(
    ( defined($sel) ? $sel : $DebSrcBin::select_up_default ),
    $self->check( $levels, $sel )
  );
}

sub select_by_pri {
  my $self = shift;
  $self->{bin}->select_by_pri( @_ );
}

1;

