package CFX5::Units;

use strict;
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);

require Exporter;
require DynaLoader;
require AutoLoader;

@ISA = qw(Exporter DynaLoader);
# Items to export into callers namespace by default. Note: do not export
# names by default without a very good reason. Use EXPORT_OK instead.
# Do not simply export all your public functions/methods/constants.
@EXPORT = qw(
	
);
$VERSION = '0.1';

bootstrap CFX5::Units $VERSION;

# Preloaded methods go here.

# parseQuantity - see POD docuemtation below.
sub parseQuantity {
  my ($pq) = @_;

  # bail if we didn't get an argument
  if (!defined($pq)) {
    return;
  }

  # RegExps to parse the  string
#  my $numberRE = '[0-9\.eE\-\+]+'; # RE to match floats and ints
#  my $unitRE = '\[[\w \^\-\+\/]*\]'; # RE to match unit string (enclosed in [])
# Modified RE's by Jeremy's suggestion.
   my $numberRE = '-?[0-9]+\.?[0-9]*(?:[eEdD]*[+-]?[0-9]+)?';
   my $unitRE = '[[][ ]*[(a-zA-Z][ ()\.a-zA-Z0-9^/-]*[ ]*[\]]';



  # Where we're putting the results (UNDEF to start)
  my $value;
  my $unit;

  #Pull out the number and unit strings 
  # (look for exactly 1 number, and 0 or 1 units with optional whitespace)
  if ($pq =~ /^\s*($numberRE){1}\s*($unitRE)?\s*$/) {
    $value = $1;
    if (defined($2)) {
      $unit = $2;
      # get rid of []
      $unit =~ /\[\s*(.*)\s*\]/;
      $unit = $1;
    } else {
      $unit = "";
    }
  }

  # Return the value and unit (they're UNDEF if we didn't find a number).
  return ($value,$unit);

}

sub convertToSI {
  # converts a given quantity string to SI.  Returns units and value as
  # separate entries in a list - see POD doc below for details
 my ($quantity) = @_;
 
 my ($inVal,$inU) = parseQuantity($quantity);
 if (!defined($inU)) {
  return undef;
 }

 my ($outU,$mul,$add) = getSIConvert($inU);
 if (!defined($outU)) {
  return undef;
 }

 my $outVal = $inVal*$mul + $add;

 return ($outVal, $outU);

}
     
# Autoload methods go after =cut, and are processed by the autosplit program.

1;
__END__
# Below is the stub of documentation for your module. You better edit it!

=head1 NAME

Units - Perl extension to enable units checking in CCL.

=head1 SYNOPSIS

use CFX5::Units;

CFX5::Units::unitsInit();

#Get common units for velocity
my $unitsListRef = CFX5::Units::getCommonUnits("Velocity");
if (!defined($unitsListRef)) {
  die "Error getting common units";
}

#Get and print the dimensions array for the first one.
my $dimArrRef = CFX5::Units::dimFromUnit($unitsListRef->[0]);
if (defined($dimArrRef)) {
  foreach $dim (@$dimArrRef) {
    print "$dim ";
  }
  print "\n";
}

=head1 DESCRIPTION

The methods in this extension allow the user to access information about the
units and dimensionality of a physical quantity.  Most of the methods are
wrappers around libunits.a in CFX5.

=head1 AUTHORS

Steve Elias - Perl extension.
Jeremy Clark, et al. - All the original units code.

=head1 METHODS 

=head2 int unitsInit()

Initialises data for the units processor and common units. Looks in the 
directory specified by CFX_DATA_DIR (and the local directory) for the 
initialisation files (units.cfx and common_units.cfx).

Returns 1 on success and 0 on failure.

=head2 arrayRef getCommonUnits(String quantityType)

Given a string representing a standard physical type (e.g. Velocity, 
Temperature, etc.) returns a reference to an array of strings with 
common units for that physical type.

If the quanitity type is not recognised, or another error occurs, the
return is UNDEF.

=head2 arrayRef dimFromUnit(String units)

Given a unit string, returns a reference to a 10 entry dimensionality array.
See documentation on libunits.a for details on the contents of this array.

If the unit string is not recognised, or another error occurs, the
return is UNDEF.

=head2 (String,String) parseQuantity(String quantity)

Given a string representing a physical quantity parses it into value and unit
strings and returns them as a two entry list.  If the string can't be parsed 
(likely an expression) then both return stings are UNDEF.  A dimensionless 
quantity (i.e. a number with no unit specification) has the unit string set to
"".

Note this is a utility method defined within Units.pm, and does not come
from libunit.a

=head2 (String,String) convertToSI(String quantity)

Given a string representing a physical quantity returns the value
and unit strings converted to SI as a two entry list.  If there are
any errors, the return is undef.

Note this is a utility method defined within Units.pm, and does not come
from libunit.a
=cut
