########################################################################
# COPYRIGHT - VIX IP PTY LTD ("VIX"). ALL RIGHTS RESERVED.
#
# Module name   : shellbuild_windows.pl
# Module type   : Makefile system
# Compiler(s)   : Perl
# Environment(s): jats
#
# Description   : Script invoked by Makefile system to do the hard work
#                 of building COTS windows packages.
#
#......................................................................#

require 5.008_002;
use strict;
use warnings;
use File::Basename;
use File::Copy;
use File::Path;


use Pod::Usage;
use Getopt::Long;
use Cwd 'abs_path';

use JatsError;
use FileUtils;
use JatsSystem;
use JatsCopy;

#
#   Options
#
my $opt_debug   = $ENV{'GBE_DEBUG'};        # Allow global debug
my $opt_verbose = $ENV{'GBE_VERBOSE'};      # Allow global verbose
my $opt_help = 0;

my $opt_CLEAN = '';
my $opt_SHELLBUILD = '';
my $opt_BUILD_NAME = '';
my $opt_BUILD_VERSION = '';
my $opt_PLATFORM = '';
my $opt_TYPE = '';
my $opt_MACHTYPE = '';
my $opt_BUILD_ROOT = '';
my $opt_INTERFACE_DIR = '';
my $opt_LOCAL_DIR = '';
my $opt_LOCAL_INC_DIR = '';
my $opt_LOCAL_LIB_DIR = '';
my $opt_LOCAL_BIN_DIR = '';
my $opt_BIN_DIR = '';
my $opt_OBJ_DIR = '';
my $opt_LIB_DIR = '';
my $opt_PKG_BIN_DIR = '';
my $opt_PKG_INC_DIR = '';
my $opt_PKG_LIB_DIR = '';
my $opt_PKG_PKG_DIR = '';
my $opt_PKG_DIR = '';
my $opt_PKG_TOOL_DIR = '';
my $opt_PKG_TOOL_BIN_DIR = '';
my $opt_ISA_TOOLSET = 0;
my $opt_PKG_TOOL_SCRIPT_DIR = '';
my $opt_DOWNLOAD_PKG = '';
my $opt_PATCHES_DIR = 'patches';

my @ConfigMsg;

my $opt_SCRIPT=abs_path($0);
my $opt_SCRIPT_DIR=dirname($opt_SCRIPT);


#
#   Debug support
#   Allow the following build operations to be optionally performed
#
my $DO_CLEAN        = 1;
my $DO_DOWNLOAD     = 1;
my $DO_PATCHES      = 1;
my $DO_CONFIGURE    = 1;
my $DO_MAKE         = 1;
my $DO_INSTALL      = 1;

my $DO_BASH         = 0;

#-------------------------------------------------------------------------------
# Function        : ConfigMsg
#
# Description     : Display a simple message
#                   Retain message text for ue in config dump
#
# Inputs          : Array of message text
#
# Returns         : 
#
sub ConfigMsg
{
    Message (@_);
    push @ConfigMsg, @_;
}

#------------------------------------------------------------------------------
# Extract arguments - order not important except that the first argument is
# the launch script
#------------------------------------------------------------------------------

my $result = GetOptions (
                "help+"                 => \$opt_help,
                "manual:3"              => \$opt_help,
                "verbose+"              => \$opt_verbose,

                "clean"                 => \$opt_CLEAN,
                "ShellBuild=s"          => \$opt_SHELLBUILD,
                "BuildName=s"           => \$opt_BUILD_NAME,
                "BuildVersion=s"        => \$opt_BUILD_VERSION,
                "Platform=s"            => \$opt_PLATFORM,
                "Type=s"                => \$opt_TYPE,
                "MachType=s"            => \$opt_MACHTYPE,
                "BuildRoot=s"           => \$opt_BUILD_ROOT,
                "InterfaceDir=s"        => \$opt_INTERFACE_DIR,
                "LocalDir=s"            => \$opt_LOCAL_DIR,
                "LocalIncDir=s"         => \$opt_LOCAL_INC_DIR,
                "LocalLibDir=s"         => \$opt_LOCAL_LIB_DIR,
                "LocalBinDir=s"         => \$opt_LOCAL_BIN_DIR,
                "BinDir=s"              => \$opt_BIN_DIR,
                "ObjDir=s"              => \$opt_OBJ_DIR,
                "LibDir=s"              => \$opt_LIB_DIR,
                "PackageBinDir=s"       => \$opt_PKG_BIN_DIR,
                "PackageIncDir=s"       => \$opt_PKG_INC_DIR,
                "PackageLibDir=s"       => \$opt_PKG_LIB_DIR,
                "PackagePkgDir=s"       => \$opt_PKG_PKG_DIR,
                "PackageDir=s"          => \$opt_PKG_DIR,
                "PackageToolDir=s"      => \$opt_PKG_TOOL_DIR,
                "PackageToolBin=s"      => \$opt_PKG_TOOL_BIN_DIR,
                "PackageToolScript=s"   => \$opt_PKG_TOOL_SCRIPT_DIR,
                "DownloadPkg=s"         => \$opt_DOWNLOAD_PKG,
                "PatchesDir=s"          => \$opt_PATCHES_DIR,
                "Toolset"               => \$opt_ISA_TOOLSET,
                );

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


