#**************************************************************
#  
#  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::directory;

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

##############################################################
# Collecting all directory trees in global hash
##############################################################

sub collectdirectorytrees
{
	my ( $directoryref ) = @_;

	for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
	{
		my $onedir = ${$directoryref}[$i];
		my $styles = "";
		if ( $onedir->{'Styles'} ) { $styles = $onedir->{'Styles'}; }

		if ( $styles ne "" )
		{
			foreach my $treestyle ( keys %installer::globals::treestyles )
			{
				if ( $styles =~ /\b$treestyle\b/ )
				{
					my $hostname = $onedir->{'HostName'};
					# -> hostname is the key, the style the value!
					$installer::globals::hostnametreestyles{$hostname} = $treestyle;
				}
			}
		}
	}
}

##############################################################
# Overwriting global programfilesfolder, if required
##############################################################

sub overwrite_programfilesfolder
{
	my ( $allvariables ) = @_;
	
	if ( $allvariables->{'PROGRAMFILESFOLDERNAME'} )
	{
		$installer::globals::programfilesfolder = $allvariables->{'PROGRAMFILESFOLDERNAME'};
	}
}

##############################################################
# Maximum length of directory name is 72.
# Taking care of underlines, which are the separator.
##############################################################

sub make_short_dir_version
{
	my ($longstring) = @_;
	
	my $shortstring = "";
	my $cutlength = 60;
	my $length = 5; # So the directory can still be recognized
	my $longstring_save = $longstring;
	
	# Splitting the string at each "underline" and allowing only $length characters per directory name.
	# Checking also uniqueness and length.
	
	my $stringarray = installer::converter::convert_stringlist_into_array_without_newline(\$longstring, "_");
	
	foreach my $onestring ( @{$stringarray} )
	{
		my $partstring = "";
		
		if ( $onestring =~ /\-/ )
		{
			my $localstringarray = installer::converter::convert_stringlist_into_array_without_newline(\$onestring, "-");
			foreach my $onelocalstring ( @{$localstringarray} )
			{
				if ( length($onelocalstring) > $length ) { $onelocalstring = substr($onelocalstring, 0, $length); }
				$partstring = $partstring . "-" . $onelocalstring;
			}
			$partstring =~ s/^\s*\-//;
		}
		else
		{
			if ( length($onestring) > $length ) { $partstring = substr($onestring, 0, $length); }
			else { $partstring = $onestring; }
		}

		$shortstring = $shortstring . "_" . $partstring;
	}

	$shortstring =~ s/^\s*\_//;

	# Setting unique ID to each directory
	# No counter allowed, process must be absolute reproducable due to patch creation process.
	
	# chomp(my $id = `echo $longstring_save | md5sum | sed -e "s/ .*//g"`);  # Very, very slow
	# my $subid = substr($id, 0, 9); # taking only the first 9 digits

	my $subid = installer::windows::msiglobal::calculate_id($longstring_save, 9); # taking only the first 9 digits

	if ( length($shortstring) > $cutlength ) { $shortstring = substr($shortstring, 0, $cutlength); }

	$shortstring = $shortstring . "_" . $subid;

	return $shortstring;
}

##############################################################
# Adding unique directory names to the directory collection
##############################################################

