----------------------------------------------------------------------
-- Aufgabe: producer-consumer (summation_of_naturals) with bounded buffer
-- Methode: tasks for producer-consumer (simple sum_of_naturals problem)
--          AND task for buffer
----------------------------------------------------------------------

with Stringpack; use Stringpack;
procedure Bounded_Buffer2 is

   task Buffer is                -- server task
      entry Insert(D: Natural);
      entry Take(D: out Natural);
   end Buffer;

   task Producer is
      entry Start(How_Many: Natural);
   end Producer;

   task Consumer is
      entry Start(Break: Natural);
   end Consumer;

   task body Producer is
      Local_How_Many: Natural;
   begin
      accept Start(How_Many: Natural) do
         Local_How_Many := How_Many;
      end Start;

      Consumer.Start(Local_How_Many +1);
      for I in 1..(Local_How_Many +1) loop
         Buffer.Insert(I);
      end loop;
   end Producer;

task body Consumer is
   Over, Item, Result: Natural;
begin
   accept Start(Break: Natural) do
      Over := Break;
   end Start;

   Result := 0;
   Buffer.Take(Item);
   while Item /= Over loop
      Result := Result +Item;
      Buffer.Take(Item);
   end loop;

   Print("Summe= " & Result);
end Consumer;

task body Buffer is
   Length: constant Natural := 10;
   B: array(0..Length-1) of Natural;
   In_Ptr, Out_Ptr: Natural := 0;
   Count: Natural := 0;
begin
   loop
      select
         when Count < Length =>
            accept Insert(D: Natural) do
               B(In_Ptr) := D;
            end Insert;

            In_Ptr := (In_Ptr +1) mod Length;
            Count := Count +1;
      or
         when Count > 0 =>
            accept Take(D: out Natural) do
               D := B(Out_Ptr);
            end Take;

            Out_Ptr := (Out_Ptr +1) mod Length;
            Count := Count -1;
      or
         terminate;
      end select;
   end loop;
end Buffer;

N: Natural;
begin
   Print("give natural");
   N := Getint;
   Producer.Start(N);
end Bounded_Buffer2;