#   Determine the location of the generated files
#   Will simplify processing later
#
$opt_SHELLBUILD=FullPath($opt_SHELLBUILD);
$opt_BUILD_ROOT=FullPath($opt_BUILD_ROOT);
$opt_INTERFACE_DIR=FullPath($opt_INTERFACE_DIR);
$opt_LOCAL_DIR=FullPath ($opt_LOCAL_DIR);
$opt_LOCAL_INC_DIR=FullPath ($opt_LOCAL_INC_DIR);
$opt_LOCAL_LIB_DIR=FullPath ($opt_LOCAL_LIB_DIR);
$opt_LOCAL_BIN_DIR=FullPath ($opt_LOCAL_BIN_DIR);

$opt_PKG_BIN_DIR=FullPath ($opt_PKG_BIN_DIR);
$opt_PKG_INC_DIR=FullPath ($opt_PKG_INC_DIR);
$opt_PKG_LIB_DIR=FullPath ($opt_PKG_LIB_DIR);
$opt_PKG_PKG_DIR=FullPath ($opt_PKG_PKG_DIR);
$opt_PKG_DIR=FullPath ($opt_PKG_DIR);

$opt_PKG_TOOL_DIR=FullPath ($opt_PKG_TOOL_DIR);
$opt_PKG_TOOL_BIN_DIR=FullPath($opt_PKG_TOOL_BIN_DIR);
$opt_PKG_TOOL_SCRIPT_DIR=FullPath($opt_PKG_TOOL_SCRIPT_DIR);


#------------------------------------------------------------------------------
# Dump JATS information for debugging purposes
#------------------------------------------------------------------------------
Message "================================================================================";
Message "   JATS SUPPLIED FIELDS";
Message "================================================================================";
ConfigMsg " BuildName         = $opt_BUILD_NAME $opt_BUILD_VERSION";
ConfigMsg " Script            = $opt_SCRIPT";
ConfigMsg " ScriptDir         = $opt_SCRIPT_DIR";
ConfigMsg " ShellBuild        = $opt_SHELLBUILD";
ConfigMsg " Platform          = $opt_PLATFORM";
ConfigMsg " Type              = $opt_TYPE";
ConfigMsg " MachType          = $opt_MACHTYPE";
ConfigMsg " BuildRoot         = $opt_BUILD_ROOT";
ConfigMsg " InterfaceDir      = $opt_INTERFACE_DIR";
ConfigMsg " LocalDir          = $opt_LOCAL_DIR";
ConfigMsg " LocalIncDir       = $opt_LOCAL_INC_DIR";
ConfigMsg " LocalLibDir       = $opt_LOCAL_LIB_DIR";
ConfigMsg " LocalBinDir       = $opt_LOCAL_BIN_DIR";
ConfigMsg " BinDir            = $opt_BIN_DIR";
ConfigMsg " ObjDir            = $opt_OBJ_DIR";
ConfigMsg " LibDir            = $opt_LIB_DIR";
ConfigMsg " PackageBinDir     = $opt_PKG_BIN_DIR";
ConfigMsg " PackageIncDir     = $opt_PKG_INC_DIR";
ConfigMsg " PackageLibDir     = $opt_PKG_LIB_DIR";
ConfigMsg " PackagePkgDir     = $opt_PKG_PKG_DIR";
ConfigMsg " PackageDir        = $opt_PKG_DIR";
ConfigMsg " PackageToolDir    = $opt_PKG_TOOL_DIR";
ConfigMsg " PackageToolBin    = $opt_PKG_TOOL_BIN_DIR";
ConfigMsg " PackageToolScript = $opt_PKG_TOOL_SCRIPT_DIR";
ConfigMsg " DownloadPkg       = $opt_DOWNLOAD_PKG";
ConfigMsg " PatchesDir        = $opt_PATCHES_DIR";
ConfigMsg " Toolset           = $opt_ISA_TOOLSET";
Message "================================================================================";



