package Mkcd::Group;

my $VERSION = '1.0.0';

use strict;
use File::NCopy qw(copy);       
use File::Path;
use Mkcd::Disc;
use Mkcd::List;
use Mkcd::Tools qw(cleanrpmsrate printTable printDiscsFile readBatchFile printBatchFile);
use Mkcd::Package qw(genDeps getRPMsKeys getSize);

=head1 NAME

Group - mkcd module

=head1 SYNOPSYS

    require Mkcd::Group;

=head1 DESCRIPTION

C<Mkcd::Group> include the mkcd high level disc building routines.

=head1 SEE ALSO

mkcd

=head1 COPYRIGHT

Copyright (C) 2000,2001 MandrakeSoft <warly@mandrakesoft.com>

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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

=cut

my $config;

sub new {
    my ($class, $conf) = @_;
    $config = $conf;
    bless {
	    config      => $conf,
	    list	=> new Mkcd::List($conf),
	    disc 	=> new Mkcd::Disc($conf)
       }, $class;
}

#
# group structure
#
# $group[group number]{list}{rpm/srpm} = { list => [[cd, repname, {options}],[], ...,[]] }
#
## 2002 03 14 deprecated
## $group[group number]{sourcerep} = { list => [[ srpm cd, srpm repname], [srpm cd 2, srpm repname 2], ..., [srpm cd n, srpm repname n]] }
#
# $group[group number]{params} = rpmtools::params
#
# $group[group number]{rpmsratepath} = rpmsrate path
#
# $group[group number]{rpmsrate} = { rpmsrate }
#
# $group[group number]{size} = { rpm_name => [filesize, list number, directory], ... } 
#
# $group[group number]{listsize}{rpm} = { list => total rpm size, ... } 
#
# $group[group number]{score} = [ score weight ]
#
# $group[group number]{scoredlist} = { rpm_name => score }
#
# $group[group number]{maxsize} = rpm maxsize
#
# $group[group number]{depsrep} = deps repository name
#
# $group[group number]{depslistid} = [ depslist id ]
#
# $group[group number]{pkgdeps} = { package_name => [depslist dependencies ] }
# 
# $group[group number]{revdeps} = [ reversed depslist ]
#
# $group[group number]{lang} = { locale1 => 1, locale2 => 1}
#
# $group[group number]{filelist} = [FILELIST]
#
# $group[group number]{listrpm} = { list => [ rpm ] }
#
# $group[group number]{brokendeps} = { rpm_depending_on_non_listed_locales => 1 , rpm_which_deps_are_broken => 2 }
#
# $group[group number]{installDisc} = install disc for this group
#
# $group[group number]{discdeps} = { cd => { cds it depends on ] }
#
# $group[group number]{missingdeps} = { rpm => [ missing dependencies ] }
#
# $group[group number]{pkgrate} = { rpm => rpmsrate_increase }
#
# $group[group number]{done} = { rpm => rep number }
#
# $group[group number]{globrpm} = [ "path1/rpm1" ... "pathn/rpmq" ]
#
# $group[group number]{srpmname} = srpm-version-release
#
# $group[group number]{orderedrep}{rpm/srpm} = { "rep_name" => num }
#
# $group[group number]{maxrep} = max ordered rep_name number
# 
# $group[group number]{listmaxrep}{rpm/srpm}{list} = max ordered rep_name number for list list
# 
# $group[group number]{nodeps} = { list => 1}
#
# 0  {list}
# 1  {sourcerep}
# 2  {params}
# 3  {rpmsratepath}
# 4  {rpmsrate}
# 5  {size}
# 6  {score}
# 7  {scoredlist}
# 8  {maxsize}
# 9  {depsrep}
# 10 
# 11 {depslistid}
# 12 {pkgdeps}
# 13 {revdeps}
# 14 {lang}
# 15 {filelist}
# 16 {listrpm}
# 17 {brokendeps}
# 18 {installDisc}
# 19 {discdeps}
# 20 {missingdeps}
#
#
#  FIXME
#
# Weigh should be put in the first loop with list so that generic
# groups without installation can get scoring. At present the implementation
# prevent from using the -o option with generic and as a consequence
# generic groups will be sorted with (1,1,0) (no install means no rpmsrate)
#

