package fr.umlv.tpnotesept;

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

import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentSkipListSet;

import org.junit.Test;

public class ListsTest {
  @Test(expected=NullPointerException.class)
  public void testNull() {
    Lists.asList(null);
  }
  
  @Test
  public void testNavigable() {
    Lists.asList(new TreeSet<>());
    Lists.asList(new ConcurrentSkipListSet<>());
  }
  
  @Test
  public void testSize() {
    TreeSet<CharSequence> set = new TreeSet<>();
    for(int i=0; i<1000; i++) {
      set.add(Integer.toString(i));
    }
    List<CharSequence> list = Lists.asList(set);
    assertEquals(1000, list.size());
    
    set.add("foo");
    assertEquals(1001, list.size());
  }
  
  @Test
  public void testGet() {
    TreeSet<Integer> set = new TreeSet<>(
        Arrays.asList(1, 22, 333, 4444));
    List<Integer> list = Lists.asList(set);
    assertEquals(1, (int)list.get(0));
    assertEquals(22, (int)list.get(1));
    assertEquals(333, (int)list.get(2));
    assertEquals(4444, (int)list.get(3));
  }

  @Test
  public void testSorted() {
    TreeSet<Integer> set = new TreeSet<>(
        Arrays.asList(77, 7, 7777, 777));
    List<Integer> list = Lists.asList(set);
    assertEquals(7, (int)list.get(0));
    assertEquals(77, (int)list.get(1));
    assertEquals(777, (int)list.get(2));
    assertEquals(7777, (int)list.get(3));
    
    set.add(-7);
    assertEquals(-7, (int)list.get(0));
  }
  
  @Test(timeout=1000)
  public void testSizeO1() {
    TreeSet<String> set = new TreeSet<>();
    List<String> list = Lists.asList(set);
    for(int i=0; i<10_000; i++) {
      assertEquals(i, list.size());
      set.add(Integer.toString(i));
    }
  }
  
  @Test
  public void testIterator() {
    TreeSet<String> set = new TreeSet<>();
    List<String> list = Lists.asList(set);
    Iterator<String> it = list.iterator();
    assertFalse(it.hasNext());
    try {
      it.next();
      fail();
    } catch(NoSuchElementException e) {
      // ok
    }
  }
  
  @Test
  public void testIterator2() {
    TreeSet<String> set = new TreeSet<>();
    List<String> list = Lists.asList(set);
    
    set.add("foo");
    Iterator<String> it = list.iterator();
    assertTrue(it.hasNext());
    assertEquals("foo", it.next());
    assertFalse(it.hasNext());
    try {
      it.next();
      fail();
    } catch(NoSuchElementException e) {
      // ok
    }    
  }
  
  @Test
  public void testForeach() {
    TreeSet<Integer> set = new TreeSet<>();
    List<Integer> list = Lists.asList(set);
    for(int i=0; i<100; i++) {
      set.add(i);
    }
    
    int sum = 0;
    for(Integer i: list) {
      sum += i;
    }
    assertEquals(4950, sum);
  }
  
  @Test
  public void testForeachBackward() {
    TreeSet<Integer> set = new TreeSet<>();
    List<Integer> list = Lists.asList(set);
    for(int i=0; i<100; i++) {
      set.add(i);
    }
    
    int sum = 0;
    for(ListIterator<Integer> it = list.listIterator(list.size()); it.hasPrevious();) {
      sum += it.previous();
    }
    assertEquals(4950, sum);
  }
  
  @Test
  public void firstIndexIterator() {
    TreeSet<Object> set = new TreeSet<>();
    List<Object> list = Lists.asList(set);
    assertEquals(0, list.listIterator().nextIndex());
    assertEquals(-1, list.listIterator().previousIndex());
  }
  
  @Test
  public void lastIndexIterator() {
    TreeSet<Integer> set = new TreeSet<>();
    for(int i=0; i<100; i++) {
      set.add(i);
    }
    List<Integer> list = Lists.asList(set);
    assertEquals(list.size(), list.listIterator(list.size()).nextIndex());
    assertEquals(list.size()-1, list.listIterator(list.size()).previousIndex());
  }
  