# Calculate the relative directory locations
my $BASE_DIR=$opt_BUILD_ROOT;
my $DOWNLOADS_DIR="$BASE_DIR/downloads";
my $SRC_DIR="$BASE_DIR/src";

# Find the downloaded package
my $TARBALL_FILE="$DOWNLOADS_DIR/$opt_DOWNLOAD_PKG";
my $TAR_DECOMP_ARG;
my $ZIP_DECOMP_ARG;
my $ext;

if ( -e $TARBALL_FILE . ".tar.bz2" ) {
    $TARBALL_FILE=$TARBALL_FILE . ".tar.bz2";
    $TAR_DECOMP_ARG='j';
    $ext = '.tar.bz2';
} elsif ( -e $TARBALL_FILE . ".tar.gz" ) {
    $TARBALL_FILE=$TARBALL_FILE . ".tar.gz";
    $TAR_DECOMP_ARG='z';
    $ext = '.tar.gz';
} elsif ( -e $TARBALL_FILE . ".tgz" ) {
    $TARBALL_FILE=$TARBALL_FILE . ".tgz";
    $TAR_DECOMP_ARG='z';
    $ext = '.tgz';
} elsif ( -e $TARBALL_FILE . ".tar" ) {
    $TARBALL_FILE=$TARBALL_FILE . ".tar";
    $ext = '.tar';
} elsif ( -e $TARBALL_FILE . ".zip" ) {
    $TARBALL_FILE=$TARBALL_FILE . ".zip";
    $ZIP_DECOMP_ARG='x';
    $ext = '.zip';
} else {
    Error ("Could not find download file $TARBALL_FILE.<tar.gz|tar.bz2|tgz|zip>");
}

my $UNTAR_DIR="$SRC_DIR/$opt_DOWNLOAD_PKG";
my $WORK_DIR = "$UNTAR_DIR.$opt_PLATFORM$opt_TYPE";
my $PATCH_DIR= "$BASE_DIR/$opt_PATCHES_DIR";

# Dump configuration
Message "================================================================================";
Message "   BUILD CONFIGURATION";
Message "================================================================================";
ConfigMsg " Base Dir       = $BASE_DIR";
ConfigMsg " Tarball File   = $TARBALL_FILE";
ConfigMsg " Working Dir    = $WORK_DIR";
Message "================================================================================";

# Prepare the environment
Message " --> Preparing environment";

#
#   Clean it up - if requested
#
if ( $opt_CLEAN )
{
    Message " --> Cleaning generated files";
    DeleteDir( $UNTAR_DIR );
    DeleteDir( $WORK_DIR );
    if ( -d $UNTAR_DIR)
    {
        Error("Could not delete directory $UNTAR_DIR");
    }
    if ( -d $WORK_DIR)
    {
        Error("Could not delete directory $WORK_DIR");
    }
    exit (0);
}

#
#   Download and unzip/untar the source package
#
if ( ! -d  $WORK_DIR )
{
    $DO_DOWNLOAD = 1;
}

if ( $DO_DOWNLOAD )
{
    Message " --> Deleting existing build objects directory";
    DeleteDir( $UNTAR_DIR );
    DeleteDir( $WORK_DIR );
    if ( -d $UNTAR_DIR )
    {
        Error("Could not delete directory $UNTAR_DIR");
    }
    if ( -d $WORK_DIR )
    {
        Error("Could not delete directory $WORK_DIR");
    }

    Message " --> Extracting $TARBALL_FILE";
    $DO_PATCHES = 1;
    chdir $SRC_DIR || Error ("Cannot cd to $SRC_DIR");
    if ( $TAR_DECOMP_ARG )
    {
        #
        # Extract tar from archive
        # Extract files from tar
        #
        my $tfile = $opt_DOWNLOAD_PKG . '.tar';

        System ('7z', 'e', $TARBALL_FILE, '-y');
        System ('7z', 'x', $tfile, '-y' );
        unlink $tfile;
    }
    else
    {
        System ('7z', 'x', $TARBALL_FILE, '-y' );
    }
    
    # Make sure it exists in the expected directory.
    if ( ! -d $UNTAR_DIR ) {
        Error ("Decompression to $UNTAR_DIR did not occur as expected");
    }
    
    # It does exist, so move it to the TARBALL directory we expect.
    rename $UNTAR_DIR,$WORK_DIR || Error("Could not move $UNTAR_DIR to $WORK_DIR");
    
}
else
{
    Message " --> Keep downloaded package";
}
chdir $WORK_DIR || Error ("Cannot cd to $WORK_DIR");