sub getGroups {
    my ($config,$lists) = @_;
    my @list;
    my %cd;
    my %done;
    my %list;
    my %repname;
    print {$config->{LOG}} "getGroups\n";
    foreach my $i (keys %{$lists}){
	$config->{verbose} and print {$config->{LOG}} "getGroups: disc $i\n";
	$cd{$i} = 1;
	ref $config->{disc}[$i]{fastgeneric} or next;
	my @l = @{$config->{disc}[$i]{fastgeneric}};
	foreach (@l){
	    $config->{verbose} and print {$config->{LOG}} "getGroups: list $_->[1]{list} repname $_->[1]{repname} options (", keys %{$_->[1]} ,")\n";
	    my $idx;
	    if ($_->[1]{source}) { 
# 2002 03 14 deprecated
#		$_->[1]{score} = $_->[1]{priority} ? $_->[1]{priority} + $config->{discMax} : $config->{disc}[$i]{name};	
		push @{$list[$_->[1]{list}][1]}, [$i, $_->[1]{repname}, $_->[1], {}]
	    } else { 
		$idx = push @{$list[$_->[1]{list}][0]}, [$i, $_->[1]{repname}, $_->[1], {}]
	    }
	    push @{$repname{$i}{$_->[1]{repname}}}, [ $_->[1]{list}, $idx - 1 ];
	    $config->{verbose} and print {$config->{LOG}} "getGroups: cd $i repname $_->[1]{repname} list $_->[1]{list}\n";
	    $list{$_->[1]{list}} = 1
	}
    }
    my @group;
    my $g;
    my %donerep;
    foreach my $i (keys %{$lists}){
	my $t = $config->{disc}[$i]{function}{data}{installation};
	$config->{verbose} and print {$config->{LOG}} "getGroups: disc $i ($t)\n";
	ref $t and do {
	    print {$config->{LOG}} "getGroups: install disc for group $g => ($i)\n";
	    $group[$g]{installDisc} = $i;
	    $group[$g]{options} = $t->[1];
	    $group[$g]{score} ||= $t->[1]{score} || [1,1,1];
	    ($group[$g]{maxrep}{rpm},$group[$g]{maxlist}{rpm}) = addRepList("rpm",$group[$g],$g,$t->[1]{rpmsdir},$donerep{$g},\%done,\%list,\%cd,\%repname,$i,\@list);
	    ($group[$g]{maxrep}{srpm},$group[$g]{maxlist}{srpm}) = addRepList("srpm",$group[$g],$g,$t->[1]{srpmsdir},$donerep{$g},\%done,\%list,\%cd,\%repname,$i,\@list);
	    $group[$g]{orderedlist}{rpm} ||= [];
	    foreach (@{$group[$g]{orderedlist}{rpm}}){
		$group[$g]{list}{$_}{srpm} ||= []
	    }
	    $group[$g]{discdeps}{$i} ||= {};
	    $group[$g]{rpmsratepath} ||= $t->[1]{rpmsrate} || "$t->[1]{install}/Mandrake/base/rpmsrate";
	    print {$config->{LOG}} "getGroups: using $group[$g]{rpmsratepath} as rpmsrate file\n";

	    $group[$g]{list} and $group[$g]{depsrep} = join '-', keys %{$group[$g]{list}};
	    print {$config->{LOG}} "getGroups: $group[$g]{depsrep} defined as deps file directory\n";
	    if (ref $t->[1]{lang}) { 
		foreach (@{$t->[1]{lang}}) {$group[$g]{lang}{$_} = 1 }
	    }
	    $group[$g]{orderedlist}{srpm} ||= [];
	    print {$config->{LOG}} "getGroups: ordered rpm list for group $g: @{$group[$g]{orderedlist}{rpm}}\n";	
	    print {$config->{LOG}} "getGroups: ordered srpm list for group $g: @{$group[$g]{orderedlist}{srpm}}\n";	
	    $g++;
	}
    }
    # 2002 03 14 sources are now handled as the same level as RPMs
    #
    if (0){
	# complete the groups
	for (my $i; $i < @group; $i++){
	    foreach my $l (keys %{$group[$i]{list}}){
		# add srpm cds as belonging to this group
		foreach (@{$group[$i]{sourcerep}{$l}}){ print {$config->{LOG}} "getGroups: adding sources group $i handle disc $_->[0]\n";$group[$i]{discdeps}{$_->[0]} ||= {}}
		foreach (@{$list[$l][0]}){
		    $_->[2]{source} or next;
		    $config->{verbose} and print {$config->{LOG}} "getGroups: adding sources list $l cd $_->[0] repname $_->[1]\n";
		    if (!$done{$_->[0]}{$_->[1]}){
			$group[$i]{discdeps}{$_->[0]} ||= {};
			print {$config->{LOG}} "getGroups: adding sources group $i handle disc $_->[0]\n";
			push @{$config->{list}[$l]{disc}{$_->[0]}{$_->[1]}{master}}, $g;
			push @{$group[$i]{list}{$l}}, $_;
			$done{$_->[0]}{$_->[1]}++
		    }
		}
	    }
	}
    }
    foreach (keys %list){
	$config->{verbose} and print {$config->{LOG}} "getGroups: searching alone groups list $_\n";
	if ($list{$_} == 1){ 
	    print {$config->{LOG}} "WARNING getGroups: list $_ does not belong to any installation disc, setting alone groups\n";
	    getAlone("rpm",$list[$_][0],$group[$g],$g,\%done);
	    getAlone("srpm",$list[$_][1],$group[$g],$g,\%done);
	    $group[$g]{score} = [1,1,1];
	    $group[$g]{depsrep} = $_;
	    $config->{verbose} and print {$config->{LOG}} "getGroups: searching alone groups list $_ source $list[$_][1] group $group[$g]{sourcerep}{$_}\n";
	    $list{$_}++;
	    $g++
	}
    }
    foreach my $i (keys %{$lists}){
	$done{$i} and next;
	$config->{verbose} and print {$config->{LOG}} "getGroups: searching alone disc disc $i does not handled by any group, setting alone group\n";
	$group[$g]{discdeps}{$i} ||= {};
	$g++
    }
    
    $config->{verbose} and printTable(\@group);
    \@group
}

