########################################################################
# COPYRIGHT - VIX IP PTY LTD ("VIX"). ALL RIGHTS RESERVED.
#
# Module name   : cc2svn_reposcan.pl
# Module type   : Makefile system
# Compiler(s)   : Perl
# Environment(s): jats
#
# Description   : Process the Repo.dat file and generate lists of
#                 packages to be processed
#
#                 Used to select packages that can be processed
# Usage:
#
#......................................................................#

require 5.008_002;
use strict;
use warnings;

use Pod::Usage;
use Getopt::Long;

use JatsError;
use FileUtils;

#
#   Globals
#
my  $VERSION = "1.0.0";                      # Update this
our %ScmRepoMap;

#
#   Options
#
my $opt_verbose = 0;
my $opt_help = 0;
my $opt_repo;
my $opt_repoExclude;
my $opt_age;
my $opt_user;
my $opt_svn = 0;
my $opt_tail;
my $opt_ageorder;
my $opt_ageorderUser;
my $opt_reposort;
my $opt_onlyName;
my $opt_onlyFullName;
my $opt_touch;
my @opt_available;
my @opt_exclude;
my $opt_all;
my $opt_protected;

my %excludeRepos;

#-------------------------------------------------------------------------------
# Function        : Main Entry
#
# Description     :
#
# Inputs          :
#
# Returns         :
#
my $result = GetOptions (
                "help+"         => \$opt_help,          # flag, multiple use allowed
                "manual:3"      => \$opt_help,
                "verbose:+"     => \$opt_verbose,       # flag
                'repo:s'        => \$opt_repo,
                'excluderepo:s' => \$opt_repoExclude,
                'age:i'         => \$opt_age,
                'user:i'        => \$opt_user,
                'tail:i'        => \$opt_tail,
                'byage'         => \$opt_ageorder,
                'byuser'        => \$opt_ageorderUser,
                'byrepo'        => \$opt_reposort,
                'byname'        => \$opt_onlyName,
                'byfullname'    => \$opt_onlyFullName,
                'svn'           => \$opt_svn,            # Include SVNed packages
                'touch:s'       => \$opt_touch,
                'available:s'   => \@opt_available,
                'exclude:s'     => \@opt_exclude,
                'all'           => \$opt_all,
                'protected'     => \$opt_protected,

                );

#
#   Process help and manual options
#
pod2usage(-verbose => 0, -message => "Version: $VERSION")  if ($opt_help == 1  || ! $result);
pod2usage(-verbose => 1)  if ($opt_help == 2);
pod2usage(-verbose => 2)  if ($opt_help > 2);

ErrorConfig( 'name'    =>'CC2SVN_REPOSCAN',
             'verbose' => $opt_verbose,
              );

#
#   Sanity test
#
Error ("Touch path is not a directory") if ( defined $opt_touch && ! -d $opt_touch );

foreach ( @opt_available )
{
    Error ("Available selector is not a directory: $_")
        unless ( -d $_ );
}

foreach ( @opt_exclude )
{
    Error ("Exclude selector is not a directory: $_")
        unless ( -d $_ );
}

if ($opt_repoExclude)
{
    foreach (split m/\s*,\s*/, $opt_repoExclude )
    {
        $excludeRepos{$_} = 1;
    }
}

#
#   Read in the Mapping Data
#
Message ("Read in Vob Mapping");

my $fname = 'cc2svn.repo.dat';
my $rname;
foreach my $base ( '' , '../' , '-' )
{
    Error ("Connot find file: $fname") if ( $base eq '-' );
    $rname = $base . $fname;
    last if ( -f $rname );
}
require $rname;

Error("Data in $fname is not valid")
    unless ( keys(%ScmRepoMap) >= 0 );

#
#   Filter Repos
#
my $keep = 0;
foreach my $pkgname ( keys %ScmRepoMap )
{
    my $entry = $ScmRepoMap{$pkgname};
    $keep = 1;

    unless ( $opt_all || $opt_protected)
    {
        if ( $entry->{protected} )
        {
            $keep = 0;
            next;
        }
    }

    if ( $opt_protected )
    {
        my $prot = $entry->{protected} ? $entry->{protected} :' ';
        $prot =~ m~(.)~;
        $prot = $1;
        if ( $prot eq 'B' )
        {
            $keep = 0;
            next;
        }
    }

    if ( $opt_repoExclude )
    {
        $entry->{repo} =~ m~^(.*?)(/|$)~;
        my $baseRepo = $1;
        if ( exists $excludeRepos{$baseRepo} || exists $excludeRepos{$entry->{repo}}  )
        {
            $keep = 0;
            next;
        }
    }

    my $avFound = 2;
    foreach my $basedir ( @opt_available )
    {
        if ( -f $basedir . '/' . $pkgname || -f $basedir . '/' . $pkgname . '.svg' )
        {
            $avFound = 1;
            last;
        }
        $avFound = 0;
    }
    unless ($avFound > 0)
    {
        $keep = 0;
        next;
    }

    foreach my $basedir ( @opt_exclude )
    {
        if ( -f $basedir . '/' . $pkgname || -f $basedir . '/' . $pkgname . '.svg' )
        {
            $keep = 0;
            last;
        }
    }
    next unless($keep);


    if ( $opt_repo )
    {
        unless ( $entry->{repo} =~ m~^$opt_repo($|/)~i )
        {
         $keep = 0;
         next;
        }
    }

    if ( defined $opt_age )
    {
        if ( $opt_age > $entry->{youngest} )
        {
            $keep = 0;
            next;
        }
    }

    if ( defined $opt_user )
    {
        if ( $opt_user > $entry->{ynr} )
        {
            $keep = 0;
            next;
        }
    }

    my $isSvn = exists ($entry->{SVN}) &&  $entry->{SVN};
    if (  !$opt_svn )
    {
        $keep = ! $isSvn;
    }
    next unless ( $keep );
}
continue
{
    delete $ScmRepoMap{$pkgname} unless ( $keep );
}

