#!perl
# Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
# All rights reserved.
# This component and the accompanying materials are made available
# under the terms of the License "Eclipse Public License v1.0"
# which accompanies this distribution, and is available
# at the URL "http://www.eclipse.org/legal/epl-v10.html".
# 
# Initial Contributors:
# Nokia Corporation - initial contribution.
# 
# Contributors:
# 
# Description:
# 
#

use strict;
use FindBin;
use lib "$FindBin::Bin";
use Getopt::Long;
use File::Path;
use IniData;
use RelTransfer::Import;
use CommandController;


#
# Globals.
#

my $verbose = 0;
my $iniData;
my $commandController;
my $force = 0;
my $ftpResume = 0;
my %releases; # Data structure changed to a double hash (from a single hash).
              # Top level keys are (case lowered) component names with has reference values.
              # Second level hash keys are versions, with a dummy value.
              # This arrangement makes it possible for a single component to have more than one
              # version, and to easily delete versions that have already been imported.
my $passphraseFile;
my $noPassphraseRetry;
my %goodImports;
my %failedImports;
my %alreadyImported;

#
# Main.
#

ProcessCommandLine();
CheckAlreadyImported();
ImportRelease() if (keys %releases); # It may be that all components have already been imported
PrintReport();

#
# Subs.
#

sub ProcessCommandLine {
  Getopt::Long::Configure ("bundling");
  my $help;
  GetOptions("h" => \$help, "v+" => \$verbose, "f" => \$force, "r" => \$ftpResume, "p=s" => \$passphraseFile, "noPassphraseRetry" => \$noPassphraseRetry);

  if ($help) {
    Usage(0);
  }

  if (scalar(@ARGV) == 1) {
    if (-f $ARGV[0]) {
      open IN, $ARGV[0] or die "Error: Couldn't open $ARGV[0] for reading: $!\n";
      while (my $line = <IN>) {
	chomp $line;
	$line =~ s/^\s*$//;
	$line =~ s/#.*//;
	if ($line eq '') {
	  next; #Nothing left
	}
	my ($comp, $ver) = split(" ", $line);
	if (defined $comp and defined $ver) {
	  $releases{lc($comp)}->{$ver} = 1;
	}
	else {
	  print "Error: Invalid file format in $ARGV[0]\n";
	  Usage(1);
	}
      }
      close IN;
    }
    else {
      print "Error: $ARGV[0] is not a file\n";
      Usage(1);
    }
  }	
  elsif (scalar(@ARGV) == 2) {
    $releases{lc($ARGV[0])}->{$ARGV[1]} = 1;
  }
  else {
    print "Error: Invalid arguments\n";
    Usage(1);
  }
  $iniData = IniData->New(undef,1);
  $commandController = CommandController->New($iniData, 'ImportRel');
  #if ftp resume option is used override value in reltools.ini
  if ($ftpResume) {
    $iniData->FtpServerSupportsResume(1);
  }
}

