package Mkcd::Disc;

my $VERSION = '0.0.2';

use strict;
use File::Path;
use Mkcd::Functions;
use Mkcd::Tools qw(du);

=head1 NAME

Disc - mkcd disc functions

=head1 SYNOPSYS

    require Mkcd::Disc;

=head1 DESCRIPTION

C<Mkcd::Disc> include the mkcd disc handling subroutines.

=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,
	   functions	=> new Mkcd::Functions($config)
	  }, $class;
}

# FIXME must add space for synthesis, however they are negligeable compared to hdlist. Only
# a pb with very small CD.

sub guessHdlistSize{
    my ($class,$group,$size,$cdsize,$lists,$discsFiles) = @_;
    my $FACTOR = 125;
    my $SynFACTOR = 90;
    my $depsRep = "$config->{tmp}/$class->{config}{name}/$group->{depsrep}";
    print {$config->{LOG}} "guessHdlistSize: depsRep $depsRep\n";
    # FIXME heuristic for hdlist size on installation disc, (RPMS size / $FACTOR) per discs
    my $depsSize = du("$depsRep");
    my $instdisc = $group->{installDisc};
    my $sz;
    # keeping curdone outside the list loop could correct the mis value if multiple reps on one discs
    my %curdone;
    my @notdone;
    foreach my $list (keys %{$group->{list}}){
	if ($config->{list}[$list]{auto}){
	    if ($config->{list}[$list]{cd}){
		my $tsize = ($config->{discsize}/$FACTOR) * $config->{list}[$list]{cd}; 
		$sz += $tsize < $depsSize ? $tsize : $depsSize;
	    }else {
	       	$sz += $depsSize
	    }
	}else {
	    my $ok;
	    my $listsize = $group->{listsize}{$list}{rpm};
	    foreach my $rd (@{$group->{list}{$list}{rpm}}){
		my ($cdrep,undef,undef,$opt) = @$rd;
		if ($opt->{nodeps}) { $ok = 1; next }
		$curdone{$cdrep} and next;
		$curdone{$cdrep} = 1;
		if ($lists->{$cdrep}){
		    if ($listsize > $cdsize->[$cdrep]){
			$sz += $cdsize->[$cdrep] / $FACTOR;
			$listsize -= $cdsize->[$cdrep];
		    }else{
			$sz += $listsize / $FACTOR;
			last
		    }
		}
	    }
	    $ok and push @notdone, $list	
	}
    }
    print {$config->{LOG}} "guessHdlistSize: reserving ";
    if ($depsSize < $sz){ 
	print {$config->{LOG}} "$depsSize";
	$size->{disc}[$instdisc] += $depsSize;
	if ($config->{disc}[$instdisc]{function}{data}{installation}[1]{synthesis}) { $size->{disc}[$instdisc] += $depsSize / $SynFACTOR }
    } else { 
	print {$config->{LOG}} "$sz"; 
	$size->{disc}[$instdisc] += $sz ;
	if ($config->{disc}[$instdisc]{function}{data}{installation}[1]{synthesis}) { $size->{disc}[$instdisc] += $depsSize / $SynFACTOR }
    }
    print {$config->{LOG}} " (new size $size->{disc}[$instdisc]) on disc $instdisc ($depsSize/$sz) for dependencies files\n";
    @notdone or return 1;
    my $sz;
    foreach my $list (@notdone){
	foreach my $rd (@{$group->{list}{$list}{rpm}}){
	    my ($cd,$rep,$repopt,$opt) = @$rd;
	    if ($lists->{$cd} == 1){
		$sz += du("$class-{config}{topdir}/build/$class->{config}{name}/$cd/$class->{config}{disc}[$cd]{function}{data}{dir}{$rep}")
	    }elsif ($lists->{$cd} == 2){
		foreach my $rpm (keys %{$discsFiles->[$cd]{$rep}{$list}}){
		    $sz += du("$discsFiles->[$cd]{$rep}{$list}{$rpm}/$rpm.rpm")
		}
	    }
	}
    }
    $sz /= $FACTOR;
    print {$config->{LOG}} "guessHdlistSize: reserving ";
    print {$config->{LOG}} "$sz"; 
    $size->{disc}[$instdisc] += $sz;
    if ($config->{disc}[$instdisc]{function}{data}{installation}[1]{synthesis}) { $size->{disc}[$instdisc] += $sz / $SynFACTOR }
    print {$config->{LOG}} " (new size $size->{disc}[$instdisc]) on disc $instdisc ($sz) for extra dependencies files\n"
}		

sub getBuiltDiscs{
    my ($class, $lists, $group, $discsFiles) = @_;
    foreach my $l (keys %{$group->{list}}){
	my @rpmlist;
	ref $group->{list}{$l}{rpm} and push @rpmlist, @{$group->{list}{$l}{rpm}};
	ref $group->{list}{$l}{srpm} and push @rpmlist, @{$group->{list}{$l}{srpm}};
	for (my $i; $i < @rpmlist; $i++){
	    my ($cd,$rep,$repopt) = @{$rpmlist[$i]};
	    $lists->{$cd} == 1 or next;
	    my $dir = "$class->{config}{topdir}/build/$class->{config}{name}/$cd/$class->{config}{disc}[$cd]{function}{data}{dir}{$rep}";
	    #
	    # FIXME maybe need to unshift instead of push
	    #
	    $repopt->{source} or push @{$class->{config}{list}[$l]{packages}}, [$dir];
	    $class->{config}{list}[$l]{disc}{$cd}{$rep}{done} = 1;
	    print {$config->{LOG}} "getBuiltDiscs: get files from $dir\n";
	    local *A; opendir A,$dir;
	    foreach (readdir A){
		/(.*)\.rpm/ or next;
		# FIXME need to check if it is well placed in getList function
		# $group->{done}{$rpm} = $group->{orderedrep}{"$cd/$rep"};
		$discsFiles->[$cd]{$rep}{$l}{$1} = $dir
	    }
	}
    }
    1
}

