=head1 NAME

CFX5::Config::Component - package for finding ANSYS components.

=head1 SYNOPSIS

    use CFX5::Config::Component;
    return get_component("commonfiles");

=head1 DESCRIPTION

This module provides a set of functions to find various ANSYS components.

COPYRIGHT ANSYS, ALL RIGHTS RESERVED

=cut

package CFX5::Config::Component;

use strict;
use Carp;

use CFX5::Config qw(%Config export_conf append_to_libpath prepend_to_libpath
                    append_to_execpath prepend_to_execpath);
use CFX5::CurrentConfig qw(:std %Config query_conf);
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_std_dir get_component get_commonfiles_dir 
    get_commontools_dir get_std_dir site_cfx get_std_arch_dir );

%EXPORT_TAGS = (
    'all' => [ qw( get_component get_commonfiles_dir get_commontools_dir 
        get_std_dir site_cfx get_std_arch_dir ) ]
);

=head2 get_component

    C<get_component($dir, @override)>

This function provides full paths relative to the CFX installation directory 
to other installed components. It will first read any environment variables 
which have been provided and then attempt to find an installed component under 
the CFX installation directory.

Parameters:
    $dir:       The directory to be found.
    @overrides: A list of environment variables to read which provide 
        alternative installation locations of the component.
=cut
sub get_component {
    my ($dir, @overrides) = @_;
  
    for my $override (@overrides) {
        return $ENV{$override} if defined $override and 
            defined $ENV{$override} and -e $ENV{$override};
    }
    
    $dir = _get_std_install_dir($dir);
    
    return $dir if defined $dir and -e $dir;
    undef;
}

=head2 get_commonfiles_dir

This function provides a wrapper to C<get_component()> specifically for 
use to find directories under the commonfiles directory.

=cut
sub get_commonfiles_dir {
  my $dir=shift;
  
  return get_component( join_file("commonfiles", $dir) );
}

=head2 get_commontools_dir

This function provides a wrapper to C<get_component()> specifically for 
use to find directories under the tools directory.

=cut
sub get_commontools_dir {
  my $dir=shift;
  return get_component( join_file("Tools", $dir) );
  
}

=head2 site_cfx
This function will return the full path to the CFX installation directory.
The CFX5ROOT_FORCE environment variable is used if set. Otherwise it will 
parse the the $0 special variable.
=cut
sub site_cfx {
    my $root;
    
    my $style=$Config{"CFX_DIR_STYLE"};
    
    
    if (exists $ENV{CFX5ROOT_FORCE}) {
        _debug("Using forced CFX5ROOT $ENV{CFX5ROOT_FORCE}");
        $root=fullpath($ENV{CFX5ROOT_FORCE});
    } else {
        my $dir=findbin_by_path($0);
        unless (-d $dir or $dir eq '.') {
            _debug("Trying again for $0 with fullpath");
            # this will allow us to have a go at expanding Cygwin stuff
            # before complaining.  If this fails we're going to die anyway,
            # so it does no harm to have a go ...
            $dir=dirname(fullpath($0));
        }
        _abort("Unable to locate the executable $0 used to run\n",
            "this command. Try giving a full path to the executable.") 
            if ($dir eq '.' or ! -d $dir);

        $dir =~ s![\\/]perllib$!!i;    

        # We default to the product now.
        if ($style eq 'product') {
            # new style -- the root directory is only up one level (and its
            # name contains the product version)
            $root = fullpath(dirname($dir));
        } elsif ($style eq 'complete') {
            # (findbin_by_dir can call fullpath(), but we want to expand symlinks etc)
            $root = fullpath(dirname(dirname($dir)));
        } else {
            internal_error("Unknown installation style $style");
        }
    }

    _debug("Root directory is $root");

    return $root;
}

=head2 _get_cfx_dir
This function provides a full path to CFX directories. 
It can handle both 'product' and 'complete' installation styles.

Parameters:
    $dir:   The CFX directory to be found.
    $suff:  An arbitrary suffix to a directory.
=cut
sub _get_cfx_dir {
    my $dir=shift;
    my $suff=shift;

    my $root=$Config{"CFX5ROOT"};

    my $style=$Config{"CFX_DIR_STYLE"};

    my $rv;

    # We default to the product now.
    if ($style eq 'product') {
        $rv=join_file($root, $dir);
    } elsif ($style eq 'complete') {
        my $vers=$Config{"CFXBUILDID"};
        $rv=join_file($root, $dir, $vers);
    } else {
        internal_error("Unknown installation style $style");
    }
    $rv = join_file($rv,$suff) if defined $suff and defined $rv;

    # just to be sure ...
    $rv=fullpath($rv);

    return $rv;
}

=head2 get_std_dir
This function is a wrapper to _get_cfx_dir. It is provided to maintain 
backwards compatability.
Parameters are passed onto _get_cfx_dir.
=cut
sub get_std_dir {
    return _get_cfx_dir(@_);
}

=head2 get_std_arch_dir
This function is a wrapper to _get_cfx_dir. It is provided to maintain 
backwards compatability.
    
Parameters:
    $dir:   The CFX directory to be found.
    $suff:  Platform specific suffix to a directory.
=cut
sub get_std_arch_dir {
  my $dir=shift;
  my $suff=shift;

  my $os=$Config{"CFX5OS"}.getconf("debug_suff");

  return _get_cfx_dir($dir, $os);
}

=head2 _get_std_install_dir
This is used by get_component() subroutine to find ANSYS products relative 
to the CFX install directory. 
It uses the CFX5ROOT variable to site CFX.

Parameters:
    @path: This is an array representing a directory tree to be located under 
       the CFX installer directory.
=cut
sub _get_std_install_dir {
    my @path = @_;
    
    ## First try to find the relative install path.
    my $root  = $Config{"CFX5ROOT"};
    my $local = join_file($root, "..", @path); 
    
    if ( -e $local ) {
      return fullpath($local);
    }
    
    undef;
}

1;