########################################################################
# COPYRIGHT - VIX IP PTY LTD ("VIX"). ALL RIGHTS RESERVED.
#
# Module name   : jats.sh
# Module type   : Makefile system
# Compiler(s)   : n/a
# Environment(s): jats
#
# Description   : Get package information for a package name specified on the
#                 command line.
#
#                 Determine the package id
#                 Locate all packages that have the same package name
#
#                 Pump it into SVN
#
#                 Project Based Pumping
#
#......................................................................#

require 5.006_001;
use strict;
use warnings;
use JatsError;
use JatsRmApi;
use FileUtils;
use JatsSystem;


#use Data::Dumper;
use Cwd;
use DBI;
use Getopt::Long;
use Pod::Usage;                             # required for help support
my $RM_DB;

#my $opt_repo = 'https://auawsasvn001.vix.local/svn/COTS';
my $opt_repo_base = 'https://auawsasvn001.vix.local/svn/';
my $opt_repo;
my $opt_package;
my $opt_resume;
my $opt_flat;
my $opt_test;

my %Projects = (
    '.sea' => 'Seattle',
    '.coct' => 'CapeTown',
    '.sls'  => 'Stockholm',
    '.syd'  => 'Sydney',
    '.vtk'  => 'Vasttrafik',
    '.bei'  => 'Beijing',
    '.bkk'  => 'Bangkok',
    '.mas'  => 'Mass',
    '.ndl'  => 'NewDeli',
    '.nzs'  => 'NewZealandStageCoach',
    '.was'  => 'Washington',
    '.wdc'  => 'Washington',
);

my $newPackage = 1;
my $newProject = 1;

################################################################################
#   Global data
#
my $VERSION = "1.0.0";
my %ReleasePackages;            # Packages in the release
my %BuildPackages;              # Packages for this build
my $last_pv_id;
my $pkg_id;
my %versions;
my %suffixes;

#
#   Options
#
my $opt_help = 0;
my $opt_manual = 0;
my $opt_verbose = 0;

my $result = GetOptions (
                "help+"         => \$opt_help,          # Help
                "manual"        => \$opt_manual,        # Help
                "verbose+"      => \$opt_verbose,       # Versose
                "repository:s"  => \$opt_repo,          # Name of repository
                "resume:s"      => \$opt_resume,        # Resume at given version
                "flat!"         => \$opt_flat,          # Flat structure
                "test!"         => \$opt_test,          # Test operations
                );

#
#   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_manual || ($opt_help > 2));

#
#   Configure the error reporting process now that we have the user options
#
ErrorConfig( 'name'    =>'PLAY9d',
             'verbose' => $opt_verbose );

Error("No repository specified. ie -repo=DevTools, COTS") unless ( defined $opt_repo );
Error("Specify a package as 'name'" ) unless ( defined $ARGV[0] );

$opt_package = $ARGV[0];
$opt_repo = $opt_repo_base . $opt_repo;

Verbose( "Base Package: $opt_package");
Verbose( "Repo URL: $opt_repo");

#
#   Body of the process
#
GetPkgIdByName ( $opt_package );
GetData_by_pkg_id ( $pkg_id );

#
#   Generate backward links
#
foreach my $entry ( keys(%versions) )
{
    foreach ( @{ $versions{$entry}{next}} )
    {
        $versions{$_}{last} = $entry;
    }
}

#
#   Find start
#   Entry with no previous
#
my @startPoints;
my $last_entry = 0;
foreach my $entry ( keys(%versions) )
{
    unless ( exists $versions{$entry}{last} )
    {
        push @startPoints, $entry;
    }

    if ( $entry > $last_entry )
    {
        $last_entry = $entry;
    }
}

#
#   Walk backwards from the LAST entry and mark the main path through the tree
#
my $entry = $last_entry;
while ( $entry )
{
    $versions{$entry}{'main'} = 1;
    $entry = $versions{$entry}{last};
}

DebugDumpData ("Versions", \%versions );
DebugDumpData ("Starts", \@startPoints );
DebugDumpData ("Suffixes", \%suffixes);

#
#   Possibly flattern the output
#
if ( $opt_flat )
{
    %suffixes = ();
    foreach  ( keys %versions )
    {
        push @{$suffixes{''}}, $_;
    }
}

#
#   Display processing order
#   Do the real work
#
$newPackage = 1;
foreach my $suffix ( sort keys %suffixes )
{
    $newProject = 1;
    foreach my $entry (sort {$versions{$a}{version} cmp $versions{$b}{version}} @{$suffixes{$suffix}} )
    {
        next if ( $versions{$entry}{locked} eq 'N' );
#        print "--- Entry:",GetVname($entry)," Tag: ",$versions{$entry}{vcsTag},"\n";
        processPackage( $entry, $suffix );
    }
}

RmDirTree ('SvnImportDir');
Message ("All Done");
exit 99;