#
#   Apply local patches
#
if ( $DO_PATCHES )
{
    my $patch_script = "$opt_SCRIPT_DIR/patch.pl";
    Message " --> Patch script found at $patch_script";

    my @patches = glob("$PATCH_DIR/*.patch");
    @patches = sort @patches;
    foreach (@patches) {
        my $patch=$_;
        Message " --> Applying patch: $patch";
        System ("perl $patch_script -p1 < $patch");
    }

    @patches = glob("$PATCH_DIR/*.patch.$opt_PLATFORM");
    @patches = sort @patches;
    foreach (@patches) {
        my $patch=$_;
        Message " --> Applying platform patch: $patch";
        System ("perl $patch_script -p1 < $patch");
    }

}

#
#   Call the build script - first setup the environment, then enter the script.
#

ExportDir('WORK_DIR', $WORK_DIR);
$ENV{DOWNLOAD_PKG}=$opt_BUILD_NAME;
$ENV{PLATFORM}=$opt_PLATFORM;
$ENV{TYPE}=$opt_TYPE;

ExportDir('PKG_DIR'    , $opt_PKG_DIR    );
ExportDir('PKG_BIN_DIR', $opt_PKG_BIN_DIR);
ExportDir('PKG_INC_DIR', $opt_PKG_INC_DIR);
ExportDir('PKG_LIB_DIR', $opt_PKG_LIB_DIR);
ExportDir('PKG_PKG_DIR', $opt_PKG_PKG_DIR);

ExportDir('LOCAL_DIR'    , $opt_LOCAL_DIR    );
ExportDir('LOCAL_BIN_DIR', $opt_LOCAL_BIN_DIR);
ExportDir('LOCAL_INC_DIR', $opt_LOCAL_INC_DIR);
ExportDir('LOCAL_LIB_DIR', $opt_LOCAL_LIB_DIR);

ExportDir('BIN_DIR'    , $opt_BIN_DIR    );
ExportDir('OBJ_DIR'    , $opt_OBJ_DIR    );
ExportDir('LIB_DIR'    , $opt_LIB_DIR    );

if ($opt_ISA_TOOLSET)
{
    ExportDir('PKG_TOOL_DIR'        ,$opt_PKG_TOOL_DIR );
    ExportDir('PKG_TOOL_BIN_DIR'    ,$opt_PKG_TOOL_BIN_DIR );
    ExportDir('PKG_TOOL_SCRIPT_DIR' ,$opt_PKG_TOOL_SCRIPT_DIR );
    $ENV{PKG_TOOL_ISA_TOOLSET}=1;
}

ExportDir('INTERFACE_DIR'     , $opt_INTERFACE_DIR);
ExportDir('INTERFACE_LIB_DIR' , "$opt_INTERFACE_DIR/lib/$opt_PLATFORM");
ExportDir('INTERFACE_INC_DIR' , "$opt_INTERFACE_DIR/include");

# Clean-up the various flags that can impact nmake.
$ENV{MAKEFLAGS}='';
$ENV{MAKE}='';

$opt_SHELLBUILD=~tr{/}{\\};
$result=System("$opt_SHELLBUILD");
if ($result != 0 ) 
{
    Error("Shell build failed with code $result");
}

Message " --> All Done";
exit 0;

#-------------------------------------------------------------------------------
# Function        : ExportDir 
#
# Description     : Export a directory into the Windows environment 
#
# Inputs          : VarName     - Target Var Name
#                   Data        - Data to set     
#
# Returns         : Cleaned up data  
#
sub ExportDir
{
    my ($varName, $data) = @_;
    $data=~tr{/}{\\};
    $ENV{$varName} = $data;

    return $data;
}
