#! 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   : Transform a file
#                 This is a JATS command line utility that can be used to:
#                   1) Copy a file
#                   2) Perform DOS <-> Unix converion
#                   3) Perform tag substitution
#
# Usage:    jats_transform_file
#               -infile=xxxxx
#               -outfile=yyyyyyy
#               -dos2unix, -unix2dos
#               -tag=tag,value
#
#               The utilty may be used by user scripts
#               The utilty may be used within GenerateFiles
#
#......................................................................#

require 5.006_001;
use strict;
use warnings;

use JatsError;
use FileUtils;

use File::Copy;
use Getopt::Long;
use Pod::Usage;                             # required for help support


################################################################################
#   Option variables
#

my $VERSION = "1.0.0";                      # Update this
my $opt_verbose = 0;
my $opt_datafile = "";
my $opt_ofile;
my $opt_infile;
my $opt_help = 0;
my $opt_manual;
my $opt_2dos;
my $opt_2unix;
my @opt_tags;
my $opt_tsep = ',';

#   Globals
#
my @tag_order;
my %tags;                                      # Tags data

my $result = GetOptions (
                "help+"     => \$opt_help,          # flag, multiple use allowed
                "manual"    => \$opt_manual,        # flag
                "verbose+"  => \$opt_verbose,       # flag
                "outfile=s" => \$opt_ofile,         # string
                "infile=s"  => \$opt_infile,        # string
                "unix"      => \$opt_2unix,         # flag
                "dos"       => \$opt_2dos,          # flag
                "tag=s"     => \@opt_tags,          # flag
                "tsep=s"    => \$opt_tsep,          # 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));

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

#
#   Allow two command line argumenst to be infile and outfile
#
unless ( $opt_infile || $opt_ofile )
{
    $opt_infile = shift @ARGV;
    $opt_ofile =  shift @ARGV;
}

#
#   Sanity test the user arguemnts
#
Error ("Too many command line arguments: @ARGV" )
    if ( $#ARGV >= 0 );

Error ("No Input File specified")
    unless ( $opt_infile );

Error ("Input File is a directory")
    if ( -d $opt_infile );

Error ("Input File does not exist")
    unless ( -e $opt_infile );

Error ("No Output File specified" )
    unless ( $opt_ofile );

Error ("Input and output file are the same" )
    if ( $opt_infile eq $opt_ofile );

Error ("Select one of DOS or UNIX line endings" )
    if ( $opt_2unix && $opt_2dos );

#
#   Determine the output directory
#   Ensure that it exists
#
my $tdir = StripFileExt( $opt_ofile );
Verbose ("Target directory: $tdir");
Error ("Target directory does not exist: $tdir")
    if ( $tdir && ! -d $tdir );

Verbose ("Create DOS line endings" ) if ( $opt_2dos );
Verbose ("Create UNIX line endings" ) if ( $opt_2unix );

#
#   Process the TAGS and create a structure to be used later
#
my $sep = quotemeta ($opt_tsep );
foreach my $tag ( @opt_tags )
{
    my ($tname,$tvalue) = split ( $sep, $tag );
    Error ("No tag value in: $tag" ) unless ( defined $tvalue );
    Error ("Duplicate Tag: $tname" ) if ( exists $tags{$tname} );
    Verbose ("Tag: $tname :: $tvalue");
    push @tag_order, $tname;
    $tags{$tname} = $tvalue;
}

#
#   Is this a simple file copy
#   If so then don't treat the file as a text file
#
unless ( $opt_2unix || $opt_2dos || @opt_tags )
{
    simple_file_copy();
    exit (0);
}

#
#   Not a simple copy
#   Read each line from the input file
#       - Perform translations
#       - Perform line end fixup
#
open (FH, "<", $opt_infile ) || Error ("Cannot open input file: $opt_infile", "Reason: $!");
binmode(FH);

#
#   Create the output file
#   Attempt to delete it first, if it exists
#
unlink ($opt_ofile) if -f ($opt_ofile);
open (FO, ">", $opt_ofile ) || Error ("Cannot open output file: $opt_ofile", "Reason: $!");
binmode(FO);

#
#   Setup line ending
#
my $eol = '';
$eol = "\n"   if ( $opt_2unix );
$eol = "\r\n" if ( $opt_2dos );

#
#   Read each line form the input file
#
while ( <FH> )
{
    #
    #   Perform tag replacement
    #
    foreach my $tag ( @tag_order )
    {
        my $value = $tags{$tag};
        if ( s~$tag~$value~g )
        {
            Verbose ("Replaced: $tag with $value");
        }
    }

    #
    #   Perform Line Ending massaging
    #
    if ( $opt_2unix || $opt_2dos )
    {
        s~[\n\r]+$~$eol~;
    }

    print FO $_;
}
close FH;
close FO;

exit (0);


#-------------------------------------------------------------------------------
# Function        : simple_file_copy
#
# Description     : Simple binary file copy
#                   Used to copy a file, with a possible name change
#
# Inputs          : None. Use globals
#                         $opt_infile - does exist and is not a directory
#
# Returns         : Will not return on error
#
sub simple_file_copy
{
    Verbose ("Simple Copy: $opt_infile, $opt_ofile" );
    unless (File::Copy::copy($opt_infile, $opt_ofile))
    {
        Error ("File Copy Failed: $!",
               "Input file: $opt_infile",
               "Output file: $opt_ofile" );
    }
}

#-------------------------------------------------------------------------------
#   Documentation
#

=pod

=for htmltoc    MAKEUTIL::

=head1 NAME

jats_transform_file - Transform a file

=head1 SYNOPSIS

  jats etool jats_transform_file [options]

 Options:
    -help               - brief help message
    -help -help         - Detailed help message
    -man                - Full documentation
    -verbose            - Verbose operation
    -infile=file        - Input file
    -outfile=file       - Output file
    -dos                - Output file will have DOS line endingd
    -unix               - Output file will have Unix line endings
    -tsep=c             - Tag seperator character. Default ','
    -tag=name,value     - Perform tag replacement


=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<-verbose>

Increases program output. This option may be specified mutiple times

=item B<-infile=xxx>

The name of the input file. There is no default file.

=item B<-outfile=xxx>

The name of the output file. The output file cannot be the same as
the input file. This utility does not do in-place transformations

=item B<-dos>

The input file is assumed to be a text file. Line endings will be replaced
with DOS line endings.

=item B<-unix>

The input file is assumed to be a text file. Line endings will be replaced
with Unix line endings.

=item B<-tsep=c>

The character specified the seperator used in the -tag option to isolate the
name and the tag. The default character is ','.

This value applies to all tags fields specified on the command line.

=item B<-tag=name,value>

The input file is assumed to be a text file. Lines will be scanned and text
replacement will occur.

Tags of the form 'name' will be replaced with 'value'.

The order of replacement is the same as that specified on the command line.

=back

=head1 DESCRIPTION

This JATS utility is used within the build system to perform a number of file
transformation operations.

If no transformation options are invoked then the utility will assume that the
file is a binary file and simply copy the file.

If neiterh DOS or UNIX line endings are specified then the line endings will
be preserved.

=head1 EXAMPLE

The following makfile.pl fragment will create 'file1.h' based on 'file1.template'. It will replace various fields.

    GenerateFiles ('*', 'jats_transform_file',
                        '--AutoGenerate',
                        '--NoVarTag',
                        '-infile=--Prerequisite(file1.template)',
                        '-outfile=--Generated(file1.h)',
                        '-unix',
                        '-tag=__NAME__,--Var(BuildName)',
                        '-tag=__VERSION__,--Var(BuildVersion)',
                        '-tag=__VERSIONNUM__,--Var(BuildVersionNum)',
                    );

=cut

