#*************************************************************************
#
#   OpenOffice.org - a multi-platform office productivity suite
#
#   $RCSfile: archivefiles.pm,v $
#
#   $Revision: 1.17 $
#
#   last change: $Author: vg $ $Date: 2007-12-05 17:36:00 $
#
#   The Contents of this file are made available subject to
#   the terms of GNU Lesser General Public License Version 2.1.
#
#
#     GNU Lesser General Public License Version 2.1
#     =============================================
#     Copyright 2005 by Sun Microsystems, Inc.
#     901 San Antonio Road, Palo Alto, CA 94303, USA
#
#     This library is free software; you can redistribute it and/or
#     modify it under the terms of the GNU Lesser General Public
#     License version 2.1, as published by the Free Software Foundation.
#
#     This library 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
#     Lesser General Public License for more details.
#
#     You should have received a copy of the GNU Lesser General Public
#     License along with this library; if not, write to the Free Software
#     Foundation, Inc., 59 Temple Place, Suite 330, Boston,
#     MA  02111-1307  USA
#
#*************************************************************************

package installer::archivefiles;

use installer::converter;
use installer::existence;
use installer::exiter;
use installer::files;
use installer::globals;
use installer::logger;
use installer::pathanalyzer;
use installer::systemactions;

#################################################################
# Changing the name for files with flag RENAME_TO_LANGUAGE
#################################################################

sub put_language_into_name
{
    my ( $oldname, $onelanguage ) = @_;

    my $newname = "";

    my $filename = "";
    my $extension = "";

    if ( $oldname =~ /^\s*(.*)(\..*?)\s*$/ )    # files with extension
    {
        $filename = $1;
        $extension = $2;
    }
    else
    {
        $filename = $oldname;
        $extension = "";
    }

    $newname = $1 . "_" . $onelanguage . $2;

    return $newname;
}

#################################################################
# Converting patchfiles string into array
#################################################################

sub get_patch_file_list
{
    my ( $patchfilestring ) = @_;

    $patchfilestring =~ s/^\s*\(?//;
    $patchfilestring =~ s/\)?\s*$//;
    $patchfilestring =~ s/^\s*\///;
    $patchfilestring =~ s/^\s*\\//;

    my $patchfilesarray = installer::converter::convert_stringlist_into_array_without_linebreak_and_quotes(\$patchfilestring, ",");

    return $patchfilesarray;
}

#################################################################
# Analyzing files with flag ARCHIVE
#################################################################