sub create_unique_directorynames
{
	my ($directoryref, $allvariables) = @_;

	$installer::globals::officeinstalldirectoryset = 0;

	my %completedirhashstep1 = ();
	my %shortdirhash = ();
	my %shortdirhashreverse = ();
	my $infoline = "";
	my $errorcount = 0;

	for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
	{
		my $onedir = ${$directoryref}[$i];
		my $uniquename = $onedir->{'HostName'};

		my $styles = "";
		if ( $onedir->{'Styles'} ) { $styles = $onedir->{'Styles'}; }

		$uniquename =~ s/^\s*//g;				# removing beginning white spaces
		$uniquename =~ s/\s*$//g;				# removing ending white spaces
		$uniquename =~ s/\s//g;					# removing white spaces
		$uniquename =~ s/\_//g;					# removing existing underlines
		$uniquename =~ s/\.//g;					# removing dots in directoryname
		$uniquename =~ s/OpenOffice/OO/g;

		$uniquename =~ s/\Q$installer::globals::separator\E/\_/g;	# replacing slash and backslash with underline

		$uniquename =~ s/_registry/_rgy/g;
		$uniquename =~ s/_registration/_rgn/g;
		$uniquename =~ s/_extension/_ext/g;
		$uniquename =~ s/_frame/_frm/g;
		$uniquename =~ s/_table/_tbl/g;
		$uniquename =~ s/_chart/_crt/g;

		# The names after this small changes must still be unique!
		if ( exists($completedirhashstep1{$uniquename}) ) { installer::exiter::exit_program("ERROR: Error in packaging process. Unallowed modification of directory name, not unique (step 1): \"$uniquename\".", "create_unique_directorynames"); }
		$completedirhashstep1{$uniquename} = 1;

		# Starting to make unique name for the parent and its directory
		my $originaluniquename = $uniquename;

		$uniquename = make_short_dir_version($uniquename);

		# Checking if the same directory already exists, but has another short version.
		if (( exists($shortdirhash{$originaluniquename}) ) && ( $shortdirhash{$originaluniquename} ne $uniquename )) { installer::exiter::exit_program("ERROR: Error in packaging process. Unallowed modification of directory name, not unique (step 2A): \"$uniquename\".", "create_unique_directorynames"); }

		# Also checking vice versa
		# Checking if the same short directory already exists, but has another long version.
		if (( exists($shortdirhashreverse{$uniquename}) ) && ( $shortdirhashreverse{$uniquename} ne $originaluniquename )) { installer::exiter::exit_program("ERROR: Error in packaging process. Unallowed modification of directory name, not unique (step 2B): \"$uniquename\".", "create_unique_directorynames"); }

		# Creating assignment from long to short directory names
		$shortdirhash{$originaluniquename} = $uniquename;
		$shortdirhashreverse{$uniquename} = $originaluniquename;

		# Important: The unique parent is generated from the string $originaluniquename (with the use of underlines).

		my $uniqueparentname = $originaluniquename;
		my $keepparent = 1;

		if ( $uniqueparentname =~ /^\s*(.*)\_(.*?)\s*$/ )	# the underline is now the separator
		{
			$uniqueparentname = $1;
			$keepparent = 0;
		}
		else
		{
			$uniqueparentname = $installer::globals::programfilesfolder;
			$keepparent = 1;
		}

		if ( $styles =~ /\bPROGRAMFILESFOLDER\b/ )
		{
			$uniqueparentname = $installer::globals::programfilesfolder;
			$keepparent = 1;
		}
		if ( $styles =~ /\bCOMMONFILESFOLDER\b/ )
		{
			$uniqueparentname = $installer::globals::commonfilesfolder;
			$keepparent = 1;
		}
		if ( $styles =~ /\bCOMMONAPPDATAFOLDER\b/ )
		{
			$uniqueparentname = $installer::globals::commonappdatafolder;
			$keepparent = 1;
		}
		if ( $styles =~ /\bLOCALAPPDATAFOLDER\b/ )
		{
			$uniqueparentname = $installer::globals::localappdatafolder;
			$keepparent = 1;
		}

		if ( $styles =~ /\bSHAREPOINTPATH\b/ )
		{
			$uniqueparentname = "SHAREPOINTPATH";
			$installer::globals::usesharepointpath = 1;
			$keepparent = 1;
		}

		# also setting short directory name for the parent
		
		my $originaluniqueparentname = $uniqueparentname;

		if ( ! $keepparent )
		{
			$uniqueparentname = make_short_dir_version($uniqueparentname);
		}

		# Again checking if the same directory already exists, but has another short version.
		if (( exists($shortdirhash{$originaluniqueparentname}) ) && ( $shortdirhash{$originaluniqueparentname} ne $uniqueparentname )) { installer::exiter::exit_program("ERROR: Error in packaging process. Unallowed modification of directory name, not unique (step 3A): \"$uniqueparentname\".", "create_unique_directorynames"); }

		# Also checking vice versa
		# Checking if the same short directory already exists, but has another long version.
		if (( exists($shortdirhashreverse{$uniqueparentname}) ) && ( $shortdirhashreverse{$uniqueparentname} ne $originaluniqueparentname )) { installer::exiter::exit_program("ERROR: Error in packaging process. Unallowed modification of directory name, not unique (step 3B): \"$uniqueparentname\".", "create_unique_directorynames"); }

		$shortdirhash{$originaluniqueparentname} = $uniqueparentname;
		$shortdirhashreverse{$uniqueparentname} = $originaluniqueparentname;
		
		# Hyphen not allowed in database
		$uniquename =~ s/\-/\_/g;			# making "-" to "_"
		$uniqueparentname =~ s/\-/\_/g;		# making "-" to "_"
		
		# And finally setting the values for the directories
		$onedir->{'uniquename'} = $uniquename;
		$onedir->{'uniqueparentname'} = $uniqueparentname;

		# setting the installlocation directory
		if ( $styles =~ /\bISINSTALLLOCATION\b/ )
		{
			if ( $installer::globals::installlocationdirectoryset ) { installer::exiter::exit_program("ERROR: Directory with flag ISINSTALLLOCATION alread set: \"$installer::globals::installlocationdirectory\".", "create_unique_directorynames"); }
			$installer::globals::installlocationdirectory = $uniquename;
			$installer::globals::installlocationdirectoryset = 1;
		}
		
		# setting the sundirectory
		if ( $styles =~ /\bSUNDIRECTORY\b/ )
		{
			if ( $installer::globals::vendordirectoryset ) { installer::exiter::exit_program("ERROR: Directory with flag SUNDIRECTORY alread set: \"$installer::globals::vendordirectory\".", "create_unique_directorynames"); }
			$installer::globals::vendordirectory = $uniquename;
			$installer::globals::vendordirectoryset = 1;
		}
	}	
}

