=head1 NAME

CFX5::Config::Version - package for reporting CFX version numbers.

=head1 SYNOPSIS

    use CFX5::Config::Version;
    return get_version(\$VERSION_TYPE{BUILD_ID}, \$SEMVER{MINOR}, 
        \$ACCUMULATE{TRUE}, \$SEPARATOR{DOT});

=head1 DESCRIPTION

This module provides a set of functions to report the CFX version numbers.

COPYRIGHT ANSYS, ALL RIGHTS RESERVED

=cut


package CFX5::Config::Version;

use strict;
use Carp;

use CFX5::Config::Component qw(:all);
use CFX5::Config qw(%Config export_conf append_to_libpath prepend_to_libpath
                    append_to_execpath prepend_to_execpath);
use CFX5::Output qw(:all);
use CFX5::PathManip qw(:all);


use Exporter;
use vars     qw(@ISA @EXPORT_OK %EXPORT_TAGS);
@ISA       = qw(Exporter);
@EXPORT_OK = qw( get_version %VERSION_TYPE %SEMVER %ACCUMULATE %SEPARATOR );
%EXPORT_TAGS = (
    'all' => [qw( get_version %VERSION_TYPE %SEMVER %ACCUMULATE %SEPARATOR )]
);

use vars qw(%VERSION_TYPE %SEMVER %ACCUMULATE %SEPARATOR);

BEGIN {
    # VERSION_TYPE specifies the different types of version number that we can return.
    %VERSION_TYPE = (
        REVISION     => 0,
        BUILD_ID     => 1,
        BASE_RELEASE => 2,
    );

    #
    # CFXBUILDID largely follows semantic versioning.
    # The various parts of a version number are here given their index as if it 
    # was an array such as [2,0,1] for 2.0.1
    #
    %SEMVER = (
        MAJOR => 0,
        MINOR => 1,
        PATCH => 2,
    );

    #
    # The value of SEMVER determines the 'depth' on the version number to which 
    # we descend. The value of ACCUMULATE determines if we return only the number 
    # at that depth, or if we wish to return all values down to that depth.
    # Thus, assuming a version number of 16.5.1:
    #   _get_version(... \$SEMVER{MINOR}, \$ACCUMULATE{FALSE} ...)  returns 5.
    # while:
    #   _get_version(... \$SEMVER{MINOR}, \$ACCUMULATE{TRUE} ...)  returns 16.5.
    #
    %ACCUMULATE = (
        FALSE => 0,
        TRUE  => 1
    );

    #
    # The SEPARATOR is an arbitrary glyph which to seperate the parts of a 
    # version number. We currently only support dots and none.
    #
    %SEPARATOR = (
        NONE  => "",
        DOT   => ".",
    );
}

=head2 get_version
This subroutine provides access to the versioning code. It uses the $type 
parameter to pass the other arguments onto more specific subroutines.

Parameters:
    $type:  A string, specified from the hash %VERSION_TYPE.
    $depth: An integer, specified from the hash %SEMVER.
    $accumulate: An interger, specified from the hash %ACCUMULATE.
    $style: A string, specified from the hash %SEPARATOR.
=cut
sub get_version {
    my ( $type, $depth, $accumulate, $style ) = @_;
    
    if ( $$type eq $VERSION_TYPE{REVISION} ) {
        if ( $style ) {
            _warn "Build revision can only be presented as a string.";
        }
        return _get_revision($depth);
    } elsif ( $$type eq $VERSION_TYPE{BUILD_ID} ) {
        return _get_build_id($depth, $accumulate, $style);
    } elsif ( $$type eq $VERSION_TYPE{BASE_RELEASE} ) {
        return $Config{CFXBUILDID_MAJOR}."0"
    } else {
        _warn "Unknown version type provided.";
    }
}

=head2 _get_build_id
This subroutine parses the CFX build id and returns the requested part of it.
The CFX Build ID is set in etc/release.sh.

If $depth is MINOR, $accumulate is true, and $style is '.': 
    we will return "MAJOR.MINOR"
If $depth is MINOR, $accumulate is false:
    we will return "MINOR".

Parameters:
    $depth: This determines which parts of the version we will act on. 
        If MAJOR is specified we will only iterate over only the Major 
            version number.
        If MINOR is specified we will iterate over the Major and Minor version 
            numbers.
        If PATCH is specified we iterate over all version numbers.
    $accumulate: This determines if we accumulate the version as we read them, 
        or if we will only return the final one we read.
    $style: This determines the separator between version numbers.

=cut
sub _get_build_id {
    my ($depth, $accumulate, $style) = @_;
    
    if ( not $Config{CFXBUILDID} ) {
        _warn("Unable to determine CFX build id.");
    }
    
    my @idparts;
    my $buildid = $Config{CFXBUILDID};
    
    if ($depth) { 
        if ( $buildid =~ m/^([0-9]+)\.([0-9]+)/ ) {
            @idparts = split( /\./, $buildid );
            if ($$accumulate) {
                if ($#idparts >= $$depth) {
                    $buildid = join($$style, @idparts[0 .. $$depth]);
                } else {
                    $buildid = join($$style, @idparts);
                }
            } else {
                $buildid = $idparts[$$depth];
            }
        } else {
            _info("Revision does not match semantic versioning.");
            return 
        }
    }
    
    return $buildid;
}

=head2 _get_revision
This subroutine reads the 'install_help_about' file and returns 
the CFX revision number.

It can currently parse the revision number to find MAJOR and MINOR version 
numbers, but this is not currently in use.
=cut
sub _get_revision {
    my ($depth) = @_;
    my $revision;
    my @rev;
    my @na;
    my $n;
    my @a;

    if (not $revision) {
        $revision = _read_help_about();
    }
    
    if ($depth) {
        if ( $revision =~ m/^([0-9]+)\.([0-9]+)/ ) {
            @rev = split( /\./, $revision );
            $revision = join('.', @rev[0 .. $$depth]);
        } else {
            _info("Revision does not match semantic versioning.");
            return 
        }
    } 
    
    return $revision;
}

=head2 _read_help_about
This subroutine reads the install_help_about file. It will then read the first 
line and test the length of that line, warning if it is more than 16 
characters or empty.
=cut
sub _read_help_about {
    my $global    = "globalsettings";
    my $helpAbout = "install_help_about.txt";
    my $helpLen   = 16;
    my $revision  = " " x $helpLen;
    my $fh;
    
    my $globalDir = get_commonfiles_dir($global);
    my $helpFile  = join_file($globalDir,$helpAbout);
    
    if (-f $helpFile) {
        if (open $fh, '<', $helpFile) {
            chomp($revision = <$fh>);
            close $fh;
        } else {
            _warn "Unable to read $helpFile";
        }
    } else {
        _warn("Unable to find $helpAbout");
    }
    

    
    if ( length($revision) > $helpLen ) {
        _warn "Revision is over 16 characters long " . length ($revision);
    } elsif ( length($revision) == 0 ) {
        _warn "Revision is empty.";
    }
    
    return $revision;
}


1;