sub Usage {
  my $exitCode = shift;

  Utils::PrintDeathMessage($exitCode, "\nUsage: importrel [options] (<component> <version>) | (<component_ver_list_file>)

options:

-h  help
-f  force import overwriting if necessary
-r  use FTP reconnect and resume transfer mode
-p <file> file containing passphrase
-v  verbose output (-vv very verbose)
--noPassphraseRetry  Will cause ImportRel to terminate if an incorrect passphrase is specified\n");
}

sub CheckAlreadyImported {
#remove releases from attempted imports if they already exist locally
  unless ($force) {
    foreach my $comp (sort keys %releases) {
      foreach my $ver (keys %{$releases{$comp}}) {
	my $loc = $iniData->PathData->LocalArchivePathForExistingComponent($comp, $ver);
	if ($loc && -d $loc) { 
	  push (@{$alreadyImported{$comp}}, $ver);          
	  print "$comp $ver already exists in local archive\n" if ($verbose);
	  delete $releases{$comp}->{$ver};
	  unless (scalar(keys %{$releases{$comp}}) > 0) {
	    delete $releases{$comp};
	  }
	}	
      }
    }
  }
}

sub ReadPassphraseFile {
  return undef unless $passphraseFile;
  open(PP, $passphraseFile) or die "Couldn't open passphrase file \"$passphraseFile\" because $!\n";
  my $passphrase = join ("\n", <PP>);
  close PP;
  return $passphrase;
}

sub ImportRelease {
  my $importer = RelTransfer::Import->New(ini_data => $iniData,
					  force => $force,
					  verbose => $verbose,
            passphrase => ReadPassphraseFile);
  #do the import
  foreach my $comp (sort keys %releases) {
    my $imported;
    foreach my $ver (keys %{$releases{$comp}}) {
      eval {
        $imported = $importer->TransferRelease($comp, $ver, $noPassphraseRetry);
      };
      if ($@) {
        print $@;
        if ($@ =~ /cannot\s+connect/i) {
          print "\nConnection to remote site dropped aborting import\n";
          last;
        }
        my $error = $@;
        chomp $error;
        $error =~ s/^error: ("?$comp $ver"? )?//i;
        $failedImports{$comp}->{$ver} = $error;
      }
      else {
        if ($imported) {
          push (@{$goodImports{$comp}}, $ver);
        } else {
          push (@{$alreadyImported{$comp}}, $ver);
        }
      }
    }
  }
}

sub PrintReport { 
  print "\n=========IMPORT SUMMARY==========\n";

  my $tableData = [["Component", "Version", "status"]];

  foreach my $comp (sort keys %goodImports) {
    foreach my $ver (@{$goodImports{$comp}}) {
      push (@$tableData, [$comp, $ver, 'successfully imported']);
    }
  }
    
  foreach my $comp (sort keys %alreadyImported) {
    foreach my $ver (@{$alreadyImported{$comp}}) {
      push (@$tableData, [$comp, $ver, 'has already been imported']);
    }
  }
  
  if (scalar @{$tableData} > 1) {
    $iniData->TableFormatter->PrintTable($tableData, 1);
  }
  
  if (scalar (keys %alreadyImported) > 0) {
    print "\nYou can specify the -f option to force the re-import of component releases\n";
  }
  
  #handle failed imports
  if (keys %failedImports) {
    print "\n=========FAILED IMPORTS==========\n";
    my $failureTableData = [["Component", "Version", "Failure reason"]];
    foreach my $comp (sort keys %failedImports) {
      foreach my $ver (sort keys %{$failedImports{$comp}}) {
        push (@$failureTableData, [$comp, $ver, $failedImports{$comp}->{$ver}]);
      }
    }
    $iniData->TableFormatter->PrintTable($failureTableData, 1);
    print "\nError: Unable to import component release successfully.  Component release might be corrupted.\n";
  }
  else
  {
    if (keys %goodImports) {
      print "\nAll releases imported successfully\n";
    } else {
      print "\nNothing to do!\n";
    }
  }
}

  
__END__

=head1 NAME

ImportRel - Imports a component release from a remote site.

=head1 SYNOPSIS

  importrel [options] (<component> <version>) | (<component_ver_list_file>)

options:

  -h  help
  -f  force import overwriting if necessary
  -r  use FTP reconnect and resume transfer mode
  -p <file> file containing passphrase
  -v  verbose output (-vv very verbose)
  --noPassphraseRetry  Will cause ImportRel to terminate if an incorrect passphrase is specified

=head1 DESCRIPTION

Attempts to import the component release specified on the command line from the projects remote site to the local archive.

The name of file containing a list of components and versions maybe passed as an argument to the tool instead of a single component to import multiple releases.

Using the C<-f> option will force releases to be imported even if they already exist in the local archive.

If the C<-r> option is used and the FTP connection is dropped during the download of a release, the tools will automatically reconnect to the FTP site and resume the download. This feature may not be supported by some FTP servers.

It is recommended NOT to use the C<-p> option as it may be a security risk. You will be prompted if a passphrase is needed.

=head1 KNOWN BUGS

None

=head1 COPYRIGHT

 Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
 All rights reserved.
 This component and the accompanying materials are made available
 under the terms of the License "Eclipse Public License v1.0"
 which accompanies this distribution, and is available
 at the URL "http://www.eclipse.org/legal/epl-v10.html".
 
 Initial Contributors:
 Nokia Corporation - initial contribution.
 
 Contributors:
 
 Description:
 

=cut
