package Geometry is
------------------------------------------------------------------
--| Defines an abstract data type for a geometric figure.  
--| Operations include constructors for rectangles, circles, 
--| and squares, and selectors for width, height, side,
--| area and perimeter.
--| Author: Michael B. Feldman, The George Washington University 
--| Last Modified: September 1995                                     
------------------------------------------------------------------
  
  -- Data Types
  
  subtype NonNegFloat is Float range 0.0 .. Float'Last;
  type FigKind is (Rectangle, Square, Circle);

  type Figure (FigShape : FigKind := Rectangle) is private;

  -- Exported Exception

  ShapeError: exception;
  
  -- Constructor Operations 

  function MakeRectangle (Width, Height : NonNegFloat) return Figure;
  -- Pre : Width and Height are defined
  -- Post: returns a rectangle

  function MakeCircle (Radius : NonNegFloat) return Figure;
  -- Pre : Radius is defined
  -- Post: returns a circle

  function MakeSquare (Side : NonNegFloat) return Figure;
  -- Pre : Side is defined
  -- Post: returns a square
  
  -- selectors
  function Shape     (OneFig : Figure) return FigKind;   
  function Height    (OneFig : Figure) return NonNegFloat;
  function Width     (OneFig : Figure) return NonNegFloat;
  function Radius    (OneFig : Figure) return NonNegFloat;
  function Side      (OneFig : Figure) return NonNegFloat;
  function Perimeter (OneFig : Figure) return NonNegFloat;
  function Area      (OneFig : Figure) return NonNegFloat;
  -- Pre   : OneFig is defined.
  -- Post  : Returns the appropriate characteristic
  -- Raises: ShapeError if the requested characteristic is
  --         undefined for the shape of OneFig 

private

  type Figure (FigShape : FigKind := Rectangle) is record
    Area : NonNegFloat := 0.0;
    Perimeter : NonNegFloat := 0.0;
    case FigShape is
      when Rectangle | Square =>
        Width : NonNegFloat := 0.0;
        Height : NonNegFloat := 0.0;
      when Circle =>
        Radius : NonNegFloat := 0.0;
    end case;  
  end record;  

end Geometry;