(* Parameters come as:
    1. what to test: 
      0 - correctness of insert, delete and union
      1 - speed of inserts and deletes
      2 - speed of union
   in case of $0 == 0
    2. max size of queue for all tests
   in case of $0 == 1
    2. number of inserts
    3. number of deletes 
   in case of $0 == 2
    2. size of first
    3. size of second
*)

module Tests (Queue : Prioqueue.PRIOQUEUE) =
struct
  type action =
      Test_Correctness_Of_All_Operations
    | Test_Speed_Of_Insert_And_Del_Min
    | Test_Speed_Of_Union
    | Print_Statistics_Of_Operations_On_Certain_Permutations
    | Tell_User_That_He_Should_Read_The_Fkn_Manual

  let what_to_do =
    (function x ->
       match x with
           0 -> Test_Correctness_Of_All_Operations
         | 1 -> Test_Speed_Of_Insert_And_Del_Min
         | 2 -> Test_Speed_Of_Union
         | 3 -> Print_Statistics_Of_Operations_On_Certain_Permutations
         | _ -> Tell_User_That_He_Should_Read_The_Fkn_Manual
    )
      (Scanf.fscanf stdin "%d" (function x -> x) )

  module QueueTester = Tester.PrioqueueTester( Queue )

  let test() =
    match what_to_do with
        Test_Correctness_Of_All_Operations
        ->
          begin

            QueueTester.num_of_other := (Scanf.fscanf stdin "%d" (function x -> x) );

            QueueTester.key_gen();

            if not (QueueTester.correct_insert_del_min()) then
              Printf.printf "%s%!" "Error in insert delete min!\n"
            else
              Printf.printf "%s%!" "Insert and delete min - OK!\n";

            if not (QueueTester.correct_union_all()) then
              Printf.printf "%s%!" "Error in union!\n"
            else
              Printf.printf "%s%!" "Union - OK!\n";

          end

      | Test_Speed_Of_Insert_And_Del_Min
        ->
          begin

            let num_of_insert = (Scanf.fscanf stdin "%d" (function x -> x) )

            and num_of_delete = (Scanf.fscanf stdin "%d" (function x -> x) )

            in

              QueueTester.num_of_other := num_of_insert;

              QueueTester.num_of_min := 0;

              QueueTester.num_of_delete := num_of_delete;

              QueueTester.key_gen();

              Printf.printf "%f" ( QueueTester.speed_insert_del_min () );

              exit 0;

          end

      | Test_Speed_Of_Union
        ->
          begin

            let size_1 = (Scanf.fscanf stdin "%d" (function x -> x) )

            and size_2 = (Scanf.fscanf stdin "%d" (function x -> x) )

            in

              QueueTester.num_of_other := size_1 + size_2;

              QueueTester.num_of_min := 0;

              QueueTester.key_gen();

              Printf.printf "%f" ( QueueTester.speed_union ( size_1 ) );

              exit 0;

          end

      | Print_Statistics_Of_Operations_On_Certain_Permutations
          ->
          begin

            QueueTester.queue_input_size := 1000;

            QueueTester.permutation_size := 5;

            QueueTester.how_precise      := 20;

            let (best_perms,
                 maximum,
                 minimum,
                 average_diff) = QueueTester.statistics_of_best_permutations()
            in

            let _ = List.rev_map
              (function (perm, time) ->
                 begin
                   let _ = List.rev_map (function x -> begin Printf.printf "%d " x; end) perm
                   in
                     Printf.printf "        ";
                     Printf.printf "%f" (time);
                     Printf.printf "\n";
                 end
              )
              best_perms
            in

              Printf.printf "\n";

              Printf.printf "Maximum : %f\n\n" maximum;

              Printf.printf "Minimum : %f\n\n" minimum;

              Printf.printf "Average difference : %f\n\n" average_diff;

              exit 0;

          end

      | Tell_User_That_He_Should_Read_The_Fkn_Manual
        ->
          begin

            Printf.printf "%s" "Wrong first parameter!";

            exit 1;

          end
            (* end of test () *)

end

(* module LetsTest = Tests(ParticularQueue);; *)

(* LetsTest.test();; *)