#**************************************************************
#  
#  Licensed to the Apache Software Foundation (ASF) under one
#  or more contributor license agreements.  See the NOTICE file
#  distributed with this work for additional information
#  regarding copyright ownership.  The ASF licenses this file
#  to you under the Apache License, Version 2.0 (the
#  "License"); you may not use this file except in compliance
#  with the License.  You may obtain a copy of the License at
#  
#    http://www.apache.org/licenses/LICENSE-2.0
#  
#  Unless required by applicable law or agreed to in writing,
#  software distributed under the License is distributed on an
#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
#  KIND, either express or implied.  See the License for the
#  specific language governing permissions and limitations
#  under the License.
#  
#**************************************************************



package installer::windows::media;

use installer::exiter;
use installer::files;
use installer::globals;
use installer::windows::idtglobal;

##############################################################
# Returning the diskid for the media table.
##############################################################

sub get_media_diskid
{
	my ($id) = @_;
	
	return $id;
}

##############################################################
# Returning the lastsequence for the media table.
##############################################################

sub get_media_lastsequence
{
	my ($fileref) = @_;
	
	return $fileref->{'sequencenumber'};
}

##############################################################
# Returning the diskprompt for the media table.
##############################################################

sub get_media_diskprompt
{
	return 1;
}

##############################################################
# Returning the cabinet file name for the media table.
##############################################################

sub get_media_cabinet
{
	my ($id) = @_;

	my $number = 1000 + $id;
	my $filename = "f_" . $number . ".cab";
	
	if ( $installer::globals::include_cab_in_msi ) { $filename = "\#" . $filename; }
	
	return $filename;
}

##############################################################
# Returning the volumelabel for the media table.
##############################################################

sub get_media_volumelabel
{
	return "DISK1";
}

##############################################################
# Returning the source for the media table.
##############################################################

sub get_media_source
{
	return "";
}

##############################################################
# Saving the cabinet file name in the files collector.
# This is useful for making a list to connect the 
# source of each file with the destination cabinet file.
##############################################################

sub set_cabinetfilename_for_component_in_file_collector
{
	my ($cabinetfilename, $filesref, $componentname, $max) = @_;

	for ( my $i = 0; $i <= $max; $i++ )
	{
		my $onefile = ${$filesref}[$i];
		my $component = $onefile->{'componentname'};

		if ( $component eq $componentname )
		{
			my $cabinet = "";
			
			if ( $onefile->{'cabinet'} ) { $cabinet = $onefile->{'cabinet'}; }
			
			if ( $cabinet eq "" )
			{
				$onefile->{'cabinet'} = $cabinetfilename;				
			}
		}
	}
}	

#################################################
# Creating the cab file name dynamically
#################################################

sub generate_cab_filename_for_some_cabs
{
	my ( $allvariables, $id ) = @_;

	my $name = $allvariables->{'PRODUCTNAME'};
	
	$name = lc($name);
	$name =~ s/\.//g;
	$name =~ s/\s//g;

	# possibility to overwrite the name with variable CABFILENAME
	if ( $allvariables->{'CABFILENAME'} ) { $name = $allvariables->{'CABFILENAME'}; }

	$name = $name . $id . ".cab";

	if ( $installer::globals::include_cab_in_msi ) { $name = "\#" . $name; }

	return $name;
}

#################################################
# Creating the cab file name for cab files
# defined in packages.
#################################################

sub get_cabfilename
{
	my ($name) = @_;
	
	if ( $installer::globals::include_cab_in_msi ) { $name = "\#" . $name; }

	return $name;	
}

#################################################
# Creating the cab file name dynamically
#################################################

sub generate_cab_filename
{
	my ( $allvariables ) = @_;

	my $name = $allvariables->{'PRODUCTNAME'};
	
	$name = lc($name);
	$name =~ s/\.//g;
	$name =~ s/\s//g;

	# possibility to overwrite the name with variable CABFILENAME
	if ( $allvariables->{'CABFILENAME'} ) { $name = $allvariables->{'CABFILENAME'}; }

	$name = $name . ".cab";

	if ( $installer::globals::include_cab_in_msi ) { $name = "\#" . $name; }

	return $name;
}

sub get_maximum_filenumber
{
	my ($allfiles, $maxcabfilenumber) = @_;

	my $maxfile = 0;
	
	while ( ! ( $allfiles%$maxcabfilenumber == 0 ))
	{
		$allfiles++;	
	} 
	
	$maxfile = $allfiles / $maxcabfilenumber;
	
	$maxfile++;					# for securitry
	
	return $maxfile;
}

#################################################################################
# Setting the last sequence for the cabinet files
#################################################################################

sub get_last_sequence
{
	my ( $cabfilename, $alludpatelastsequences ) = @_;
	
	my $sequence = 0;
	
	if (( $installer::globals::updatedatabase ) && ( exists($alludpatelastsequences->{$cabfilename}) ))
	{
		$sequence = $alludpatelastsequences->{$cabfilename};
	}
	else
	{
		$sequence = $installer::globals::lastsequence{$cabfilename};
	}

	return $sequence;
}

