package fr.umlv.universe;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.junit.Assert;
import org.junit.Test;

public class UniverseSetTest {
  @Test
  public void universeSetConstructors() {
    Universe<String> universe = Universe.universe("foo", "bar");
    Assert.assertTrue(universe.newSet().isEmpty());
    Assert.assertEquals(1, universe.newSet("foo").size());
    Assert.assertEquals(1, universe.newSet(Arrays.asList("bar")).size());
  }

  @Test(expected=IllegalArgumentException.class)
  public void universeSetConstructorNotInSet1() {
    Universe<String> universe = Universe.universe("baz");
    Set<String> set = universe.newSet();
    set.add("zab");
  }

  @Test(expected=IllegalArgumentException.class)
  public void universeSetConstructorNotInSet2() {
    Universe<Integer> universe = Universe.universe(-1, 42);
    universe.newSet(-42);
  }

  @Test(expected=IllegalArgumentException.class)
  public void universeSetConstructorNotInSet3() {
    Universe<Double> universe = Universe.universe(12.);
    universe.newSet(Arrays.asList(21.));
  }

  @Test
  public void universeSetConstructorAll() {
    Universe<Integer> universe = Universe.universe(123, 321);
    Set<Integer> set = universe.newSet(universe);
    Assert.assertEquals(universe, set);
  }

  @Test
  public void universeSetAdd() {
    Universe<Object> universe = Universe.<Object>universe("zoo", 100);
    Set<Object> set = universe.newSet();
    set.add("zoo");
    Assert.assertEquals(Collections.singleton("zoo"), set);
  }

  @Test
  public void universeSetIterator() {
    Universe<Integer> universe = Universe.universe(1,4,5,7);
    Set<Integer> set = universe.newSet(universe);
    Iterator<Integer> iterator = set.iterator();
    Assert.assertTrue(iterator.hasNext());
    Assert.assertTrue(iterator.hasNext());

    HashSet<Integer> hashSet = new HashSet<>();
    for(int i=0; i<universe.size(); i++) {
      hashSet.add(iterator.next());
    }
    Assert.assertFalse(iterator.hasNext());
    Assert.assertEquals(set, hashSet);
  }

  @Test
  public void universeSetIteratorRemove() {
    Universe<Integer> universe = Universe.universe(1,4,5,7);
    Set<Integer> set = universe.newSet(universe);
    Iterator<Integer> iterator = set.iterator();
    for(int i=0; i<universe.size(); i++) {
      int value = iterator.next();
      if (value % 2 == 1) {
        iterator.remove();
      }
    }
    Assert.assertEquals(Collections.singleton(4), set);
  }

  @Test(expected=IllegalStateException.class)
  public void universeSetIteratorRemove2() {
    Universe<Integer> universe = Universe.universe(1,4,5,7);
    Set<Integer> set = universe.newSet(universe);
    Iterator<Integer> iterator = set.iterator();
    iterator.next();
    iterator.remove();
    iterator.remove();
  }

  @Test
  public void universeSetRemove() {
    Universe<String> universe = Universe.universe("1", "2");
    Set<String> set = universe.newSet(universe);
    Assert.assertTrue(set.remove("2"));
    Assert.assertFalse(set.remove("3"));
    Assert.assertEquals(Collections.singleton("1"), set);
  }

  @Test
  public void universeSetClear() {
    Universe<String> universe = Universe.universe("1", "2");
    Set<String> set = universe.newSet(universe);
    set.clear();
    Assert.assertTrue(set.isEmpty());
  }

  @Test
  public void universeSetAddAll() {
    Universe<Object> universe = Universe.<Object>universe("zoo", 100);
    Set<Object> set = universe.newSet();
    Assert.assertTrue(set.addAll(Arrays.asList(100, "zoo")));
    Assert.assertEquals(universe, set);
  }

  @Test
  public void universeSetAddAll2() {
    Universe<Integer> universe = Universe.universe(1, 34, 5, 7);
    Set<Integer> set1 = universe.newSet(34, 7);
    Set<Integer> set2 = universe.newSet(1, 5);
    Assert.assertTrue(set1.addAll(set2));
    Assert.assertEquals(universe, set1);
  }

  @Test
  public void universeSetRemoveAll() {
    Universe<String> universe = Universe.universe("1877", "1921");
    Set<String> set = universe.newSet(universe);
    Assert.assertTrue(set.removeAll(Arrays.asList("1921", "1877", "1757")));
    Assert.assertTrue(set.isEmpty());
  }

  @Test
  public void universeSetRemoveAll2() {
    Universe<Integer> universe = Universe.universe(23, 56, 78, 69);
    Set<Integer> set = universe.newSet(universe);
    Assert.assertTrue(set.removeAll(universe.newSet(69)));
    Assert.assertEquals(universe.newSet(23, 56, 78), set);
  }

  @Test
  public void universeSetRemoveAll3() {
    Universe<Integer> universe = Universe.universe(23, 56, 78, 69);
    Set<Integer> set = universe.newSet(universe);
    Assert.assertTrue(set.removeAll(universe));
    Assert.assertTrue(set.isEmpty());
  }

  @Test
  public void universeSetRetainAll() {
    Universe<String> universe = Universe.universe("1877", "1921");
    Set<String> set = universe.newSet(universe);
    Assert.assertTrue(set.retainAll(Arrays.asList("1921", "1757")));
    Assert.assertEquals(Collections.singleton("1921"), set);
  }

  @Test
  public void universeSetRetainAll2() {
    Universe<String> universe = Universe.universe("1877", "1921");
    Set<String> set = universe.newSet(universe);
    Assert.assertTrue(set.retainAll(universe.newSet("1921")));
    Assert.assertEquals(Collections.singleton("1921"), set);
  }

  @Test
  public void universeSetRetainAll3() {
    Universe<Integer> universe = Universe.universe(23, 56, 78, 69);
    Set<Integer> set = universe.newSet(universe);
    Assert.assertFalse(set.retainAll(universe));
    Assert.assertEquals(universe, set);
  }
}