  @Test
  public void seekIntheMiddle() {
    TreeSet<Integer> set = new TreeSet<>();
    for(int i=100; --i>=0;) {
      set.add(i);
    }
    List<Integer> list = Lists.asList(set);
    ListIterator<Integer> it = list.listIterator(50);
    assertEquals(50, (int)it.next());
    assertEquals(51, (int)it.next());
    assertEquals(50, (int)it.previous());
    assertEquals(49, (int)it.previous());
  }
  
  @Test
  public void iteratorRemove() {
    TreeSet<Integer> set = new TreeSet<>();
    for(int i=0; i<100; i++) {
      set.add(i);
    }
    List<Integer> list = Lists.asList(set);
    for(Iterator<Integer> it = list.iterator(); it.hasNext();) {
      Integer i = it.next();
      if (i % 2 == 1) {
        it.remove();
      }
    }
    
    for(int i=0; i<100; i+=2) {
      assertTrue(set.contains(i));
      assertFalse(set.contains(i + 1));
    }
  }
  
  @Test(expected=IllegalStateException.class)
  public void iteratorRemove2() {
    TreeSet<String> set = new TreeSet<>();
    List<String> list = Lists.asList(set);
    set.add("foo");
    list.iterator().remove();
  }
  
  @Test
  public void iteratorSet() {
    TreeSet<String> set = new TreeSet<>();
    List<String> list = Lists.asList(set);
    Collections.addAll(set, "bar", "foo");
    ListIterator<String> it = list.listIterator();
    it.next();
    it.set("baz");
    HashSet<String> set2 = new HashSet<>();
    Collections.addAll(set2, "baz", "foo");
    assertEquals(set2, set);
    assertEquals("foo", it.next());
  }
  
  @Test
  public void iteratorSet2() {
    TreeSet<String> set = new TreeSet<>();
    List<String> list = Lists.asList(set);
    Collections.addAll(set, "bar", "baz", "foo");
    ListIterator<String> it = list.listIterator();
    it.next();
    it.next();
    it.set("bat");
    HashSet<String> set2 = new HashSet<>();
    Collections.addAll(set2, "bar", "bat", "foo");
    assertEquals(set2, set);
  }
  
  @Test
  public void iteratorSet3() {
    TreeSet<String> set = new TreeSet<>();
    List<String> list = Lists.asList(set);
    set.add("foo");
    ListIterator<String> it = list.listIterator();
    it.next();
    it.set("xoxo");
    assertEquals(new HashSet<>(Arrays.asList("xoxo")), set);
  }
  
  @Test(expected=IllegalStateException.class)
  public void iteratorSet4() {
    TreeSet<String> set = new TreeSet<>();
    List<String> list = Lists.asList(set);
    ListIterator<String> it = list.listIterator();
    it.set("foobar");
  }
  
  @Test
  public void iteratorSet5() {
    TreeSet<String> set = new TreeSet<>();
    List<String> list = Lists.asList(set);
    set.add("foo");
    ListIterator<String> it = list.listIterator();
    it.next();
    it.set("fool");
    try {
      it.set("april");
      fail();
    } catch(IllegalStateException e) {
      // ok
    }
  }
  
  @Test
  public void iteratorSet6() {
    TreeSet<String> set = new TreeSet<>();
    List<String> list = Lists.asList(set);
    Collections.addAll(set, "bar", "foo");
    ListIterator<String> it = list.listIterator();
    it.next();
    try {
      it.set("fool");
      fail();
    } catch(IllegalStateException e) {
      // ok
    }
  }
  
  @Test
  public void iteratorSet7() {
    TreeSet<String> set = new TreeSet<>();
    List<String> list = Lists.asList(set);
    Collections.addAll(set, "bar", "foo");
    ListIterator<String> it = list.listIterator();
    it.next();
    it.next();
    try {
      it.set("aaa");
      fail();
    } catch(IllegalStateException e) {
      // ok
    }
  }
  
  @Test
  public void iteratorAdd() {
    TreeSet<String> set = new TreeSet<>();
    List<String> list = Lists.asList(set);
    Collections.addAll(set, "bar", "foo");
    ListIterator<String> it = list.listIterator();
    it.next();
    it.add("baz");
    HashSet<String> set2 = new HashSet<>();
    Collections.addAll(set2, "bar", "baz", "foo");
    assertEquals(set2, set);
    assertEquals("foo", it.next());
  }
}