#################################################################################
# Creating the file Media.idt dynamically
# Content: 
# DiskId LastSequence DiskPrompt Cabinet VolumeLabel Source
# Idea: Every component is packed into each own cab file 
#################################################################################

sub create_media_table
{
	my ($filesref, $basedir, $allvariables, $alludpatelastsequences, $allupdatediskids) = @_;

	my @mediatable = ();
	
	my $diskid = 0;

	installer::windows::idtglobal::write_idt_header(\@mediatable, "media");
	
	if ( $allvariables->{'INCLUDE_CAB_IN_MSI'} ) { $installer::globals::include_cab_in_msi = 1; }

	if ( $installer::globals::use_packages_for_cabs )
	{
		my $cabfile;
		foreach $cabfile ( sort keys %installer::globals::lastsequence )
		{
			my %media = ();
			$diskid++;
		
			$media{'DiskId'} = get_media_diskid($diskid);
			$media{'LastSequence'} = get_last_sequence($cabfile, $alludpatelastsequences);
			$media{'DiskPrompt'} = get_media_diskprompt();
			$media{'Cabinet'} = get_cabfilename($cabfile);
			$media{'VolumeLabel'} = get_media_volumelabel();
			$media{'Source'} = get_media_source();

			my $oneline = $media{'DiskId'} . "\t" . $media{'LastSequence'} . "\t" . $media{'DiskPrompt'} . "\t"  
						. $media{'Cabinet'} . "\t" . $media{'VolumeLabel'} . "\t" . $media{'Source'} . "\n";

			push(@mediatable, $oneline);

			# Comparing the disk id with the disk id from update database. Both have to be identical. New files have to be added
			# to the new pff cabinet file. And existing cab files must not be removed.
			if ( $installer::globals::updatedatabase )
			{
				# Comparing lines in new media table with line from media table in udpate database.
				if ( exists($allupdatediskids->{$media{'Cabinet'}}) )
				{
					if ( $media{'DiskId'} != $allupdatediskids->{$media{'Cabinet'}} )
					{
						installer::exiter::exit_program("ERROR: Different DiskIDs for cab file \"$media{'Cabinet'}\".\nCurrent installation set: \"$media{'DiskId'}\", but update database used \"$allupdatediskids->{$media{'Cabinet'}}\".\nWere cabinet files removed or added?", "create_media_table");
					}
				}
				else
				{
					my $localinfoline = "Warning: Could not find cabinet file \"$media{'Cabinet'}}\" in update database. This seems to be an new cabinet file!?\n"; 
					push(@installer::globals::logfileinfo, $localinfoline);
				}
			}
		}
		
		# one new cabinet file for all files added after the final release
		if (( $installer::globals::updatedatabase ) && ( $installer::globals::pfffileexists ))
		{
			my %media = ();
			$diskid++;

			$media{'DiskId'} = get_media_diskid($diskid) + $installer::globals::mergemodulenumber;  # Adding mergemodulenumber, because this files are included later
			$media{'LastSequence'} = $installer::globals::updatesequencecounter;
			$media{'DiskPrompt'} = get_media_diskprompt();
			$media{'Cabinet'} = get_cabfilename($installer::globals::pffcabfilename);
			$media{'VolumeLabel'} = get_media_volumelabel();
			$media{'Source'} = get_media_source();

			my $oneline = $media{'DiskId'} . "\t" . $media{'LastSequence'} . "\t" . $media{'DiskPrompt'} . "\t"  
						. $media{'Cabinet'} . "\t" . $media{'VolumeLabel'} . "\t" . $media{'Source'} . "\n";

			push(@mediatable, $oneline);
		}
		
	}
	elsif ( $installer::globals::cab_file_per_component )
	{
		for ( my $i = 0; $i <= $#{$filesref}; $i++ )
		{
			my $onefile = ${$filesref}[$i];
			my $nextfile = ${$filesref}[$i+1];
		
			my $filecomponent = "";
			my $nextcomponent = "";
		
			if ( $onefile->{'componentname'} ) { $filecomponent = $onefile->{'componentname'}; }
			if ( $nextfile->{'componentname'} ) { $nextcomponent = $nextfile->{'componentname'}; }

			if ( $filecomponent eq $nextcomponent )
			{
				next;		# nothing to do, this is not the last file of a component
			}
		
			my %media = ();
			$diskid++;
		
			$media{'DiskId'} = get_media_diskid($diskid);
			$media{'LastSequence'} = get_media_lastsequence($onefile);
			$media{'DiskPrompt'} = get_media_diskprompt();
			$media{'Cabinet'} = get_media_cabinet($diskid);
			$media{'VolumeLabel'} = get_media_volumelabel();
			$media{'Source'} = get_media_source();

			my $oneline = $media{'DiskId'} . "\t" . $media{'LastSequence'} . "\t" . $media{'DiskPrompt'} . "\t"  
					. $media{'Cabinet'} . "\t" . $media{'VolumeLabel'} . "\t" . $media{'Source'} . "\n";

			push(@mediatable, $oneline);		

			$media{'Cabinet'} =~ s/^\s*\#//;	# removing leading hash
			set_cabinetfilename_for_component_in_file_collector($media{'Cabinet'}, $filesref, $filecomponent, $i);	
		}
	}
	elsif ( $installer::globals::fix_number_of_cab_files )
	{		
		# number of cabfiles
		my $maxcabfilenumber = $installer::globals::number_of_cabfiles;
		if ( $allvariables->{'CABFILENUMBER'} ) { $maxcabfilenumber = $allvariables->{'CABFILENUMBER'}; }
		my $allfiles = $#{$filesref} + 1;
		my $maxfilenumber = get_maximum_filenumber($allfiles, $maxcabfilenumber);
		# my $maxfilenumber = 1000;	# maximum 1000 files in each cabinet file
		my $cabfilenumber = 0;
		my $cabfull = 0;
		my $counter = 0;
		
		# Sorting of files collector files required !
		# Attention: The order in the cab file is not guaranteed (especially in udpate process)
		
		for ( my $i = 0; $i <= $#{$filesref}; $i++ )
		{
			if (( $counter >= $maxfilenumber ) || ( $i == $#{$filesref} )) { $cabfull = 1; }

			$counter++; 	 # counting the files in the cab file
			
			my $onefile = ${$filesref}[$i];
			my $nextfile = ${$filesref}[$i+1];
		
			my $filecomponent = "";
			my $nextcomponent = "";
			
			if ( $onefile->{'componentname'} ) { $filecomponent = $onefile->{'componentname'}; }
			if ( $nextfile->{'componentname'} ) { $nextcomponent = $nextfile->{'componentname'}; }

			if ( $filecomponent eq $nextcomponent )	# all files of one component have to be in one cab file
			{
				next;		# nothing to do, this is not the last file of a component
			}

			if ( $cabfull )
			{
				my %media = ();
				$cabfilenumber++;

				$media{'DiskId'} = get_media_diskid($cabfilenumber);
				# $media{'LastSequence'} = get_media_lastsequence($onefile);
				$media{'LastSequence'} = $i + 1;	# This should be correct, also for unsorted files collectors
				$media{'DiskPrompt'} = get_media_diskprompt();
				$media{'Cabinet'} = generate_cab_filename_for_some_cabs($allvariables, $cabfilenumber);
				$media{'VolumeLabel'} = get_media_volumelabel();
				$media{'Source'} = get_media_source();

				my $oneline = $media{'DiskId'} . "\t" . $media{'LastSequence'} . "\t" . $media{'DiskPrompt'} . "\t"  
						. $media{'Cabinet'} . "\t" . $media{'VolumeLabel'} . "\t" . $media{'Source'} . "\n";

				push(@mediatable, $oneline);		

				# Saving the cabinet file name in the file collector

				$media{'Cabinet'} =~ s/^\s*\#//;	# removing leading hash

				for ( my $j = 0; $j <= $i; $j++ )
				{
					my $onefile = ${$filesref}[$j];			
					if ( ! $onefile->{'cabinet'} ) { $onefile->{'cabinet'} = $media{'Cabinet'}; }				
				}

				$cabfull = 0;
				$counter = 0;				
			}
		}
	}
	elsif ( $installer::globals::one_cab_file )
	{	
		my %media = ();
		$diskid++;
		
		my $maximumfile = $#{$filesref};

		$media{'DiskId'} = get_media_diskid($diskid);
		# $media{'LastSequence'} = ${$filesref}[$maximumfile]->{'sequencenumber'};	# sequence number of the last file
		$media{'LastSequence'} = $maximumfile + 1; # This works also for unsorted file collector
		$media{'DiskPrompt'} = get_media_diskprompt();
		$media{'Cabinet'} = generate_cab_filename($allvariables);
		$media{'VolumeLabel'} = get_media_volumelabel();
		$media{'Source'} = get_media_source();

		my $oneline = $media{'DiskId'} . "\t" . $media{'LastSequence'} . "\t" . $media{'DiskPrompt'} . "\t"  
					. $media{'Cabinet'} . "\t" . $media{'VolumeLabel'} . "\t" . $media{'Source'} . "\n";

		push(@mediatable, $oneline);

		# Saving the cabinet file name in the file collector

		$media{'Cabinet'} =~ s/^\s*\#//;	# removing leading hash

		for ( my $i = 0; $i <= $#{$filesref}; $i++ )
		{
			my $onefile = ${$filesref}[$i];			
			$onefile->{'cabinet'} = $media{'Cabinet'};				
		}
	}
	else
	{
		installer::exiter::exit_program("ERROR: No cab file specification in globals.pm !", "create_media_table");
	}
	
	# Saving the file
	
	my $mediatablename = $basedir . $installer::globals::separator . "Media.idt";
	installer::files::save_file($mediatablename ,\@mediatable);
	my $infoline = "Created idt file: $mediatablename\n"; 
	push(@installer::globals::logfileinfo, $infoline);
}

1;