sub getAlone{
    my ($type,$list,$group,$g,$done) = @_;
    my $num = 1;
    $list or return;
    foreach my $l (@{$list}){
	my ($ls,$cd,$rep) = @$l;
	$config->{verbose} and print {$config->{LOG}} "getGroups: searching alone groups list @$l (list $_)\n";
	push @{$config->{list}[$_]{disc}{$cd}{$rep}{master}}, $g;
	push @{$group->{list}{$type}{$_}}, $l;
	$group->{orderedrep}{$type}{"$cd/$rep"} = $num++;
	$done->{$cd}{$rep}{$ls}++;
	print {$config->{LOG}} "getGroups: searching alone groups group $g handle disc $l->[0]\n";
	$group->{discdeps}{$l->[0]} ||= {};
    }
}

sub addRepList{
    my ($type,$group,$g,$replist,$donerep,$done,$list,$disc,$repname,$i,$listTable) = @_;
    my $num = 1;
    my $lnsort = 1;
    foreach (@$replist){
	my ($cdlist,$cd,$name) = ($_->[0],$_->[1],$_->[2]);
	my $opt = $_->[3] || {};
	$config->{verbose} and print {$config->{LOG}} "getGroups: group $g cd $cd repname $name list $cdlist\n";
	$donerep->{$type}{$cd}{$name}{$cdlist} and print {$config->{LOG}} "ERROR getGroups: $cd/$name/$cdlist is defined multiple time for group $g, ignoring\n" and next;
	$donerep->{$type}{$cd}{$name}{$cdlist} = 1;
	$disc->{$cd} or print {$config->{LOG}} "ERROR getGroups: disc $cd not in list, ignoring\n" and next;
	my $ln = $repname->{$cd}{$name};
	$ln or print {$config->{LOG}} "ERROR getGroups: $name on disc $cd does not exist\n" and next;
	$group->{orderedrep}{$type}{"$cd/$name"} = $num++;
	$cd != $i and $group->{discdeps}{$i}{$cd}++;
	$cd != $i and print {$config->{LOG}} "getGroups: group $g handle disc $i\n";
	foreach my $l (@$ln){
	    my ($ls,$idx) = @$l;
	    next if $cdlist && $cdlist != $ls;
	    if ($group->{listmaxrep}{$type}{$ls} < $group->{orderedrep}{$type}{"$cd/$name"}) { $group->{listmaxrep}{$type}{$ls} = $group->{orderedrep}{$type}{"$cd/$name"} }
	    $group->{list}{$ls}{$type} or push @{$group->{orderedlist}{$type}}, $ls;	
	    foreach my $lst (@{$group->{orderedlist}{$type}}) { $group->{listmatrix}{$type}{$ls}{$lst} = 1 }
	    if (!$group->{listsort}{$ls}{$type}) { $group->{listsort}{$ls}{$type} = $lnsort++ };
	    print {$config->{LOG}} "getGroups: list sorting list $ls ($group->{listsort}{$type}{$ls})\n";
	    push @{$group->{list}{$ls}{$type}}, [$cd, $name, $listTable->[$ls][0][$idx][2], $opt];
	    if ($opt->{fixed}){
		push @{$config->{list}[$ls]{disc}{$cd}{$name}{master}}, $g		
	    }else{
		# this group is the master for this rep
		unshift @{$config->{list}[$ls]{disc}{$cd}{$name}{master}}, $g
	    }
	    $list->{$ls}++;
	    $done->{$cd}{$name}{$ls}++;
	}	
    }
    return ($num,$lnsort)
}