sub resolving_archive_flag
{
    my ($filesarrayref, $additionalpathsref, $languagestringref, $loggingdir) = @_;

    if ( $installer::globals::debug ) { installer::logger::debuginfo("installer::archivefiles::resolving_archive_flag : $#{$filesarrayref} : $#{$additionalpathsref} : $$languagestringref : $loggingdir"); }

    my @newallfilesarray = ();

    my ($systemcall, $returnvalue, $infoline);

    my $unziplistfile = $loggingdir . "unziplist_" . $installer::globals::build . "_" . $installer::globals::compiler . "_" . $$languagestringref . ".txt";

    my $platformunzipdirbase = installer::systemactions::create_directories("zip", $languagestringref);
    push(@installer::globals::removedirs, $platformunzipdirbase);

    installer::logger::include_header_into_logfile("Files with flag ARCHIVE:");

    my $repeat_unzip = 0;
    my $maxcounter = 0;

    for ( my $i = 0; $i <= $#{$filesarrayref}; $i++ )
    {
        if ( $repeat_unzip ) { $i--; }  # decreasing the counter

        my $onefile = ${$filesarrayref}[$i];
        my $styles = "";

        if ( $onefile->{'Styles'} ) { $styles = $onefile->{'Styles'}; }

        if ( $styles =~ /\bARCHIVE\b/ )     # copying, unzipping and changing the file list
        {
            my $iscommonfile = 0;
            my $sourcepath = $onefile->{'sourcepath'};

            if ( $sourcepath =~ /\Q$installer::globals::separator\E\bcommon$installer::globals::productextension\Q$installer::globals::separator\E/ )   # /common/ or /common.pro/
            {
                $iscommonfile = 1;
            }

            my $use_internal_rights = 0;
            if ( $styles =~ /\bUSE_INTERNAL_RIGHTS\b/ ) { $use_internal_rights = 1; }   # using the rights used inside the zip file

            my $rename_to_language = 0;
            if ( $styles =~ /\bRENAME_TO_LANGUAGE\b/ ) { $rename_to_language = 1; } # special handling for renamed files (scriptitems.pm)

            # mechanism to select files from an archive files
            my $select_files = 0;
            my $selectlistfiles = "";
            my @keptfiles = ();
            if ( $onefile->{'Selectfiles'} )
            {
                $select_files = 1;
                $selectlistfiles = get_patch_file_list( $onefile->{'Selectfiles'} );
                $infoline = "Selected file list defined at file: $onefile->{'Name'} :\n";
                push( @installer::globals::logfileinfo, $infoline);
                for ( my $k = 0; $k <= $#{$selectlistfiles}; $k++ )
                {
                    $infoline = "\"${$selectlistfiles}[$k]\"\n";
                    push( @installer::globals::logfileinfo, $infoline);
                }
            }

            if ( $onefile->{'Selectfiles'} ) { $onefile->{'Selectfiles'} = ""; } # Selected files list no longer required

            # mechanism to define patch files inside an archive files
            my $select_patch_files = 0;
            my $patchlistfiles = "";
            my @keptpatchflags = ();
            if (( $styles =~ /\bPATCH\b/ ) && ( $onefile->{'Patchfiles'} ) && ( $installer::globals::patch ))
            {
                $select_patch_files = 1; # special handling if a Patchlist is defined
                $patchlistfiles = get_patch_file_list( $onefile->{'Patchfiles'} );
                $infoline = "Patch file list defined at file: $onefile->{'Name'} :\n";
                push( @installer::globals::logfileinfo, $infoline);
                for ( my $k = 0; $k <= $#{$patchlistfiles}; $k++ )
                {
                    $infoline = "\"${$patchlistfiles}[$k]\"\n";
                    push( @installer::globals::logfileinfo, $infoline);
                }
            }

            if ( $onefile->{'Patchfiles'} ) { $onefile->{'Patchfiles'} = ""; } # Patch file list no longer required

            # creating directories

            my $onelanguage = $onefile->{'specificlanguage'};

            # files without language into directory "00"

            if ($onelanguage eq "") { $onelanguage = "00"; }

            my $unzipdir;

            # if ($iscommonfile) { $unzipdir = $commonunzipdirbase . $installer::globals::separator . $onelanguage . $installer::globals::separator; }
            # else { $unzipdir = $platformunzipdirbase . $installer::globals::separator . $onelanguage . $installer::globals::separator; }

            $unzipdir = $platformunzipdirbase . $installer::globals::separator . $onelanguage . $installer::globals::separator;

            installer::systemactions::create_directory($unzipdir);  # creating language specific subdirectories

            my $onefilename = $onefile->{'Name'};
            $onefilename =~ s/\./\_/g;      # creating new directory name
            $onefilename =~ s/\//\_/g;      # only because of /letter/fontunxpsprint.zip, the only zip file with path
            $unzipdir = $unzipdir . $onefilename . $installer::globals::separator;

            if ( $installer::globals::dounzip ) { installer::systemactions::create_directory($unzipdir); }  # creating subdirectories with the names of the zipfiles

            $systemcall = "$installer::globals::unzippath -l $sourcepath |";
            open (UNZIP, "$systemcall");
            my @zipfile = <UNZIP>;
            close (UNZIP);

            $infoline = "Systemcall: $systemcall\n";
            push( @installer::globals::logfileinfo, $infoline);

            if (!( $#zipfile > -1 ))    # the zipfile is empty
            {
                $infoline = "ERROR: Could not unzip $sourcepath\n";
                push( @installer::globals::logfileinfo, $infoline);

            }
            else
            {
                # now really unpacking the files
                # Parameter -o : overwrite files without prompting
                # Parameter -q : quiet mode

                if ( $installer::globals::dounzip )         # really unpacking the files
                {
                    $returnvalue = 1;
                    $systemcall = "$installer::globals::unzippath -o -q $sourcepath -d $unzipdir";
                    $returnvalue = system($systemcall);

                    $infoline = "Systemcall: $systemcall\n";
                    push( @installer::globals::logfileinfo, $infoline);

                    if ($returnvalue) { installer::exiter::exit_program("ERROR: $infoline", "resolving_archive_flag"); }

                    if ( $^O =~ /cygwin/i )
                    {
                        # Make dll's executable
                        $systemcall = "cd $unzipdir; find . -name \\*.dll -exec chmod 775 \{\} \\\;";
                        $returnvalue = system($systemcall);
                        $infoline = "Systemcall: $systemcall\n";
                        push( @installer::globals::logfileinfo, $infoline);

                        if ($returnvalue)
                        {
                            $infoline = "ERROR: Could not execute \"$systemcall\"!\n";
                            push( @installer::globals::logfileinfo, $infoline);
                        }
                    }

                    if ( ! $installer::globals::iswindowsbuild )
                    {
                        # Setting unix rights to "775" for all created directories inside the package

                        $systemcall = "cd $unzipdir; find . -type d -exec chmod 775 \{\} \\\;";
                        $returnvalue = system($systemcall);
                        $infoline = "Systemcall: $systemcall\n";
                        push( @installer::globals::logfileinfo, $infoline);

                        if ($returnvalue)
                        {
                            $infoline = "ERROR: Could not execute \"$systemcall\"!\n";
                            push( @installer::globals::logfileinfo, $infoline);
                        }
                    }
                }

                my $zipfileref = \@zipfile;
                my $unziperror = 0;

                # Format: Length, Date, Time, Name
                # This includes new destination directories!

                for ( my $j = 0; $j <= $#{$zipfileref}; $j++ )
                {
                    my $line = ${$zipfileref}[$j];

                    # Format:
                    #    0 07-25-03  18:21   dir1/
                    # 1241 07-25-03  18:21   dir1/so7drawing.desktop

                    if ( $line =~ /^\s*(\d+)\s+(\S+)\s+(\S+)\s+(\S+.*\S+?)\s*$/ )
                    {
                        my $zipsize = $1;
                        my $zipdate = $2;
                        my $ziptime = $3;
                        my $zipname = $4;

                        # some directories and files (from the help) start with "./simpress.idx"

                        $zipname =~ s/^\s*\.\///;

                        if ($installer::globals::iswin and $^O =~ /MSWin/i) { $zipname =~ s/\//\\/g; }

                        # if ( $zipsize == 0 )  # also files can have a size of 0
                        if ( $zipname =~ /\Q$installer::globals::separator\E\s*$/ ) # slash or backslash at the end characterizes a directory
                        {
                            $zipname = $zipname . "\n";
                            push(@{$additionalpathsref}, $zipname);

                            # Also needed here:
                            # Name
                            # Language
                            # ismultilingual
                            # Basedirectory

                            # This is not needed, because the list of all directories for the
                            # epm list file is generated from the destination directories of the
                            # files included in the product!
                        }
                        else
                        {
                            my %newfile = ();
                            %newfile = %{$onefile};
                            $newfile{'Name'} = $zipname;
                            my $destination = $onefile->{'destination'};
                            installer::pathanalyzer::get_path_from_fullqualifiedname(\$destination);
                            $newfile{'destination'} = $destination . $zipname;
                            $newfile{'sourcepath'} = $unzipdir . $zipname;
                            $newfile{'zipfilename'} = $onefile->{'Name'};
                            $newfile{'zipfilesource'} = $onefile->{'sourcepath'};
                            $newfile{'zipfiledestination'} = $onefile->{'destination'};

                            if (( $use_internal_rights ) && ( ! $installer::globals::iswin ))
                            {
                                my $value = sprintf("%o", (stat($newfile{'sourcepath'}))[2]);
                                $newfile{'UnixRights'} = substr($value, 3);
                                $infoline = "Setting unix rights for \"$newfile{'sourcepath'}\" to \"$newfile{'UnixRights'}\"\n";
                                push( @installer::globals::logfileinfo, $infoline);
                            }

                            if ( $select_files )
                            {
                                if ( ! installer::existence::exists_in_array($zipname,$selectlistfiles) )
                                {
                                    $infoline = "Removing from ARCHIVE file $onefilename: $zipname\n";
                                    push( @installer::globals::logfileinfo, $infoline);
                                    next; # ignoring files, that are not included in $selectlistfiles
                                }
                                else
                                {
                                    $infoline = "Keeping from ARCHIVE file $onefilename: $zipname\n";
                                    push( @installer::globals::logfileinfo, $infoline);
                                    push( @keptfiles, $zipname); # collecting all kept files
                                }
                            }

                            if ( $select_patch_files )
                            {
                                # Is this file listed in the Patchfile list?
                                # $zipname (filename including path in zip file has to be listed in patchfile list

                                if ( ! installer::existence::exists_in_array($zipname,$patchlistfiles) )
                                {
                                    $newfile{'Styles'} =~ s/\bPATCH\b//;    # removing the flag PATCH
                                    $newfile{'Styles'} =~ s/\,\s*\,/\,/;
                                    $newfile{'Styles'} =~ s/\(\s*\,/\(/;
                                    $newfile{'Styles'} =~ s/\,\s*\)/\)/;
                                    # $infoline = "Removing PATCH flag from: $zipname\n";
                                    # push( @installer::globals::logfileinfo, $infoline);
                                }
                                else
                                {
                                    # $infoline = "Keeping PATCH flag at: $zipname\n";
                                    # push( @installer::globals::logfileinfo, $infoline);
                                    push( @keptpatchflags, $zipname); # collecting all PATCH flags
                                }
                            }

                            if ( $rename_to_language )
                            {
                                my $newzipname = put_language_into_name($zipname, $onelanguage);
                                my $oldfilename = $unzipdir . $zipname;
                                my $newfilename = $unzipdir . $newzipname;

                                installer::systemactions::copy_one_file($oldfilename, $newfilename);

                                $newfile{'Name'} = $newzipname;
                                $newfile{'destination'} = $destination . $newzipname;
                                $newfile{'sourcepath'} = $unzipdir . $newzipname;

                                $infoline = "RENAME_TO_LANGUAGE: Using $newzipname instead of $zipname!\n";
                                push( @installer::globals::logfileinfo, $infoline);
                            }

                            my $sourcefiletest = $unzipdir . $zipname;
                            if ( ! -f $sourcefiletest )
                            {
                                $infoline = "ATTENTION: Unzip failed for $sourcefiletest!\n";
                                push( @installer::globals::logfileinfo, $infoline);
                                $unziperror = 1;
                            }

                            # only adding the new line into the files array, if not in repeat modus

                            if ( ! $repeat_unzip ) { push(@newallfilesarray, \%newfile); }
                        }
                    }
                }

                # Comparing the content of @keptfiles and $selectlistfiles
                # Do all files from the list of selected files are stored in @keptfiles ?
                # @keptfiles contains only files included in $selectlistfiles. But are all
                # files from $selectlistfiles included in @keptfiles?

                if ( $select_files )
                {
                    my $number = $#{$selectlistfiles} + 1;
                    $infoline = "SELECTLIST: Number of files in file selection list: $number\n";
                    push( @installer::globals::logfileinfo, $infoline);
                    $number = $#keptfiles + 1;
                    $infoline = "SELECTLIST: Number of kept files: $number\n";
                    push( @installer::globals::logfileinfo, $infoline);

                    for ( my $k = 0; $k <= $#keptfiles; $k++ )
                    {
                        $infoline = "KEPT FILES: $keptfiles[$k]\n";
                        push( @installer::globals::logfileinfo, $infoline);
                    }

                    my @warningfiles = ();

                    for ( my $k = 0; $k <= $#{$selectlistfiles}; $k++ )
                    {
                        if ( ! installer::existence::exists_in_array(${$selectlistfiles}[$k],\@keptfiles) )
                        {
                            push(@warningfiles, ${$selectlistfiles}[$k]);
                        }
                    }

                    for ( my $k = 0; $k <= $#warningfiles; $k++ )
                    {
                        $infoline = "WARNING: $warningfiles[$k] not included in install set (does not exist in zip file)!\n";
                        push( @installer::globals::logfileinfo, $infoline);
                    }

                }

                # Comparing the content of @keptpatchflags and $patchlistfiles
                # Do all files from the patch list have a PATCH flag ?
                # @keptpatchflags contains only files included in $patchlistfiles. But are all
                # files from $patchlistfiles included in @keptpatchflags?

                if ( $select_patch_files )
                {
                    my $number = $#{$patchlistfiles} + 1;
                    $infoline = "PATCHLIST: Number of files in patch list: $number\n";
                    push( @installer::globals::logfileinfo, $infoline);
                    $number = $#keptpatchflags + 1;
                    $infoline = "PATCHLIST: Number of kept PATCH flags: $number\n";
                    push( @installer::globals::logfileinfo, $infoline);

                    for ( my $k = 0; $k <= $#keptpatchflags; $k++ )
                    {
                        $infoline = "KEPT PATCH FLAGS: $keptpatchflags[$k]\n";
                        push( @installer::globals::logfileinfo, $infoline);
                    }

                    my @warningfiles = ();

                    for ( my $k = 0; $k <= $#{$patchlistfiles}; $k++ )
                    {
                        if ( ! installer::existence::exists_in_array(${$patchlistfiles}[$k],\@keptpatchflags) )
                        {
                            push(@warningfiles, ${$patchlistfiles}[$k]);
                        }
                    }

                    for ( my $k = 0; $k <= $#warningfiles; $k++ )
                    {
                        $infoline = "WARNING: $warningfiles[$k] did not keep PATCH flag (does not exist in zip file)!\n";
                        push( @installer::globals::logfileinfo, $infoline);
                    }
                }

                if ( $unziperror )
                {
                    installer::logger::print_warning( "Repeating to unpack $sourcepath! \n" );
                    $infoline = "ATTENTION: Repeating to unpack $sourcepath !\n";
                    push( @installer::globals::logfileinfo, $infoline);
                    $repeat_unzip = 1;
                    $maxcounter++;

                    if ( $maxcounter == 5 ) # exiting the program
                    {
                        installer::exiter::exit_program("ERROR: Failed to unzip $sourcepath !", "resolving_archive_flag");
                    }
                }
                else
                {
                    $infoline = "Info: $sourcepath unpacked without problems !\n";
                    push( @installer::globals::logfileinfo, $infoline);
                    $repeat_unzip = 0;
                    $maxcounter = 0;
                }
            }
        }
        else        # nothing to do here, no zipped file (no ARCHIVE flag)
        {
            push(@newallfilesarray, $onefile);
        }
    }

    $infoline = "\n";
    push( @installer::globals::logfileinfo, $infoline);

    return \@newallfilesarray;
}


1;