#-------------------------------------------------------------------------------
# Function        : processPackage
#
# Description     : Process a package version
#
# Inputs          : $entry              - Ref to entry being proccessed
#                   $suffix             - Project Suffix
#
# Returns         : 
#
sub processPackage
{
    my ($entry, $suffix) = @_;
    my $rv;
    my $ProjectName;

    print "--- Entry:",GetVname($entry)," Tag: ",$versions{$entry}{vcsTag},"\n";
    return if ( $opt_test );

    #
    #   Allow resumption
    #   Assumes a great deal ...
    #   Designed to allow manual recovery
    #
    if ( $opt_resume )
    {
        if ( $opt_resume ne GetVname($entry) )
        {
            $newProject = 0;
            $newPackage = 0;
            return;
        }
        $opt_resume = undef;
    }

    #
    #   First entry being created
    #   Prime the work area
    #
    if ( $newPackage )
    {
        SystemConfig ('ExitOnError' => 1);
        JatsToolPrint ( 'jats_svn', 'delete-package', '-noerror',  "$opt_repo/$opt_package" );
        JatsToolPrint ( 'jats_svn', 'create', "$opt_repo/$opt_package" );
        RmDirTree ('SvnImportDir');
        $newPackage = 0;
    }

    #
    #   New project
    #   Kill the running import directory
    #
    if ( $newProject )
    {
        RmDirTree ('SvnImportDir');
        $newProject = 0;
    }

    #
    #   Determine version information
    #
    my $opt_label = $opt_package . '_' . GetVname($entry);

    my $tag = $versions{$entry}{vcsTag} || '';
    $tag =~ s~\\~/~g;
    $tag =~ m~^(.+?)::(.*?)(::(.+))?$~;

    my $opt_path = $2 || '';
    $opt_path =~ s~\\~/~g;
    $opt_path =~ s~//~/~g;

    my $cc_label = $4;
    if ( !defined $opt_path || ! defined $cc_label )
    {
        print "--- (E) Error: Bad Config Spec for:",GetVname($entry),"\n";
        return;
    }
print "--- Path: $opt_path, Label: $cc_label\n";

    my @author;
    my $author = $versions{$entry}{created_id};
    if ( $author )
    {
        push @author, '-author', $author;
    }
    my $created = $versions{$entry}{created};
    if ( $created )
    {
        $created =~ s~ ~T~;
        $created .= '00000Z';
        push @author, '-date', $created;
    }

    my $log = $versions{$entry}{comment};
    if ( $log )
    {
        push @author, '-log', $log;
    }

    #
    #   Projects are stored on a branch
    #
    if ( $suffix )
    {
        Error ("Unknown Project: $suffix") unless ( defined $Projects{$suffix} );
        $ProjectName = $Projects{$suffix};
    }
    
    #
    #   Create CC view
    #   Import into Subversion View
    #
    SystemConfig ('ExitOnError' => 0);
    $rv = JatsToolPrint ( 'jats_ccrelease', '-extractfiles', '-root=.' , '-noprefix',
                    "-label=$cc_label" ,
                    "-path=$opt_path");

    unless ( $rv )
    {
        SystemConfig ('ExitOnError' => 1);
        my $import_label = $opt_label;
        $import_label = $cc_label if ( $cc_label =~ m~WIP$~ );

        JatsToolPrint ( 'jats_svn', 'import', '-reuse' ,
                        "-package=$opt_repo/$opt_package",
                        "-dir=$cc_label/$opt_path",
                        "-label=$import_label",
                        "-branch=$ProjectName",
                        @author
                         );
    };

    #
    #   Delete the created view
    #   Its just a directory, so delete it
    #
    RmDirTree ($cc_label) if -d ($cc_label);
}

sub JatsToolPrint
{
    Information ("Command: @_");
    JatsTool @_;
}

sub GetVname
{
    my ($entry) = @_;
    my $me = $versions{$entry}{vname};
    unless ( $me )
    {
        $me = 'Unknown-' . $entry;
    }
    return $me;
}

exit 0;


#-------------------------------------------------------------------------------
# Function        : GetPkgIdByName
#
# Description     :
#
# Inputs          : pkg_name
#
# Returns         :
#
sub GetPkgIdByName
{
    my ( $pkg_name ) = @_;
    my (@row);
    my $pv_id;

    #
    #   Establish a connection to Release Manager
    #
    connectRM(\$RM_DB) unless ( $RM_DB );

    #
    #   Extract data from Release Manager
    #
    my $m_sqlstr = "SELECT pkg.PKG_NAME, pkg.PKG_ID" .
                   " FROM RELEASE_MANAGER.PACKAGES pkg" .
                   " WHERE pkg.PKG_NAME = \'$pkg_name\'";
                   
    my $sth = $RM_DB->prepare($m_sqlstr);
    if ( defined($sth) )
    {
        if ( $sth->execute( ) )
        {
            if ( $sth->rows )
            {
                while ( @row = $sth->fetchrow_array )
                {
                    Verbose( "DATA: " . join(',', @row) );
                    $pkg_id = $row[1] || 0;
                    last;
                }
            }
            else
            {
                Error ("GetPkgIdByName:No Data for package: $pkg_name");
            }
            $sth->finish();
        }
    }
    else
    {
        Error("GetPkgIdByName:Prepare failure" );
    }
}