#####################################################
# Adding ":." to selected default directory names
#####################################################

sub check_sourcedir_addon
{
	my ( $onedir, $allvariableshashref ) = @_;
	
	if (($installer::globals::addchildprojects) ||
		($installer::globals::patch) ||
		($installer::globals::languagepack) || 
		($allvariableshashref->{'CHANGETARGETDIR'}))
	{
		my $sourcediraddon = "\:\.";
		$onedir->{'defaultdir'} = $onedir->{'defaultdir'} . $sourcediraddon;
	}			
	
}

#####################################################
# The directory with the style ISINSTALLLOCATION
# will be replaced by INSTALLLOCATION
#####################################################

sub set_installlocation_directory
{
	my ( $directoryref, $allvariableshashref ) = @_;
	
	if ( ! $installer::globals::installlocationdirectoryset ) { installer::exiter::exit_program("ERROR: Directory with flag ISINSTALLLOCATION not set!", "set_installlocation_directory"); }
	
	for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
	{
		my $onedir = ${$directoryref}[$i];

		if ( $onedir->{'uniquename'} eq $installer::globals::installlocationdirectory )
		{
			$onedir->{'uniquename'} = "INSTALLLOCATION";
			check_sourcedir_addon($onedir, $allvariableshashref);
		}
		
		if ( $onedir->{'uniquename'} eq $installer::globals::vendordirectory )
		{
			check_sourcedir_addon($onedir, $allvariableshashref);			
		}
		
		if ( $onedir->{'uniqueparentname'} eq $installer::globals::installlocationdirectory )
		{
			$onedir->{'uniqueparentname'} = "INSTALLLOCATION";			
		}
	}
}

#####################################################
# Getting the name of the top level directory. This
# can have only one letter
#####################################################

sub get_last_directory_name
{
	my ($completepathref) = @_;

	if ( $$completepathref =~ /^.*[\/\\](.+?)\s*$/ )
	{
		$$completepathref = $1;
	}
}

#####################################################
# Creating the defaultdir for the file Director.idt
#####################################################

