#! perl
########################################################################
# 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   : Walk compete dependency tree to locate all package versions
#                 Generate a build order
#                 Generate only for parts not already built on "win32"
#
#                 Currently hard coded to BEIJING (BEI) > R2
#
# Usage:
#
# Version   Who      Date        Description
#
#......................................................................#

require 5.006_001;
use strict;
use warnings;
use JatsError;
use JatsSystem;
use Getopt::Long;
use Pod::Usage;                             # required for help support
use JatsRmApi;

use DBI;

my $VERSION = "1.2.3";                      # Update this
my $opt_verbose = 1;
my $opt_help = 0;
my $opt_manual;
my $opt_rtag_id = 5702;                     #  5702 BEIJING (BEI) > R2
my $opt_no_ver = 1;
my $RM_DB;

#
#   Package information
#
my %Package;
my @StrayPackages;

#-------------------------------------------------------------------------------
# Function        : Main Entry
#
# Description     :
#
# Inputs          :
#
# Returns         :
#
my $result = GetOptions (
                "help+"         => \$opt_help,          # flag, multiple use allowed
                "manual"        => \$opt_manual,        # flag
                "verbose+"      => \$opt_verbose,       # flag
                "rtag_id=s"     => \$opt_rtag_id,       # string
                "ignorever!"    => \$opt_no_ver,        # [no]flag
                );

#
#   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));

ErrorConfig( 'name'    =>'PLAY14' );

Error ("No RTAGID specified") unless ( $opt_rtag_id );

getPkgDetailsByRTAG_ID($opt_rtag_id);
LocateStrays();
BuildOrder();
#DebugDumpData ("Package", \%Package );

exit;

sub getPkgDetailsByRTAG_ID
{
    my ($RTAG_ID) = @_;
    my $foundDetails = 0;
    my (@row);

    # if we are not or cannot connect then return 0 as we have not found anything
    connectRM( \$RM_DB);

    # First get details from pv_id

    my $m_sqlstr = "SELECT pv.PV_ID, pkg.PKG_NAME, pv.PKG_VERSION, pv.PKG_LABEL, pv.SRC_PATH, pv.BUILD_TYPE, pv.IS_DEPLOYABLE, rc.BASE_VIEW_ID" .
                    " FROM RELEASE_CONTENT rc, PACKAGE_VERSIONS pv, PACKAGES pkg" .
                    " WHERE rc.RTAG_ID = $RTAG_ID AND rc.PV_ID = pv.PV_ID AND pv.PKG_ID = pkg.PKG_ID";
    my $sth = $RM_DB->prepare($m_sqlstr);
    if ( defined($sth) )
    {
        if ( $sth->execute( ) )
        {
            if ( $sth->rows )
            {
                while ( @row = $sth->fetchrow_array )
                {
                    my $pv_id = $row[0];
                    my $name = $row[1];
                    my $ver = $row[2];
                    my $label = $row[3] || '';
                    my $path = $row[4] || '';
                    my $deployable = $row[6];
                    my $base_id = $row[7] || '';

                    if ($opt_no_ver)
                    {
                        push @{$Package{$name}{'xxx'}{ver_list}}, $ver;
                        $ver = 'xxx';
                    }

                    $path =~ tr~\\/~/~s;
#print "$row[5] --";
#printf ( "%40s %15s %50s %s\n",  $name, $ver, $label, $path);
#printf ( "copy e:\\%s\\%s .\n",  $name, $ver, $label, $path);
#print "$name $ver\n";
                    $Package{$name}{$ver}{done} = 1;
                    $Package{$name}{$ver}{base} = 1;
                    $Package{$name}{$ver}{base_id} = $base_id;
                    $Package{$name}{$ver}{deployable} = 1 if ($deployable);
                    GetDepends( $pv_id, $name, $ver );
                }
            }
            $sth->finish();
        }
    }
    else
    {
        Error("Prepare failure" );
    }

#    $globals->{RM_CONN}->disconnect() || Error ("Disconnect failed");
}

