package Metric_System is
------------------------------------------------------------------
--| Specification for Metric System Package
--| Author: Michael B. Feldman, The George Washington University 
--| Last Modified: September 1995                                     
------------------------------------------------------------------
 
--  Type definition
 
  type    Metric(Mass, Length, Time : Integer) is private;

  -- constrained subtypes

  subtype Scalar   is Metric(0, 0, 0);
 
  subtype Accel    is Metric(0, 1, -2);
  subtype Area     is Metric(0, 2, 0);
  subtype Length   is Metric(0, 1, 0);
  subtype Distance is Metric(0, 1, 0);
  subtype Mass     is Metric(1, 0, 0);
  subtype Time     is Metric(0, 0, 1);
  subtype Velocity is Metric(0, 1, -1);
  subtype Volume   is Metric(0, 3, 0);

  -- exported exception

  Dimension_Error : exception;

  -- exported unit constants; these will be defined in full below

  Gram       : constant Metric;
  METER      : constant Metric;
  SEC        : constant Metric;
  Square_M   : constant Metric;
  Cubic_M    : constant Metric;
  M_per_Sec  : constant Metric;
  M_per_Sec2 : constant Metric;
 
  function "*" (Left : Float; Right : Metric) return Metric;
  -- Pre:  Left and Right are defined
  -- Post: constructor: produces a metric quantity from a Float one

  function Value(Left : Metric) return Float;
  -- Pre:  Left is defined
  -- Post: selector: returns the Float (dimensionless) part
  --   of a metric quantity

  function "<"  (Left, Right : Metric) return Boolean;
  function "<=" (Left, Right : Metric) return Boolean;
  function ">"  (Left, Right : Metric) return Boolean;
  function ">=" (Left, Right : Metric) return Boolean;
  -- Pre:    Left and Right are defined
  -- Post:   the usual comparison operations
  -- Raises: Dimension_Error if Left and Right 
  --   have different dimensions

  function "+" (Right : Metric) return Metric;
  function "-" (Right : Metric) return Metric;
  function "abs" (Right : Metric) return Metric;
  -- Pre:  Right is defined
  -- Post: the usual monadic arithmetic operations;
  --   the dimensions of Right are, of course, preserved
 
  function "+" (Left, Right : Metric) return Metric;
  function "-" (Left, Right : Metric) return Metric;
  -- Pre:    Left and Right are defined
  -- Post:   the usual additive operations are performed on the
  --   numeric parts of Left and Right; the dimensions are preserved
  -- Raises: Dimension_Error if Left and Right
  --   have different dimensions

  function "*" (Left, Right : Metric) return Metric;
  function "/" (Left, Right : Metric) return Metric;
  -- Pre:    Left and Right are defined
  -- Post:   the usual multiplication and division operations 
  --   are performed on the numeric parts of Left and Right; 
  --   the dimensions are added pairwise (multiplication)
  --   or subtracted pairwise (division)
  --   Left and Right need not have the same dimensions.
  
private

  -- A Metric quantity is a 3-discriminant variant record,
  -- with no default values. Each object of the type must
  -- therefore be constrained to a subtype, that is, to a
  -- fixed set of dimensions. This is physically realistic.

  type Metric(Mass, Length, Time : Integer) is record
    Value : Float := 0.0;
  end record;
 
  Gram       : constant Metric := (1, 0, 0, 1.0);
  Meter      : constant Metric := (0, 1, 0, 1.0);
  Sec        : constant Metric := (0, 0, 1, 1.0);
  Square_M   : constant Metric := (0, 2, 0, 1.0);
  Cubic_M    : constant Metric := (0, 3, 0, 1.0);
  M_per_Sec  : constant Metric := (0, 1, -1, 1.0);
  M_per_Sec2 : constant Metric := (0, 1, -2, 1.0);
 
end Metric_System;