sub makeDiscs {
    my ($class, $fixed, $lists, $cds, $size, $mkisos, $discsFile, $cdfile) = @_;
    my $dir;
    my $name = $class->{config}{name};
    my $topdir = $class->{config}{topdir};
    my $tmp = "$config->{tmp}/build/$name";

    if (!$class->{config}{nolive}){
	$dir = "$topdir/build/$name";
	-d "$dir" or mkpath "$dir";
	-d $tmp or mkpath $tmp;
    }else{
	$dir = "$config->{tmp}/build/$name";
	-d "$dir" or mkpath "$dir";
    }
    print {$config->{LOG}} "makeDiscs: Discs @$cds TOPDIR $dir\n";
    foreach my $i (@$cds){
	$lists->{$i} > 1 or next;
	my $cd = $class->{config}{disc}[$i];
	if (!$fixed){
	    print {$config->{LOG}} "makeDisc: Fixed part of disc $i\n";
	    if ($class->{config}{nolive}){
		print {$config->{LOG}} "makeDisc: removing $dir/$i.list\n";
		-f "$dir/$i.list" and unlink "$dir/$i.list";
		print {$config->{LOG}} "makeDisc: removing $dir/$i\n";
		rmtree "$dir/$i";
	    }else{
	        -d "$tmp/$i" or mkpath "$tmp/$i";
		rmtree "$topdir/build/$name/$i";
		rmtree "$topdir/build/$name/first/$i"
	    }
	}else {print {$config->{LOG}} "Finalizing disc $i\n"}
	my $sz;
	for (my $j; $j < @{$cd->{steps}}; $j++){
	    my $name = $cd->{steps}[$j][0];
	    print {$config->{LOG}} "makeDiscs: $name ($fixed)\n";
	    if (defined $Mkcd::Functions::{$name}) { $sz += &{$Mkcd::Functions::{$name}}($class->{disc}->{functions},$cd->{steps}[$j],$dir,$fixed,$class->{config}{nolive},$i,$cd,$cdfile,$lists,$mkisos,$discsFile)}
	    else {print {$config->{LOG}} "ERROR: unrecognized function name $name\n"}
	    print {$config->{LOG}} "SIZE ($name) $sz\n";
	}
	if ($class->{config}{nolive}){
	    print {$config->{LOG}} "SIZE $size->{disc}[$i] + $sz\n";
	    $size->{disc}[$i] += $sz
	}else{
	    $size->{disc}[$i] = du("$dir/$i") + $sz
	}
	print {$config->{LOG}} "disc $i ($dir/$i) size: $size->{disc}[$i] ($sz)\n";
	my $mkisoopt = $class->{config}{mkisoopt};
	if ($fixed) {
	    my $isodir = $class->{config}{isodir} ? $class->{config}{isodir} : "$topdir/iso/$name";
	    if ($class->{config}{nolive}){
		$mkisos->[$i] = "mkisofs $mkisoopt -graft-points " . (-f "$dir/$i.list" ? " -path-list $dir/$i.list " : "") . " -V $cd->{serial} -o $isodir/$i-$name.iso $mkisos->[$i]"
	    }else{
		if ($mkisos->[$i]) { $mkisos->[$i] = "mkisofs $mkisoopt -V $cd->{serial} -o $isodir/$i-$name.iso $mkisos->[$i]"}
		else { $mkisos->[$i] = qq|mkisofs $mkisoopt -V $cd->{serial} -o "$isodir/$i-$name".iso "$dir/$i"|}
	    }
	}
    }
    !$fixed and return 1;
    if (!$class->{config}{noiso}){
	-d "$topdir/iso/$name" or mkpath "$topdir/iso/$name"; 
	foreach my $i (@$cds){
	    $lists->{$i} > 1 or next;
	    print {$config->{LOG}} "MKISOFS disc $i $mkisos->[$i]\n";
	    if (-x "/usr/bin/mkisofs"){
		my $err = system $mkisos->[$i];
		$err or print {$config->{LOG}} "ERROR: disc $i $mkisos->[$i] failed ($!)\n";
		$size->{disc}[$i] = du("$topdir/iso/$name/$i-$name.iso")
	    }else{
		print {$config->{LOG}} "WARNING: mkisofs is not installed on your system, to build the ISOs, install mkisofs and type the following command:
$mkisos->[$i]\n "
	    }
	}
    }
    1
}

sub checkSize{
    my ($class, $n,$size,$cdsize,$rejected) = @_;
    my $ok;
    for (my $i; $i < @{$size->{disc}}; $i++) {
	$size->{disc}[$i] or next;
	my $origcdsize = $class->{config}{disc}[$i]{size};
	if ($size->{disc}[$i] > $origcdsize) {
	    my $d = ($size->{disc}[$i] - $cdsize->[$i]);
	    if ($d > 0) { 
		$ok = 0;
		$cdsize->[$i] -= $d;
		print {$config->{LOG}} "ERROR: disc $i is too big ($size->{disc}[$i] > $origcdsize (new disc size $cdsize->[$i])\n" }
	    }elsif ($rejected){
		my $d = ($cdsize->[$i] - $size->{disc}[$i]);
		if ($d > $origcdsize/1000) { 
		    $ok = 0;
		    $cdsize->[$i] += $d;
		    print {$config->{LOG}} "ERROR: disc $i is too small ($size->{disc}[$i] < $origcdsize (new disc size $cdsize->[$i])\n" }
	    }
     	}
	return $ok
}

1