#-------------------------------------------------------------------------------
# Function        : GetDepends
#
# Description     : Extract the dependancies for a given package version
#
# Inputs          : $pvid
#
# Returns         :
#
sub GetDepends
{
    my ($pv_id, $pname, $pver ) = @_;

    #
    #   Now extract the package dependacies
    #
    my $m_sqlstr = "SELECT pkg.PKG_NAME, pv.PKG_VERSION, pd.DPV_ID, pv.IS_DEPLOYABLE" .
                   " FROM PACKAGE_DEPENDENCIES pd, PACKAGE_VERSIONS pv, PACKAGES pkg" .
                   " WHERE pd.PV_ID = \'$pv_id\' AND pd.DPV_ID = pv.PV_ID AND pv.PKG_ID = pkg.PKG_ID";
    my $sth = $RM_DB->prepare($m_sqlstr);
    if ( defined($sth) )
    {
        if ( $sth->execute( ) )
        {
            if ( $sth->rows )
            {
                my %depends;
                while ( my @row = $sth->fetchrow_array )
                {
#                    print "$name ===== @row\n";
                    my $name = $row[0];
                    my $ver = $row[1];
                    my $deployable = $row[3];

                    if ($opt_no_ver)
                    {
                        push @{$Package{$name}{'xxx'}{ver_list}}, $ver;
                        $ver = 'xxx';
                    }
                    
                    $depends{$name}{$ver} = 1;
                    push @{$Package{$name}{$ver}{usedby}}, [ $pname, $pver ];

                    unless ( exists $Package{$name}{$ver}{done} )
                    {
                        $Package{$name}{$ver}{needed} = 1;
                        $Package{$name}{$ver}{deployable} = 1 if ($deployable);

                        my @DATA = ($name, $ver, $row[2]);
                        push @StrayPackages, \@DATA;
                    }
                }
                $Package{$pname}{$pver}{depends} = \%depends;
            }
            $sth->finish();
        }
    }
    else
    {
        Error("GetDepends:Prepare failure" );
    }
}

#-------------------------------------------------------------------------------
# Function        : LocateStrays
#
# Description     :
#
# Inputs          :
#
# Returns         :
#
sub LocateStrays
{

    while ( $#StrayPackages >= 0 )
    {
        my $DATA = pop @StrayPackages;
        my $name = $DATA->[0];
        my $ver = $DATA->[1];
        my $pv_id = $DATA->[2];

        next if ( exists $Package{$name}{$ver}{done} );
        GetDepends(  $pv_id, $name, $ver );
        $Package{$name}{$ver}{done} = 1;
    }
}

#-------------------------------------------------------------------------------
# Function        : BuildOrder
#
# Description     : Determine the order to build packages
#
# Inputs          :
#
# Returns         :
#
sub BuildOrder
{
#    DebugDumpData ("Package", \%Package); exit 1;

    my $more = 1;
    my $level = 0;
    while ( $more )
    {
        my %build;
        $level ++;
        $more = 0;
        foreach my $name ( keys %Package )
        {

            #
            #   Locate packges with no dependencies left
            #
            foreach my $ver ( keys %{$Package{$name}} )
            {
                next if ( keys %{$Package{$name}{$ver}{depends}} );
                $build{$name}{$ver} = 1;

            }
        }

        foreach my $name ( keys %build )
        {
            foreach my $ver ( keys %{$build{$name}} )
            {
                $more = 1;
                print "Build($level): $name, $ver\n";
                delete $Package{$name}{$ver};
                delete $Package{$name} unless keys %{$Package{$name}{$ver}};
            }
        }

        #
        #   Delete dependencies
        #

        foreach my $name ( keys %Package )
        {
            foreach my $ver ( keys %{$Package{$name}} )
            {
                next unless ( keys %{$Package{$name}{$ver}{depends}} );
                foreach my $tname ( keys %build )
                {
                    foreach my $tver ( keys %{$build{$tname}} )
                    {
                        delete $Package{$name}{$ver}{depends}->{$tname}{$tver};
                        delete $Package{$name}{$ver}{depends}->{$tname} unless keys %{$Package{$name}{$ver}{depends}->{$tname}} ;
                    }
                }
            }
        }
    }
}


