File : initialize_structures.adb


--
-- Uwe R. Zimmer, Australia, August 2011
--

with Ada.Float_Text_IO;      use Ada.Float_Text_IO;
with Ada.Integer_Text_IO;    use Ada.Integer_Text_IO;
with Ada.Text_IO;            use Ada.Text_IO;
with Ada.Calendar;           use Ada.Calendar;

procedure Initialize_Structures is

   type RGB  is (R, G, B);

   type RGB_Colour is array (RGB) of Boolean;

   Darkness   : constant RGB_Colour := (others => False);

   Red        : constant RGB_Colour := (R => True, others => False);
   Green      : constant RGB_Colour := (G => True, others => False);
   Blue       : constant RGB_Colour := (B => True, others => False);

   Yellow     : constant RGB_Colour := Red  or Green;
   Magenta    : constant RGB_Colour := Red  or Blue;
   Cyan       : constant RGB_Colour := Blue or Green;

   White      : constant RGB_Colour := not Darkness;

   type Entry_Type is record
      Time_Stamp : Time       := Clock; -- this will be the time of an instantiation of an object of this type.
      Colour     : RGB_Colour := Darkness;
   end record;

   type Rows    is new Positive range 1 .. 5;
   type Columns is new Positive range 1 .. 2;

   type World_Type is array (Rows'Range, Columns'Range) of Entry_Type;

   Time_First : constant Time := Time_Of (Year_Number'First, Month_Number'First, Day_Number'First);

   Dark_World : constant World_Type := (others => (others => (Time_Stamp => Time_First, Colour => Darkness)));

   --

   procedure Print (W : World_Type) is

      function Colour_Image (Colour : RGB_Colour) return String is

         function Component_Image (Component : RGB) return String is

         begin
            if Colour (Component) then
               return RGB'Image (Component);
            else
               return "-";
            end if;
         end Component_Image;

      begin
         return "[ " & Component_Image (R) & " | " & Component_Image (G) & " | " & Component_Image (B) & " ]";
      end Colour_Image;

      procedure Print_Time_Stamp (TS : Time) is

         Seconds_Per_Minute  : constant Day_Duration := 60.0;
         Seconds_Per_Hour    : constant Day_Duration := 60.0 * Seconds_Per_Minute;

         Seconds_Today       : constant Day_Duration := Seconds (TS);
         Hours               : constant Natural      := Natural (Float'Floor (Float (Seconds_Today / Seconds_Per_Hour)));
         Seconds_This_Hour   : constant Day_Duration := Seconds_Today - Hours * Seconds_Per_Hour;
         Minutes             : constant Natural      := Natural (Float'Floor (Float (Seconds_This_Hour / Seconds_Per_Minute)));
         Seconds_This_Minute : constant Day_Duration := Seconds_This_Hour - Minutes * Seconds_Per_Minute;

      begin
         Put (Integer (Hours), 2); Put (':'); Put (Integer (Minutes), 2); Put (':'); Put (Float (Seconds_This_Minute), 2, 12, 0);
      end Print_Time_Stamp;

   begin
      Put_Line ("The World according to .. ");
      for x in W'Range (1) loop
         for y in W'Range (2) loop
            Print_Time_Stamp (W (x, y).Time_Stamp); Put (": "); Put (Colour_Image (W (x, y).Colour)); Put (' ');
         end loop;
         New_Line;
      end loop;
   end Print;

   --

   World : World_Type; -- All array entries are initialized with the default values for Entry_Type

begin
   -- If 'World' would not have complete initialization code, the following call would lead to the
   -- compilter warning: "World" may be referenced before it has a value.

   Print (World); -- The world is in darkness (due to its default initialization as defined above)

   -- Uni-colour the whole world and take it into the present time:

   World := (others => (others => (Time_Stamp => Clock, Colour => Magenta and not Blue)));

   -- Note that the function 'Clock' is evaluated each time.
   -- Due to the clock granularity in your system it can still still appear as the same time on screen.
   -- The expression 'Colour_Magenta and not Colour_Blue' is optimized to a constant by the compiler => Colour_Red.

   Print (World);

   -- Separate colours for the first two rows and row four.
   -- Beginning of time and darkness for the rest:

   World := (1 .. 2 => (others => (Time_Stamp => Clock,      Colour => Yellow  and Cyan)),
             4      => (others => (Time_Stamp => Clock,      Colour => Red)),
             others => (others => (Time_Stamp => Time_First, Colour => Darkness)));

   Print (World);

   -- Separate colours for the first and the second column and assign the same time to all:

   declare
      Now : constant Time := Clock;
   begin
      World := (others => (1 => (Time_Stamp => Now, Colour => White),
                           2 => (Time_Stamp => Now, Colour => Darkness)));
   end;

   Print (World);

   -- Back to a constant setting:

   World := Dark_World;

   Print (World);

end Initialize_Structures;