with Integer_Indefinite_Unbounded_Double_Lists;  use Integer_Indefinite_Unbounded_Double_Lists;
with Ada.Numerics.Discrete_Random;
with Ada.Text_IO;  use Ada.Text_IO;
with Ada.Integer_Text_IO;  use Ada.Integer_Text_IO;
with AI302.Containers;  use AI302.Containers;

procedure Test_Sort_Indefinite_Unbounded_Double_List is

   procedure Print (C : List) is
      procedure Process (I : Cursor) is
      begin
         Put (Element (I), Width => 0);
         Put (' ');
      end;

      procedure Iterate is
         new Generic_Reverse_Iteration;
   begin
      Put (Size_Type'Image (Length (C)));
      Put (": ");

      if Is_Empty (C) then
         Put ("<empty>");
      else
         Iterate (C);
      end if;

      New_Line;
   end;


   function Is_Sorted (C : List) return Boolean is

      I : Cursor := First (C);
      E : Integer := -1;

   begin

      while not Is_Null (I) loop

         if Element (I) < E then
            return False;
         end if;

         E := Element (I);
         Next (I);

      end loop;

      return True;

   end Is_Sorted;

   function Count (C : List) return Size_Type is
      N : Size_Type'Base := 0;
      I : Cursor := First (C);
   begin
      while not Is_Null (I) loop
         N := N + 1;
         Next (I);
      end loop;

      return N;
   end;


   function Count (I, J : Cursor) return Size_Type is
      N : Size_Type'Base := 0;
      II : Cursor := I;
   begin
      while II /= J loop
         N := N + 1;
         Next (II);
      end loop;

      return N;
   end;


   package Random_Integers is
      new Ada.Numerics.Discrete_Random (Integer);

   use Random_Integers;

   G : Generator;
   C, C2 : List;
   I, J : Cursor;
   E : Integer;

   use AI302.Containers;

   N : Size_Type;

   procedure Sort is
      new Generic_Sort;

begin

   Reset (G);

   Put_Line ("inserting and sorting");

   C2 := C;
   pragma Assert (C2 = C);

   Assign (Target => C2, Source => C);
   pragma Assert (C2 = C);

   Sort (C2);
   pragma Assert (Is_Sorted (C2));

--     Print (C);
--     Print (C2);
--     New_Line;

   E := Random (G) mod 1000;
   Append (C, New_Item => E);
   pragma Assert (Is_In (E, C));
   pragma Assert (Find (C, E) = First (C));
   pragma Assert (Reverse_Find (C, E) = First (C));

   loop

      --Put_Line ("C");
      --Print (C);

      C2 := C;
      pragma Assert (C2 = C);

      Assign (Target => C2, Source => C);
      pragma Assert (C2 = C);

      --Put_Line ("sorting c2");

      Sort (C2);
      pragma Assert (Is_Sorted (C2));
      pragma Assert (Count (C) = Length (C));

      --Print (C2);
      --New_Line;

      exit when Length (C) >= 100;

      I := First (C);

      for Index in 1 .. Random (G) mod Integer (Length (C)) loop
         Next (I);
      end loop;

      E := Random (G) mod 1000;

      N := Length (C);

      Insert
        (Container => C,
         Before    => I,
         New_Item  => E,
         Position  => J);

      pragma Assert (Element (J) = E);
      pragma Assert (Next (J) = I);
      pragma Assert (Length (C) = N + 1);
      pragma Assert (Count (C) = Length (C));

      N := Count (First (C), J);

--        Put ("inserted e=");
--        Put (Element (J), Width => 0);
--        Put (" offset=");
--        Put (Size_Type'Image (N));
--        New_Line;

      --Print (C);

      --Put_Line ("finding...");

      I := Find (C, E);

      while I /= J loop
         I := Find (C, E, Position => Next (I));
      end loop;

      --Put_Line ("reverse_find");

      I := Reverse_Find (C, E);
      pragma Assert (not Is_Null (I));
--        Put ("rfind.e=");
--        Put (Element (I), Width => 0);
--        Put (" offset=");
--        Put (Size_Type'Image (Count (First (C), I)));
--        New_Line;
      pragma Assert (Element (I) = E);

      while I /= J loop
         I := Reverse_Find (C, E, Position => Previous (I));
         pragma Assert (not Is_Null (I));
--           Put ("rfind.e=");
--           Put (Element (I), Width => 0);
--           Put (" offset=");
--           Put (Size_Type'Image (Count (First (C), I)));
--           New_Line;
         pragma Assert (Element (I) = E);
      end loop;

   end loop;

   Put_Line ("deleting");

   while not Is_Empty (C) loop

--        Put (Length (C), Width => 0);
--        New_Line;

      I := First (C);

      for Index in 1 .. Random (G) mod Integer (Length (C)) loop
         Next (I);
      end loop;

      E := Element (I);

      Delete (C, Item => E);

      pragma Assert (not Is_In (E, C));
      pragma Assert (Is_Null (Reverse_Find (C, E)));

   end loop;

end Test_Sort_Indefinite_Unbounded_Double_List;