sub create_defaultdir_directorynames ($)
{
	my ($directoryref) = @_;

	my @shortnames = ();
	if ( $installer::globals::prepare_winpatch ) { @shortnames = values(%installer::globals::saved83dirmapping); }

	for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
	{		
		my $onedir = ${$directoryref}[$i];
		my $hostname = $onedir->{'HostName'};

		$hostname =~ s/\Q$installer::globals::separator\E\s*$//;	
		get_last_directory_name(\$hostname);
		# installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$hostname);	# making program/classes to classes
		my $uniquename = $onedir->{'uniquename'};
		my $shortstring;
		if (( $installer::globals::prepare_winpatch ) && ( exists($installer::globals::saved83dirmapping{$uniquename}) ))
		{
			$shortstring = $installer::globals::saved83dirmapping{$uniquename};
		}
		else
		{
			$shortstring = installer::windows::idtglobal::make_eight_three_conform($hostname, "dir", \@shortnames);
		}

		my $defaultdir;

		if ( $shortstring eq $hostname )
		{
			$defaultdir = $hostname;
		}
		else
		{
			$defaultdir = $shortstring . "|" . $hostname;
		}

		$onedir->{'defaultdir'} = $defaultdir;

		my $fontdir = "";
		if ( $onedir->{'Dir'} ) { $fontdir = $onedir->{'Dir'}; }

		my $fontdefaultdir = "";
		if ( $onedir->{'defaultdir'} ) { $fontdefaultdir = $onedir->{'defaultdir'}; }

		if (( $fontdir eq "PREDEFINED_OSSYSTEMFONTDIR" ) && ( $fontdefaultdir eq $installer::globals::fontsdirhostname ))
		{
			$installer::globals::fontsdirname = $onedir->{'defaultdir'};
			$installer::globals::fontsdirparent = $onedir->{'uniqueparentname'};
		}
	}
}

###############################################
# Fill content into the directory table
###############################################

sub create_directorytable_from_collection
{
	my ($directorytableref, $directoryref) = @_;
	
	for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
	{
		my $onedir = ${$directoryref}[$i];
		my $hostname = $onedir->{'HostName'};
		my $dir = "";
		
		if ( $onedir->{'Dir'} ) { $dir = $onedir->{'Dir'}; }
		
		if (( $dir eq "PREDEFINED_PROGDIR" ) && ( $hostname eq "" )) { next; }	# removing files from root directory
		
		my $oneline = $onedir->{'uniquename'} . "\t" . $onedir->{'uniqueparentname'} . "\t" . $onedir->{'defaultdir'} . "\n";

		push(@{$directorytableref}, $oneline);
	}
}

###############################################
# Defining the root installation structure
###############################################

