----------------------------------------------------------------------
-- Aufgabe: summiere 1..n.
-- Methode: tasks fuer Teilsummen 1..n/2, n/2+1..n
--          erste task startet die zweite und bildet Gesamtergebnis
--                                        mit call-back procedure
----------------------------------------------------------------------

with Stringpack; use Stringpack;
procedure Arbeitsteilung2b is

   task Worker is
      entry Start(From, To: Integer);
      entry Result(Res: out Integer);
      entry Call_Back(Res: Integer);
   end Worker;

   type Call_Back_Proc is access procedure(X: Integer);

   procedure Call_Back_Worker(R: Integer) is --proc must not be deeper than access type
   begin
      Worker.Call_Back(R);
   end Call_Back_Worker;

   task Helper is
      entry Start(From, To: Integer; Cb: Call_Back_Proc);
   end Helper;

   task body Worker is
      Local_From, Local_To, Local_Res, Remote_Res: Integer;
   begin
      accept Start(From, To: Integer) do
         Local_From := From;
         Local_To := To;
      end Start;
      Helper.Start(Local_From, (Local_From + Local_To)/2, Call_Back_Worker'access);
      Local_Res := 0;
      for I in ((Local_From + Local_To)/2 +1)..Local_To loop
         Local_Res := Local_Res+I;
      end loop;
      accept Call_Back(Res: Integer) do
         Remote_Res := Res;
      end Call_Back;
      accept Result(Res: out Integer) do
         Res := Local_Res + Remote_Res;
      end Result;
   end Worker;

   task body Helper is
      Local_From, Local_To, Local_Res: Integer;
      My_Call_Back_Proc: Call_Back_Proc;
   begin
      accept Start(From, To: Integer; Cb: Call_Back_Proc) do
         Local_From := From;
         Local_To := To;
         My_Call_Back_Proc := Cb;
      end Start;
      Local_Res := 0;
      for I in Local_From..Local_To loop
         Local_Res := Local_Res+I;
      end loop;
      My_Call_Back_Proc(Local_Res);
   end Helper;

   N, Sum: Integer;

begin
   Print("give natural");
   N := Getint;
   Worker.Start(1, N);
   Worker.Result(Sum);
   Print("Summe= " & Sum);
end Arbeitsteilung2b;