#-------------------------------------------------------------------------------
# Function        : GetData_by_pkg_id
#
# Description     :
#
# Inputs          : pv_id
#
# Returns         :
#
sub GetData_by_pkg_id
{
    my ( $pkg_id ) = @_;
    my (@row);

    #
    #   Establish a connection to Release Manager
    #
    connectRM(\$RM_DB) unless ( $RM_DB );

    #
    #   Extract data from Release Manager
    #
    my $m_sqlstr = "SELECT pkg.PKG_NAME, pv.PKG_VERSION, pkg.PKG_ID, pv.PV_ID, pv.LAST_PV_ID, pv.MODIFIED_STAMP, release_manager.PK_RMAPI.return_vcs_tag(pv.PV_ID), amu.USER_NAME, pv.COMMENTS, pv.DLOCKED ".
                   " FROM RELEASE_MANAGER.PACKAGES pkg, RELEASE_MANAGER.PACKAGE_VERSIONS pv, ACCESS_MANAGER.USERS amu" .
                   " WHERE pv.PKG_ID = \'$pkg_id\' AND pkg.PKG_ID = pv.PKG_ID AND pv.CREATOR_ID = amu.USER_ID";
                   
                   
    my $sth = $RM_DB->prepare($m_sqlstr);
    if ( defined($sth) )
    {
        if ( $sth->execute( ) )
        {
            if ( $sth->rows )
            {
                while ( @row = $sth->fetchrow_array )
                {
                    Verbose( "DATA: " . join(',', @row) );
                    my $pkg_name = $row[0] || 'Unknown';
                    my $pkg_ver = $row[1] || 'Unknown';
                    my $pv_id = $row[3] || 'Unknown';
                    my $last_pv_id = $row[4] || 'Unknown';
                    my $created =  $row[5] || 'Unknown';
                    my $vcstag =  $row[6] || 'Unknown';
                    my $created_id =  $row[7] || 0;
                    my $comment =  $row[8] || '';
                    my $locked =  $row[9] || 'N';

                    #
                    #   Add data to the hash
                    #       Remove entries that address themselves
                    #
                    push (@{$versions{$last_pv_id}{next}}, $pv_id) unless ($pv_id == $last_pv_id) ;
                    $versions{$pv_id}{vname} = $pkg_ver;
                    $versions{$pv_id}{vcsTag} = $vcstag;
                    $versions{$pv_id}{created} = $created;
                    $versions{$pv_id}{created_id} = $created_id;
                    $versions{$pv_id}{comment} = $comment;
                    $versions{$pv_id}{locked} = $locked;

                    #
                    #   Convert version into full form for comparisions
                    #
                    my $version = $pkg_ver;
                    my $suffix;
                    if ( $version =~ m~(.*)\.cots$~ ) {
                        my $cots_base = $1;
                        $suffix = '.cots';
                        unless ( $version =~ m~(.*)(\.[0-9]4)\.cots~ )
                        {
                            $version = $cots_base . '.0000.cots';
                        }
                    }
                    elsif ( $version =~ m~(\d+)\.(\d+)\.(\d+)(\.(.*))?~ )
                    {
                        my $patch = $3;
                        my $build = '000';
                        if ( length( $patch) >= 4 )
                        {
                            $build = substr( $patch, -3 ,3);
                            $patch = substr( $patch,  0 ,length($patch)-3);
                        }

                        $version = sprintf("%3.3d.%3.3d.%3.3d.%3.3d%s", $1,$2,$patch,$build,$4 || '.0000');
                        $suffix = $4 || '';
                    }
                    else
                    {
                        $pkg_ver =~ m~(\.\w+)$~;
                        $suffix = $1 || '';
                    }
                    $versions{$pv_id}{version} = $version;

                    #
                    #   Process suffix
                    #
                    $suffix = 'Unknown' unless ( $suffix );
                    $suffix = lc ($suffix);
                    $versions{$pv_id}{suffix} = $suffix;
                    push @{$suffixes{$suffix}}, $pv_id;


                    print "$pkg_name, $pkg_ver, $pv_id, $last_pv_id, $created, $created_id, $suffix\n";
                }
            }
            else
            {
                Error ("GetData_by_pkg_id: No Data: $m_sqlstr");
            }
            $sth->finish();
        }
        else
        {
                Error ("GetData_by_pkg_id: Execute: $m_sqlstr");
        }
    }
    else
    {
        Error("GetData_by_pkg_id:Prepare failure" );
    }
}

