package exam;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.sql.Timestamp;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Set;

import org.junit.Test;

public class BogoSortTest {
  @Test
  public void testPrintPermutationWithOneSet() {
    HashSet<String> set = new HashSet<String>(Arrays.asList("b", "a", "c"));
    BogoSort.printPermutation(set);
  }
  @Test
  public void testPrintPermutationWithASetAndAList() {
    Set<Integer> set = new HashSet<Integer>(Arrays.asList(4, 5, 3));
    List<Integer> list = new ArrayList<Integer>();
    BogoSort.printPermutation(list, set);
  }
  @Test
  public void testPrintPermutationWithASetAndAList2() {
    Set<String> set = new HashSet<String>(Arrays.asList("b", "a", "c"));
    List<Object> list = new ArrayList<Object>();
    BogoSort.printPermutation(list, set);
  }

  interface Tester {
    void call(List<String> list);
  }
  @Test
  public void testForAllPermutations() {
    Set<String> set = new HashSet<String>(Arrays.asList("b", "a", "c"));
    int[] counter = new int[] { 0 };
    BogoSort.forAllPermutations(set, new Tester() {
      @Override
      public void call(List<String> list) {
        assertEquals(set, new HashSet<>(list));
        counter[0]++;
      }
    }::call);
    assertEquals(6, counter[0]);
  }
  
  interface Tester2 {
    void call(Object o);
  }
  @Test
  public void testForAllPermutations2() {
    Set<Integer> set = new HashSet<Integer>(Arrays.asList(1, 3, 7, 6));
    int[] counter = new int[] { 0 };
    BogoSort.<Integer>forAllPermutations(set, new Tester2() {
      @Override
      public void call(Object o) {
        counter[0]++;  
      }
    }::call);
    assertEquals(24, counter[0]);
  }
  
  @Test
  public void testPermutationSize() {
    Set<String> set = new HashSet<String>(Arrays.asList("b", "a", "c"));
    assertEquals(6, BogoSort.permutations(set).size());
    
  }
  @Test
  public void testPermutations() {
    Set<String> set = new HashSet<String>(Arrays.asList("b", "a", "c"));
    List<? extends List<?>> permutations = BogoSort.permutations(set);
    for(List<?> list: permutations) {
      assertEquals(3, list.size());
    }
  }
  @Test
  public void testPermutations2() {
    Set<String> set = new HashSet<String>(Arrays.asList("b", "a", "c"));
    List<List<Object>> permutations = BogoSort.permutations(set);
    for(List<Object> list: permutations) {
      assertEquals(set, new HashSet<Object>(set));
    }
  }
  @Test
  public void testPermutations3() {
    Set<Integer> set = new HashSet<Integer>(Arrays.asList(2, 6, 3));
    List<List<Integer>> permutations = BogoSort.permutations(set);
    for(List<Integer> list: permutations) {
      assertEquals(set, new HashSet<Integer>(set));
    }
  }

  @Test
  public void testIsSorted() {
    assertFalse(BogoSort.isSorted(Arrays.asList(1, 6, 7, 9, 0)));
  }
  @Test
  public void testIsSorted2() {
    assertTrue(BogoSort.isSorted(Collections.emptyList()));
  }
  @Test
  public void testIsSorted3() {
    assertTrue(BogoSort.isSorted(Collections.singletonList("a")));
  }
  @Test
  public void testIsSorted4() {
    assertTrue(BogoSort.isSorted(Collections.singletonList(new Timestamp(12))));
  }
  @Test
  public void testIsSorted5() {
    assertTrue(BogoSort.isSorted(Arrays.asList(new Timestamp(12), new Timestamp(78))));
  }
  @Test(timeout = 2000)
  public void testIsSorted6() {
    LinkedList<Integer> list = new LinkedList<>();
    for(int i = 0; i < 1_000_000; i++) {
      list.add(i);
    }
    assertTrue(BogoSort.isSorted(list));
  }
  @Test
  public void testIsSorted7() {
    LinkedHashSet<String> set = new LinkedHashSet<String>(Arrays.asList("a", "b", "c"));
    assertFalse(BogoSort.isSorted(Arrays.asList(new Timestamp(78), new Timestamp(12))));
  }
  @Test
  public void testIsSorted8() {
    ArrayDeque<Integer> queue = new ArrayDeque<Integer>(Arrays.asList(1, 4, 7, 9, 34, 56, 2, 23, 56));
    assertFalse(BogoSort.isSorted(Arrays.asList(new Timestamp(78), new Timestamp(12))));
  }
  
  
  @Test
  public void testBogoSort() {
    LinkedHashSet<Integer> set = new LinkedHashSet<Integer>();
    Random random = new Random();
    for(int i = 0; i < 10; i++) {
      set.add(random.nextInt());
    }
    ArrayList<Integer> list = new ArrayList<>(set);
    list.sort(null);
    assertEquals(list, BogoSort.bogoSort(set));
  }
}
