WITH Ada.Text_IO;
WITH Ada.Integer_Text_IO;
WITH Ada.Calendar;
PROCEDURE World_Time IS
------------------------------------------------------------------
--| Finds the current time in any of several time zones
--| Author: Michael B. Feldman, The George Washington University
--| Last Modified: July 1995
------------------------------------------------------------------

  TYPE Cities IS (Paris, London, Rio, Caracas, DC,
                  Chicago, Denver, Seattle, Honolulu);

  PACKAGE City_IO IS NEW Ada.Text_IO.Enumeration_IO(Cities);

  TYPE TimeDiffs IS ARRAY (Cities) OF Integer;

  -- table of time differences from DC; modify this table if you are
  -- not located in the Eastern U.S. time zone
  Offsets : CONSTANT TimeDiffs :=
    (Paris => +6, London => +5, Rio => +2, Caracas => -1, DC => 0,
     Chicago => -1, Denver => -2, Seattle => -3,  Honolulu => -5);

  TimeHere  : Ada.Calendar.Time;
  TimeThere : Ada.Calendar.Time;
  There     : Cities;

  FUNCTION AdjustTime(T: Ada.Calendar.Time; City: Cities;
                      OffsetTable: TimeDiffs) RETURN Ada.Calendar.Time IS

  -- given a time value, finds the corresponding time in a given time zone

  BEGIN -- AdjustTime

    RETURN Ada.Calendar."+"(T, Duration(OffsetTable(City) * 3600));

  END AdjustTime;


  PROCEDURE ReadCity(City : OUT Cities) IS

  -- reads a city name from the terminal, robustly

  BEGIN -- ReadCity

    LOOP
      BEGIN     -- exception handler block
        Ada.Text_IO.Put_Line(Item => "Please enter one of the following:");
        Ada.Text_IO.Put_Line(Item =>
          "Paris, London, Rio, Caracas, DC, ");
        Ada.Text_IO.Put(Item =>
           "Chicago, Denver, Seattle, Honolulu >");

        City_IO.Get(Item => City);
        EXIT;   -- good input data
      EXCEPTION -- bad input data
        WHEN Ada.Text_IO.Data_Error =>
          Ada.Text_IO.Skip_Line;
          Ada.Text_IO.Put(Item => "Invalid city name; please try again.");
          Ada.Text_IO.New_Line;
      END;      -- exception handler block
    END LOOP;

  END ReadCity;


  PROCEDURE DisplayTime(T: Ada.Calendar.Time) IS

  -- displays a Ada.Calendar.Time value in hh:mm:ss form

    TYPE DayInteger IS RANGE 0..86400;

    SecsPastMidnight : DayInteger;  -- could be larger than 32767
    MinsPastMidnight : Natural;
    Secs             : Natural;
    Mins             : Natural;
    Hrs              : Natural;

  BEGIN -- DisplayTime

    SecsPastMidnight := DayInteger(Ada.Calendar.Seconds(T));
    MinsPastMidnight := Natural(SecsPastMidnight/60);
    Secs             := Natural(SecsPastMidnight REM 60);
    Mins             := MinsPastMidnight REM 60;
    Hrs              := MinsPastMidnight / 60;

    Ada.Integer_Text_IO.Put (Item => Hrs, Width => 1);
    Ada.Text_IO.Put (Item => ':');
    IF Mins < 10 THEN
      Ada.Text_IO.Put (Item => '0');
    END IF;
    Ada.Integer_Text_IO.Put (Item => Mins, Width => 1);
    Ada.Text_IO.Put (Item => ':');
    IF Secs < 10 THEN
      Ada.Text_IO.Put (Item => '0');
    END IF;
    Ada.Integer_Text_IO.Put (Item => Secs, Width => 1);

  END DisplayTime;

BEGIN -- World_Time

  ReadCity(City => There);
  TimeHere := Ada.Calendar.Clock;
  TimeThere := AdjustTime(T=>TimeHere, City=>There, OffsetTable=>Offsets);

  Ada.Text_IO.Put(Item => "Current local time is ");
  DisplayTime(T => TimeHere);
  Ada.Text_IO.New_Line;
  Ada.Text_IO.Put(Item => "Current time in ");
  City_IO.Put(Item => There, Width => 1);
  Ada.Text_IO.Put(Item => " is ");
  DisplayTime(T => TimeThere);
  Ada.Text_IO.New_Line;

END World_Time;