with Integer_Bounded_Single_Lists;  use Integer_Bounded_Single_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 Ada.Command_Line;  use Ada.Command_Line;

procedure Test_Bounded_Single_List is


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

--        procedure Iterate is
--           new Generic_Iteration;
--     begin
--        Iterate (C);
--        New_Line;
--     end;


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

   use Random_Integers;

   G : Generator;

   procedure Sort is new Generic_Sort;

   function Is_Sorted (C : Container_Type) return Boolean is

      I : Iterator_Type := First (C);
      J : constant Iterator_Type := Back (C);

      E : Integer := -1;

   begin

      while I /= J loop

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

         E := Element (C, I);

         Increment (C, I);

      end loop;

      return True;

   end Is_Sorted;


   procedure Populate (C : in out Container_Type) is

      I, J : Iterator_Type;
      E : Integer;
      N : Natural;

   begin

      while Length (C) < C.Size loop

         I := First (C);

         for Index in 1 .. Random (G) mod (Length (C) + 1) loop
            Increment (C, I);
         end loop;

         E := Random (G) mod 1000;
         N := Length (C);

--           Put ("e=");
--           Put (E, Width => 0);
--           Put (" n=");
--           Put (N, Width => 0);
--           New_Line;

         Insert_After
           (Container => C,
            Position  => I,
            New_Item  => E,
            Iterator  => J);

         pragma Assert (Element (C, J) = E);
         pragma Assert (Length (C) = N + 1);

--           I := Find (C, E);

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

--           I := First (C);

--           for Index in 1 .. Random (G) mod (Length (C) + 1) loop
--              Increment (I);
--           end loop;

--           J := First (C);

--           for Index in 1 .. Random (G) mod (Length (C) + 1) loop
--              Increment (J);
--           end loop;

--           Splice (C, I, J);

         declare
            C2 : Container_Type (Size => C.Size);
         begin
            Assign (Target => C2, Source => C);
            pragma Assert (C2 = C);

            --Print (C2);
            Reverse_Container (C2);

            --Print (C2);
            Reverse_Container (C2);

            pragma Assert (C2 = C);
            --New_Line (2);

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

--         Print (C);
--         New_Line;

      end loop;

   end Populate;


   C, C2 : Container_Type (100);

   I, J : Iterator_Type;
   E : Integer;

   N : Natural;

   Seed : Integer := 0;

begin

   if Argument_Count > 0 then
      Seed := Integer'Value (Argument (1));
   end if;

   Reset (G, Seed);

   Put_Line ("inserting");

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

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

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

   for I in 1 .. 10 loop
      Prepend (C, New_Item => I);
   end loop;
   
   while not Is_Empty (C) loop
      Delete_First (C);
   end loop;

   Populate (C);

   Put_Line ("deleting");

   while not Is_Empty (C) loop

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

      I := First (C);
      pragma Assert (I /= Null_Iterator);

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

      pragma Assert (I /= Null_Iterator);

      N := Length (C);

      if I = Last (C) then
         Delete_First (C);
      else
         Delete_After (C, Position => I);
      end if;

      pragma Assert (Length (C) = N - 1);

   end loop;

   Sort (C);

   Put_Line ("inserting");

   Populate (C);

   Put_Line ("deleting");

   while not Is_Empty (C) loop

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

      I := First (C);

      for Index in 1 .. Random (G) mod (Length (C) + 1) loop
         Increment (C, I);
      end loop;

      J := First (C);

      for Index in 1 .. Random (G) mod (Length (C) + 1) loop
         Increment (C, J);
      end loop;

      Splice_After (C, I, J);

      N := Length (C);

      Delete_First (C);
      pragma Assert (Length (C) = N - 1);

   end loop;

   pragma Assert (Is_Empty (C));

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

   Put_Line ("inserting");

   Populate (C);

   Put_Line ("deleting");

   while not Is_Empty (C) loop

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

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

      I := First (C);

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

      E := Element (C, I);

      N := Length (C);

      Delete (C, Item => E);

      pragma Assert (Length (C) < N);
      pragma Assert (not Is_In (E, C));
      pragma Assert (Find (C, E) = Back (C));

   end loop;

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

end Test_Bounded_Single_List;