sub preCheck{
    # TODO
    # may not be necessary
}

sub orderGroups{
    my ($config,$groups,$lists,$acds) = @_;
    my @metagroups;
    my @groupmeta;
    my $ok;
    # FIXME This algo can create empty metagroups
    while (!$ok){
	print {$config->{LOG}} "orderGroups: ordering metagroups\n";
	$ok = 1;
	for (my $i; $i < @$groups; $i++){
	    if ($groups->[$i]{installDisc}){
		$lists->{$groups->[$i]{installDisc}} == 2 or next
	    }
	    print {$config->{LOG}} "Group $i (install disc $groups->[$i]{installDisc})\n";
	    foreach my $list (keys %{$groups->[$i]{list}}){
		foreach my $type (keys %{$groups->[$i]{list}{$list}}){
		    foreach my $rep (@{$groups->[$i]{list}{$list}{$type}}){
			my ($cd,$r) = ($rep->[0],$rep->[1]);
			$lists->{$cd} == 2 or next;
			my $og = $config->{list}[$list]{disc}{$cd}{$r}{master}[0];
			print {$config->{LOG}} "Master of disc $cd/$r = $og\n";
			if ($og != $i && $groupmeta[$i] == $groupmeta[$og]){ $ok = 0;$groupmeta[$i] = $groupmeta[$og] + 1 }
		    }
		}
	    }
	}
    }
    for (my $i; $i < @$groups; $i++){
	if ($groups->[$i]{installDisc}){
	    $lists->{$groups->[$i]{installDisc}} == 2 or next
	}
	print {$config->{LOG}} "orderGroups: group $i metagroup $groupmeta[$i]\n";
	push @{$metagroups[$groupmeta[$i]][0]}, $groups->[$i];
    }
    my %donedisc;
    foreach (@metagroups){
	my %cd;
	my %cdg;
	my $i = 1;
	foreach (@$acds) { $cd{$_} = $i++ }
	my $grps = $_->[0];
	my $loop;
	my $ok = 0;
	$_->[1] = [];
	while (!$ok && !$loop){
	    $ok = 1;
	    foreach my $g (@{$grps}){
		print {$config->{LOG}} "orderGroups: discs ", keys %{$g->{discdeps}},"\n";
		foreach my $cd (keys %{$g->{discdeps}}){
		    $donedisc{$cd} and next;
		    print {$config->{LOG}} "orderGroups: disc $cd\n";
		    $lists->{$cd} >= 1 or next;
		    $cdg{$cd} = {};
		    if (ref $g->{discdeps}{$cd}){
			foreach (keys %{$g->{discdeps}{$cd}}){
			    $donedisc{$_} and next;
			    print {$config->{LOG}} "orderGroups: disc $cd => $_\n";
			    $cdg{$cd}{$_} and print {$config->{LOG}} "ERROR: orderGroups: loop in discs dependencies, taking manual order\n" and $loop = 1;
			    $cdg{$cd}{$_} = 1;
			    $cdg{$_} = {};
			    if ($cd{$cd} <= $cd{$_}){ 
				$cd{$cd} = $cd{$_} + 1;
				$ok = 0
			    }
			}
		    }
		}
	    }
	}
	if ($loop){
	    foreach my $c (@$acds) { $cdg{$c} and $lists->{$c} == 2 and push @{$_->[1]}, $c and $donedisc{$c} = 1} 
	}else{
	    my @scds = sort { $cd{$a} <=> $cd{$b} }  keys %cdg;
	    foreach my $c (@scds) { $lists->{$c} == 2 and push @{$_->[1]}, $c and $donedisc{$c} = 1} 	
	}
	print {$config->{LOG}} "orderGroup: disc sorting @{$_->[1]}\n"
    }
    # add alone discs
    my @cd;
    foreach (keys %donedisc){
	$donedisc{$_} or push @cd, $_ 
    }
    @cd and push @metagroups, [0,\@cd];
    \@metagroups
}

