----------------------------------------------------------------------
-- resource management for varying requests
--
-- structure:  requesters = task, resourcepool(+mangement) = protected object
-- version1: double interaction
----------------------------------------------------------------------

with Stringpack, Ada.Numerics.Float_Random; use Stringpack, Ada.Numerics.Float_Random;
procedure Resources1 is

   G : Generator;
   Number_Of_Clients : constant Natural := 3;
   Number_Of_Resources : constant Natural := 5;
   How_Often : constant Natural := 5;


   protected Resource_Manager  is ---------------------------------------
      procedure Request(How_Many : Positive; Ok : out Boolean); --+ double interaction
      entry Wait (How_Many : Positive; Ok : out Boolean);       --+
      procedure Release(How_Many : Positive);
   private
      Free : Natural := Number_Of_Resources;
      Release_Event : Boolean := False;
      Wanted : Natural := 0;     -- for trace only, offene Wünsche
   end Resource_Manager;

   protected body Resource_Manager is

      procedure Trace is
	 Not_Free : Natural := Number_Of_Resources - Free;
      begin
         Outbuffer := Varnull;
         for I in 1..Number_Of_Resources loop
	    if I <= Not_Free then Outbuffer := Outbuffer & " X";
	    else Outbuffer := Outbuffer & " -";
	    end if;
	 end loop;
	 Outbuffer := (Outbuffer & "  wanted = ") & Wanted;
	 Print;
      end Trace;

      procedure Request(How_Many : Positive; Ok : out Boolean) is
	 -- this could be an entry with "when free > 0"
      begin
	 if How_Many <= Free
	 then Free := Free - How_Many; Ok := True;  --allocate
	 else Ok := False;
	 Wanted := Wanted + How_Many;   -- for trace
	 end if;
	 Trace;
      end Request;

      entry Wait (How_Many : Positive; Ok : out Boolean) when Release_Event  is
      begin
	 if Wait'Count = 0 then Release_Event := False; end if;
	 -- => loop over all waiting requesters !!!
	 if How_Many <=  Free
	 then Free := Free - How_Many; Ok := True;  --allocate
	 Wanted := Wanted - How_Many;   -- for trace
	 Trace;
	 else Ok := False;
	 end if;
      end Wait;

      procedure Release(How_Many : Positive) is
      begin
	 Free := How_Many + Free;  -- release
	 if Wait'Count > 0 then Release_Event := True; end if;
	 Trace;
      end Release;


   end Resource_Manager;  -----------------------------------------------


   task type Clients is   -----------------------------------------------
      entry Start(How_Many : Natural);
   end Clients;

   task body Clients is
      My_Need : Natural;
      Done : Boolean;
   begin
      accept Start(How_Many : Natural)
      do My_Need := How_Many; end Start;
      for I in 1..How_Often loop
	 delay Duration(0.001* Random(G));
	 Resource_Manager.Request(My_Need, Done);
	 while not Done loop                                 --+ immer neu "wait"
            Resource_Manager.Wait(My_Need, Done); end loop;  --+ aufrufen!
	 delay Duration(0.001 * Random(G));
	 Resource_Manager.Release(My_Need);
      end loop;
   end Clients;

   Client : array(1..Number_Of_Clients ) of Clients;  -------------------

begin  -----------------------------------------------------------main

   Client(1).Start(1); Client(2).Start(2); Client(3).Start(5);

end Resources1;  -----------------------------------------------------