my $count = 0;
my $total = scalar keys %ScmRepoMap;
my @printOrder;

sub sortRepoName
{
    my $rv = lc $ScmRepoMap{$a}{repo} cmp lc $ScmRepoMap{$b}{repo};
    return $rv if ( $rv );
    return $a cmp $b
}

if ( $opt_ageorderUser ) {
    @printOrder = sort {$ScmRepoMap{$a}{ynr} <=> $ScmRepoMap{$b}{ynr}} keys %ScmRepoMap;
} elsif ( $opt_ageorder ) {
    @printOrder = sort {$ScmRepoMap{$a}{youngest} <=> $ScmRepoMap{$b}{youngest}} keys %ScmRepoMap;
} elsif ( $opt_reposort ) {
    @printOrder = sort sortRepoName keys %ScmRepoMap;
} else {
    @printOrder =  sort {$a cmp $b} keys %ScmRepoMap ;
}

my $lastRepo = '';
foreach my $pkgname ( @printOrder )
{
    $count++;
    if ( $opt_tail && ($count <= ($total - $opt_tail)) )
    {
        next;
    }

    my $entry = $ScmRepoMap{$pkgname};
    if ( $opt_onlyName )
    {
        my $prefix = '';
        if ($opt_reposort)
        {
            $prefix = '    ';
            if ( $entry->{repo} ne $lastRepo )
            {
                $lastRepo =  $entry->{repo};
                print  $lastRepo,"\n";
            }
        }
        print "$prefix$pkgname\n";
    }
    elsif ($opt_onlyFullName)
    {
        printf ("%-45s %s\n", $pkgname, $entry->{repo} );
    }
    else
    {

        my $repo = $entry->{repo};
        my $svn = $entry->{SVN} ? 'SVN' : '---';
        my $prot = $entry->{protected} ? $entry->{protected} :' ';
        $prot =~ m~(.)~;
        $prot = $1;

        my $youngest            = $entry->{youngest};
        my $youngestNonRipple   = $entry->{ynr};
        my $youngestNonBuildadm = $entry->{ynb};
    

        my $txt = sprintf ("Last:%5d, User:%5d, NonR:%5d, $svn $prot", $youngest, $youngestNonBuildadm, $youngestNonRipple);
        $txt .= sprintf (" %45s %s", $pkgname, $repo );
        print "$txt\n";
    }

    if ( $opt_touch )
    {
        TouchFile( $opt_touch .'/'.$pkgname);
        foreach my $basePath ( @opt_available )
        {
            unlink ($basePath . '/' . $pkgname);
            unlink ($basePath . '/' . $pkgname . '.svg');
        }
    }
}
print "Maching entires: $total\n";

#-------------------------------------------------------------------------------
#   Documentation
#

=pod

=for htmltoc    SYSUTIL::cc2svn::

=head1 NAME

cc2svn_reposcan - Scan Repo.dat file

=head1 SYNOPSIS

  jats cc2svn_reposcan

 Options:
    -help              - brief help message
    -help -help        - Detailed help message
    -man               - Full documentation
    -verbose           - Enable verbosity
   Package Selection
    -svn               - Include packages in SVN too
    -repo=name         - Select named repos (default all)
    -excludeRepo=name  - Exclude repos
    -age=nn            - Select last build age > nn
    -user=nn           - Select last user build age> nn
    -available=path    - Select if in named directory. Allow Multiple.
    -exclude=path      - Exclude if in named directory. Allow Multiple.
    -all               - Include Protected and Broken packages
    -protected         - Include Protected packages
   Output Sorting
    -byage             - Sort by last build age
    -byuser            - Sort by last User Mode age
    -byrepo            - Sort by repository name
   Display control
    -tail=nn           - Display last nn items
    -byname            - Only display package names
    -byfullname        - Only display package names and repo
   Process control
    -touch=path        - Create a file named after the package
                         Delete 'available' marker file

=head1 OPTIONS

=over 8

=item B<-help>

Print a brief help message and exits.

=item B<-help -help>

Print a detailed help message with an explanation for each option.

=item B<-man>

Prints the manual page and exits.

=item B<-available=path>

This option will limit the selection to packages that have a marker file in
the named directory. The marker file will be file with the same name
as the package or with a '.svg' extension.

When used in conjunction with the '-touch' option the marker file will be
deleted after the target marker file has been 'touched'.

=item B<-touch=path>

This option will populate a 'new' or test directory with packages. When used,
an empty file named after the package, will be created in the target path.

=back

=head1 DESCRIPTION

This program is a tool used in the conversion of ClearCase VOBS to subversion.

=head2 Examples

The follwoing command will:

 jats cc2svn_reposcan -repo=MASS_Dev_Infra -user=30 -byuser -available=. -touch=../new

Process packages in the MASS_Dev_Infra repository, selecting that that have
not been modified by a user for 30 days and that have a marker file in the
current directory. It will display the results sorted by the time since last
modified by a user. It will also create a marker file in the directory '../new'.

=cut