sub getGroupReps{
    my ($config,$groups) = @_;
    my @reps;
    my @sreps;
    foreach my $listnumber (keys %{$groups->{list}}){
	my $ok;
	foreach (@{$groups->{list}{$listnumber}{rpm}}){
	    !$_->[3]{nodeps} and $ok = 1
	}
	if (!$ok) { $groups->{nodeps}{$listnumber} = 1; next }
	print {$config->{LOG}} "getGroupReps list $listnumber\n";
	foreach (@{$config->{list}[$listnumber]{packages}}) {
	    print {$config->{LOG}} "$_->[0] ($_->[1])\n";
	    unshift @reps, $_->[0];
	    unshift @sreps, $_->[1] 
	}
    }
    (\@reps,\@sreps)
}

sub makeWithGroups{
    my ($class, $lists, $acds) = @_;
    my $config = $class->{config};
    my $metagroups = orderGroups($config,getGroups($config,$lists),$lists,$acds);

    foreach (keys %{$lists}){
	print {$config->{LOG}} "2 LIST $_ => $lists->{$_}\n"
    }

    my @discsFiles;
    my (@cdsize,%size);
    for(my $i; $i < @{$config->{disc}}; $i++) { $cdsize[$i] = $config->{disc}[$i]{size} }
    foreach (@{$metagroups}){
	my $groups = $_->[0];
	print {$config->{LOG}} "makeWithGroups: Group listing $_ (@{$_->[1]} -- $groups)\n"
    }
    foreach my $g (@{$metagroups}){
	my $cds = $g->[1];
	my $groups = $g->[0];
	print {$class->{config}->{LOG}} "Group: $g (@{$g->[1]} -- $groups)\n";
	# FIXME ordering metagroups can lead to empty groups with the -l option
	$groups or next;

	my @buildlist;
	my @rpmlist;
	my (@log,@groupok,@mkisos);
	$class->{disc}->makeDiscs(0,$lists,$cds,\%size,\@mkisos,\@discsFiles);

	for (my $i; $i < @$groups; $i++){
	    print {$config->{LOG}} "Get already built discs lists\n";
	    $groups->[$i]{done} = {};
	    $class->{disc}->getBuiltDiscs($lists, $groups->[$i], \@discsFiles);
	    $config->{verbose} and print {$config->{LOG}} "GROUP $i\n";
	    my ($reps,$sreps) = getGroupReps($config,$groups->[$i]);
	    @$reps or next;
	    $config->{verbose} and print {$config->{LOG}} "genDeps\n";
	    $groups->[$i]{params} = genDeps("$config->{tmp}/$config->{name}/$groups->[$i]{depsrep}",$reps,$config->{deps},$config->{verbose},$config->{tmp}) or print {$config->{LOG}} "ERROR: genDeps failed\n" and return 0;

	    #print {$config->{LOG}} "PARAMS 1\nKEYS 1 ",join "\n KEYS 1 ", keys %{$groups->[$i]{params}{info}},"\n";
	    
	    $config->{verbose} and print {$config->{LOG}} "getRPMsKey\n";	
	    $groups->[$i]{rpmkey} = getRPMsKeys(0,"$config->{tmp}/$config->{name}/$groups->[$i]{depsrep}/hdlist.cz");
	    #print {$config->{LOG}} "PARAMS 1\nRPMKEYS 1 ",join "\n RPMKEYS 1 ", keys %{$groups->[$i]{rpmkey}{rpm}},"\n";
	    $config->{verbose} and print {$config->{LOG}} "getSize", keys %{$groups->[$i]{list}},"\n";
	    my $redeps = getSize($groups->[$i],$config,$config->{verbose}) or print {$config->{LOG}} "ERROR: getSize failed\n" and return 0;
	    if ($redeps == 2){ 
		print {$config->{LOG}} "Rebuilding depslist\n" and $groups->[$i]{params} = genDeps("$config->{tmp}/$config->{name}/$groups->[$i]{depsrep}",$reps,1,$config->{verbose},$config->{tmp});
		#print {$config->{LOG}} "PARAMS 2\nKEYS 2 ",join "\n KEYS 2 ", keys %{$groups->[$i]{params}{info}},"\n";
		$groups->[$i]{rpmkey} = getRPMsKeys(0,"$config->{tmp}/$config->{name}/$groups->[$i]{depsrep}/hdlist.cz");
		#print {$config->{LOG}} "PARAMS 2\nRPMKEYS 2 ",join "\n RPMKEYS 2 ", keys %{$groups->[$i]{rpmkey}{rpm}},"\n";
		getSize($groups->[$i],$config,$config->{verbose}) or print {$config->{LOG}} "ERROR: getSize failed\n" and return 0;
	    }	

	    $class->{disc}->guessHdlistSize($groups->[$i],\%size,\@cdsize,$lists,\@discsFiles);

	    $groups->[$i]{revdeps} = $class->{list}->reverseDepslist($groups->[$i]);

	    ($groups->[$i]{filelist},my $norpmsrate) = $class->{list}->getList($groups->[$i],\@discsFiles);

	    if ($groups->[$i]{rpmsratepath}){ 
		my $outputdir = "$config->{tmp}/build/$config->{name}/$groups->[$i]{installDisc}/Mandrake/base/";
		-d $outputdir or mkpath $outputdir;
		my $output = "$outputdir/rpmsrate";
	        $config->{verbose} and print {$config->{LOG}} "cleanrpmsrate $groups->[$i]{rpmsratepath} -> $output\n";
		$groups->[$i]{rpmsrate} = cleanrpmsrate($groups->[$i]{rpmsratepath},$output,$norpmsrate,@$reps) or print {$config->{LOG}} "ERROR: cleanrpmsrate failed\n";
	        $groups->[$i]{options}{rpmsrate} = $output;
	    }

	    print {$config->{LOG}} "buildList group $i\n";
	    $rpmlist[$i] = $class->{list}->buildList($groups->[$i]) or return 0;

	    $class->{list}->scoreList($groups->[$i]) or return 0;
	    $class->{list}->autodeps($groups->[$i],$rpmlist[$i]);

	    foreach my $l (keys %{$rpmlist[$i]}) { 
		my @force;
		my @superforce;
		my @limit;
		my @b;
		foreach (keys %{$rpmlist[$i]{$l}}){
		    $_ or print {$config->{LOG}} "ERROR: empty rpmlist key ($rpmlist[$i]{$l}{$_}) KEYS ", keys %{$rpmlist[$i]{$l}{$_}}," \n";
		    if (!$config->{nodeps} && !$groups->[$i]{options}{nodeps} && /basesystem/) { 
			push @superforce, [$_, $rpmlist[$i]{$l}{$_}, $groups->[$i]{scorelist}{$_}]
		    }elsif ($rpmlist[$i]{$l}{$_}{force}) { 
			push @force, [$_, $rpmlist[$i]{$l}{$_}, $groups->[$i]{scorelist}{$_}]
		    }elsif ($rpmlist[$i]{$l}{$_}{limit}){
			push @limit, [$_, $rpmlist[$i]{$l}{$_}, $groups->[$i]{scorelist}{$_}]
		    }else { push @b, [$_, $rpmlist[$i]{$l}{$_}, $groups->[$i]{scorelist}{$_}]}
		}
		$buildlist[$i]{$l} = [sort { $a->[2] <=> $b->[2] } @b];
		unshift @{$buildlist [$i]{$l}}, @limit;
		push @{$buildlist[$i]{$l}}, @force;
		push @{$buildlist[$i]{$l}}, @superforce
	    }
	}

	# FIXME it must have a cleaner manner to keep buildlist and do not have
	# to copy it.
	my @cb;
	for(my $i; $i < @buildlist; $i++){ 
	    foreach my $l (keys %{$buildlist[$i]}){ foreach (@{$buildlist[$i]{$l}}){ $config->{verbose} and print {$config->{LOG}} "MakeWithGroups: copying buildlist group $i list $l package $_->[0] ($_->[2])\n";push @{$cb[$i]{$l}}, $_}}}

	my ($diff,$rejected) = $class->{list}->buildDiscs($groups,\@cb,\@rpmlist,\@log,\@groupok,\%size,\@cdsize,$lists,$cds);
	my $logi;
	$diff or return 0;
	my $cd = $class->{list}->processDiff($groups,$diff,\@log,\@discsFiles);
	my $ok;
	$class->{disc}->makeDiscs(1,$lists,$cds,\%size,\@mkisos,\@discsFiles,$cd) or return 0;
	my $ok = $class->{disc}->checkSize(0,\%size,\@cdsize,$rejected);
	my $n;
	$ok = 1;
	while (!$ok){
	    $n++;
	    $ok = 1;
	    my @cb;
	    for(my $i; $i < @buildlist; $i++){ 
		foreach my $l (keys %{$buildlist[$i]}){ foreach (@{$buildlist[$i]{$l}}){push @{$cb[$i]{$l}}, $_}}}
		($diff,$rejected) = $class->{list}->buildDiscs($groups,\@cb,\@rpmlist,\@log,\@groupok,\%size,\@cdsize,$lists,$cds) or return 0;
		my $cd = $class->{list}->processDiff($groups,$diff,\@log,\@discsFiles);
		$class->{disc}->makeDiscs(2,$lists,$cds,\%size,\@mkisos,\@discsFiles,$cd) or return 0;
		$ok = $class->{disc}->checkSize($n,\%size,\@cdsize,$rejected);
		!$ok and print {$config->{LOG}} "ERROR: one or more disc are too big or too small, rebuilding lists\n";
		$n > 2 and print {$config->{LOG}} "ERROR: could not manage to build discs of correct size, exiting\n" and last
	}
	for (my $i; $i < @$groups; $i++){
	    foreach my $list (keys %{$groups->[$i]{list}}){
		foreach my $type (keys %{$groups->[$i]{list}{$list}}){
		    foreach (@{$groups->[$i]{list}{$list}{$type}}){
			$config->{list}[$list]{disc}{$_->[0]}{$_->[1]}{done} = 1
		    }
		}
	    }	
	}
    }
    printDiscsFile($config,\@discsFiles,$config->{print},$metagroups);
    $config->{printscript} and printBatchFile($config,\@discsFiles,$config->{printscript});
    1
}

1

#
# Changelog
#
# 2002 02 21
#
# add maxlistmaxrep value to group
#
# 2002 03 03 
#
# change size to an hash that contains disc size and rep size
#
# 2002 03 09
#
# make group{discrep} and hash not to have loop in disc dependencies when there are multiple repository on one CD
#
# 2002 03 14
#
# BIG change of group source handling
# 
# 2002 03 15
#
# use new source handling
