#!/usr/bin/perl -w

# Package ordering tool. Version 0.5
# By Martijn van Oosterhout Copyright Dec 1999 <kleptog@svana.org>
# Hereby give permission for everyone to do whatever they like with this file
# as long as my name remains within it.

use strict;

my %depends = (
# Hacks to get around truly strange dependencies
  'qmail'             => [ 'qmail-src' ],
  'device3dfx-module' => [ 'device3dfx-source' ],
  'ezmlm-idx'         => [ 'ezmlm-src' ],
  'pine'              => [ 'pine396-src', 'pine396-diffs' ],
  'pike-crypto'       => [ 'pike-crypto-build' ],
  'ucspi-tcp'         => [ 'ucspi-tcp-src' ],
);
my $package;
my %score;
my %size;
my %dependedon = qw( qmail-src 1 device3dfx-source 1 ezmlm-src 1 pine396-src 1 pine396-diffs 1 pike-crypto-build 1 ucspi-tcp-src 1 );
my %dist       = qw( qmail non-free device3dfx-module main ezmlm-idx contrib pine non-free pike-crypto contrib ucspi-tcp non-free );
my %output;

my %distscores = qw( main 2 contrib 1 non-us/main 2 non-free 1 non-us/contrib 1 non-us/non-free 1 );

if( @ARGV == 0 )
{
  print "package-order.pl [[-]distributions...]\n".
        "The distributions may be main, contrib, non-free or non-us/main, non-us/contrib and non-us/non-free\n".
        "You may use fullstops instead of slashes\n".
        "A preceding - indicates that this is a distribution you *not* want to appear on the generated list.\n".
        "The Package files should be in the current directory with names Packages.[dist]\n";
  exit;
}

foreach my $dist ( @ARGV )
{
  my $output = 1;
  if( substr( $dist, 0, 1 ) eq '-' )
  {
    $output = 0;
    $dist = substr( $dist, 1 );
  }
  open( FH, "<Packages.$dist" ) || die "Couldn't open packages file Packages.$dist ($!)\n";

  $dist =~ s#\.#/#g;
  $dist = lc($dist);
  
  $output{$dist} = $output;
  
  if( !defined $distscores{$dist} ) { die "Unknown dist '$dist'\n" }
  
  while(<FH>)
  {
    /^Package: (.*)/ && do { $package = $1; $depends{$package} = []; $score{$package} = 0; $dist{$package} = $dist; next };
    /^Depends: (.*)/ && do {
      my $dep = $1;
      $dep =~ s/\(.*?\)//g;
      $dep =~ s/\s//g;
      my @dep = split /[|,]/,$dep;
      $depends{$package} = [ @{$depends{$package}}, @dep ];
      
      map { $dependedon{$_} = 1 } @dep;
    };
    /^Provides: (.*)/ && do {
      my $dep = $1;
      $dep =~ s/\s//g;
      my @dep = split /,/,$dep;
      foreach(@dep) {
        if( defined $depends{$_} ) { $depends{$_} = [ @{$depends{$_}}, $package ] }
        else                       { $depends{$_} = [ $package ]; $score{$_} = 0; $dist{$_} = 'virtual' }
      }
      $dependedon{$package} = 1;
    };
    /^Size: (.*)/ && do { $size{$package} = $1 };
  }

  close FH;
}

open( FH, "<all-popcon-results.txt" ) || die "Couldn't open popcon results 'all-popcon-results.txt' ($!)\n";

while(<FH>)
{
  my @F = split /\s+/;
  
  $score{$F[0]} = $F[1];
}

close FH;

{
  my @bad = grep { !defined $depends{$_} } sort keys %dependedon;
  
  print "Packages depended on that do not exist in these section:\n", join("", map { "$_\n" } @bad ), "\n";

  map { $dist{$_} = 'missing'; $score{$_} = -1; $depends{$_} = [] } @bad;
}

foreach( keys %depends )
{
  my @x = @{$depends{$_}};

#  print "$_ => ",join(":",@x),"\n";
    
  @x = map  { $_->[0] }
       sort { $b->[1] <=> $a->[1] }
       map  { [ $_, $score{$_} ] } @x;
       
  $depends{$_} = [ @x ];
}

# Uncomment for more info
#print "=" x 50, "\n";
#print "List of packages(score) and absolute dependencies\n";
#
#foreach( sort keys %depends )
#{
#  print "$_($score{$_}) => ".join(",",@{$depends{$_}})."\n";
#}

print "=" x 50, "\n";
print "Output package list in optimal (hopefully) order with scores\n";
print "Num  Package_Name             Score Size__ Accumulated_Size\n";

map { my $a = $_; map { $score{$a} += $score{$_} } @{$depends{$a}} } grep { /^task-/ } keys %depends;
map { $score{$_} += 10000 } grep { /^task-/ } keys %depends;

my @list = map  { $_->[0] }
           sort { $b->[1] <=> $a->[1] }
           map  { [ $_, $score{$_} ] } keys %depends;
           
my %done;
my $sum = 0;
my $count = 1;

$| = 1;

GenerateList( @list );

sub GenerateList
{
  my $p;

  for(;;)
  {
    do {
     $p = shift;
    } while( defined($p) and $done{$p} );

    return if !defined $p;
  
    $done{$p} = 1;
  
    GenerateList( @{$depends{$p}} );
    
    next unless $output{$dist{$p}};
    
    my $size = (defined($size{$p})?((($size{$p}+100)>>11)+1)*2:0);
    $sum += $size;
    printf "%4d %-24s %5d %6d %6d\n",$count++,$dist{$p}."/".$p,$score{$p},$size,$sum;
  }
}