sub add_root_directories
{
	my ($directorytableref, $allvariableshashref) = @_;
	
#	my $sourcediraddon = "";
#	if (($installer::globals::addchildprojects) ||
#		($installer::globals::patch) ||
#		($installer::globals::languagepack) || 
#		($allvariableshashref->{'CHANGETARGETDIR'}))
#	{
#		$sourcediraddon = "\:\.";
#	}

	my $oneline = "";

	if (( ! $installer::globals::patch ) && ( ! $installer::globals::languagepack ) && ( ! $allvariableshashref->{'DONTUSESTARTMENUFOLDER'} ))
	{
		my $productname = $allvariableshashref->{'PRODUCTNAME'};
		my $productversion = $allvariableshashref->{'PRODUCTVERSION'};
		my $baseproductversion = $productversion;

		if (( $installer::globals::prepare_winpatch ) && ( $allvariableshashref->{'BASEPRODUCTVERSION'} ))
		{
			$baseproductversion = $allvariableshashref->{'BASEPRODUCTVERSION'};  # for example "2.0" for OOo
		}
		
		my $realproductkey = $productname . " " . $productversion;
		my $productkey = $productname . " " . $baseproductversion;
		
		if (( $allvariableshashref->{'POSTVERSIONEXTENSION'} ) && ( ! $allvariableshashref->{'DONTUSEEXTENSIONINDEFAULTDIR'} )) 
		{
			$productkey = $productkey . " " . $allvariableshashref->{'POSTVERSIONEXTENSION'}; 
			$realproductkey = $realproductkey . " " . $allvariableshashref->{'POSTVERSIONEXTENSION'}; 
		}
		if ( $allvariableshashref->{'NOSPACEINDIRECTORYNAME'} ) 
		{
			$productkey =~ s/\ /\_/g; 
			$realproductkey =~ s/\ /\_/g; 
		}
		
		my $shortproductkey = installer::windows::idtglobal::make_eight_three_conform($productkey, "dir");		# third parameter not used
		$shortproductkey =~ s/\s/\_/g;									# changing empty space to underline
			
		$oneline = "$installer::globals::officemenufolder\t$installer::globals::programmenufolder\t$shortproductkey|$realproductkey\n";
		push(@{$directorytableref}, $oneline);
	}

	$oneline = "TARGETDIR\t\tSourceDir\n";
	push(@{$directorytableref}, $oneline);

	$oneline = "$installer::globals::programfilesfolder\tTARGETDIR\t.\n";
	push(@{$directorytableref}, $oneline);

	$oneline = "$installer::globals::programmenufolder\tTARGETDIR\t.\n";
	push(@{$directorytableref}, $oneline);			

	$oneline = "$installer::globals::startupfolder\tTARGETDIR\t.\n";
	push(@{$directorytableref}, $oneline);

	$oneline = "$installer::globals::desktopfolder\tTARGETDIR\t.\n";
	push(@{$directorytableref}, $oneline);

	$oneline = "$installer::globals::startmenufolder\tTARGETDIR\t.\n";
	push(@{$directorytableref}, $oneline);

	$oneline = "$installer::globals::commonfilesfolder\tTARGETDIR\t.\n";
	push(@{$directorytableref}, $oneline);

	$oneline = "$installer::globals::commonappdatafolder\tTARGETDIR\t.\n";
	push(@{$directorytableref}, $oneline);

	$oneline = "$installer::globals::localappdatafolder\tTARGETDIR\t.\n";
	push(@{$directorytableref}, $oneline);
		
	if ( $installer::globals::usesharepointpath )
	{
		$oneline = "SHAREPOINTPATH\tTARGETDIR\t.\n";
		push(@{$directorytableref}, $oneline);
	}

	$oneline = "$installer::globals::systemfolder\tTARGETDIR\t.\n";
	push(@{$directorytableref}, $oneline);

	my $localtemplatefoldername = $installer::globals::templatefoldername;
	my $directorytableentry = $localtemplatefoldername;
	my $shorttemplatefoldername = installer::windows::idtglobal::make_eight_three_conform($localtemplatefoldername, "dir");
	if ( $shorttemplatefoldername ne $localtemplatefoldername ) { $directorytableentry = "$shorttemplatefoldername|$localtemplatefoldername"; }
	$oneline = "$installer::globals::templatefolder\tTARGETDIR\t$directorytableentry\n";
	push(@{$directorytableref}, $oneline);

	if ( $installer::globals::fontsdirname )
	{
		$oneline = "$installer::globals::fontsfolder\t$installer::globals::fontsdirparent\t$installer::globals::fontsfoldername\:$installer::globals::fontsdirname\n";
	}
	else
	{
		$oneline = "$installer::globals::fontsfolder\tTARGETDIR\t$installer::globals::fontsfoldername\n";
	}

	push(@{$directorytableref}, $oneline);

}

###############################################
# Creating the file Director.idt dynamically
###############################################

sub create_directory_table ($$$$)
{
	my ($directoryref, $basedir, $allvariableshashref, $loggingdir) = @_;

	# Structure of the directory table:
	# Directory Directory_Parent DefaultDir
	# Directory is a unique identifier
	# Directory_Parent is the unique identifier of the parent
	# DefaultDir is .:APPLIC~1|Application Data with
	# Before ":" : [sourcedir]:[destdir] (not programmed yet)
	# After ":" : 8+3 and not 8+3 the destination directory name
	
	$installer::logger::Lang->add_timestamp("Performance Info: Directory Table start");

	my @directorytable = ();
	my $infoline;
	
	overwrite_programfilesfolder($allvariableshashref);
	if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "directoriesforidt_local_1.log", $directoryref); }
	create_unique_directorynames($directoryref, $allvariableshashref);
	if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "directoriesforidt_local_1a.log", $directoryref); }
	create_defaultdir_directorynames($directoryref);	# only destdir!
	if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "directoriesforidt_local_2.log", $directoryref); }
	set_installlocation_directory($directoryref, $allvariableshashref);
	if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "directoriesforidt_local_3.log", $directoryref); }
	installer::windows::idtglobal::write_idt_header(\@directorytable, "directory");
	add_root_directories(\@directorytable, $allvariableshashref);
	create_directorytable_from_collection(\@directorytable, $directoryref);

	# Saving the file

	my $directorytablename = $basedir . $installer::globals::separator . "Director.idt";
	installer::files::save_file($directorytablename ,\@directorytable);
    $installer::logger::Lang->printf("Created idt file: %s\n", $directorytablename);

	$installer::logger::Lang->add_timestamp("Performance Info: Directory Table end");
}

1;
