/*
 * @author Ranides Atterwim <ranides@gmail.com>
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.collection.iterators;

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import net.ranides.assira.collection.arrays.IntArrays;
import net.ranides.assira.collection.lists.IntArrayList;
import net.ranides.assira.collection.lists.IntList;
import net.ranides.assira.collection.suite.IteratorTester;
import static net.ranides.assira.junit.NewAssert.*;
import org.junit.Test;

/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
 */
public class IntIteratorUtilsTest {
    
    @Test
	public void testFirst() {
		assertEquals(1, IntIteratorUtils.first(IntArrays.asList(1,2,3,4).iterator()));
		assertEquals(1, IntIteratorUtils.first(IntArrays.asList(1,2).iterator()));
		assertEquals(1, IntIteratorUtils.first(IntArrays.asList(1).iterator()));
		
		assertThrows(NoSuchElementException.class, () -> {
			IteratorUtils.first(Arrays.asList().iterator());
		});
	}
	
	@Test
	public void testLast() {
		assertEquals(4, IntIteratorUtils.last(IntArrays.asList(1,2,3,4).iterator()));
		assertEquals(4, IntIteratorUtils.last(IntArrays.asList(3,4).iterator()));
		assertEquals(4, IntIteratorUtils.last(IntArrays.asList(4).iterator()));
		
		assertThrows(NoSuchElementException.class, () -> {
			IteratorUtils.last(Arrays.asList().iterator());
		});
	}
    
    @Test
	public void testFirst_Filter() {
		assertEquals(7, IntIteratorUtils.first(IntArrays.asList(1,2,7,0,8,0,3).iterator(), a -> a>5));
		
		assertThrows(NoSuchElementException.class, () -> {
			IntIteratorUtils.first(IntArrays.asList(1,2,3).iterator(), a -> a>5);
		});
		assertThrows(NoSuchElementException.class, () -> {
			IntIteratorUtils.first(IntArrays.asList().iterator(), a -> a>5);
		});
	}
	
	@Test
	public void testLast_Filter() {
		assertEquals(8, IntIteratorUtils.last(IntArrays.asList(1,2,7,0,8,0,3).iterator(), a -> a>5));
		assertEquals(8, IntIteratorUtils.last(IntArrays.asList(1,2,7,0,8).iterator(), a -> a>5));
		assertEquals(8, IntIteratorUtils.last(IntArrays.asList(1,8).iterator(), a -> a>5));
		assertEquals(8, IntIteratorUtils.last(IntArrays.asList(8,1).iterator(), a -> a>5));
		
		assertThrows(NoSuchElementException.class, () -> {
			IntIteratorUtils.last(IntArrays.asList(1,2,3).iterator(), a -> a>5);
		});
		assertThrows(NoSuchElementException.class, () -> {
			IntIteratorUtils.last(IntArrays.asList().iterator(), a -> a>5);
		});
	}
	
    
    @Test
	public void testSize() {
		assertEquals(4, IntIteratorUtils.size(IntArrays.asList(1,2,7,8).iterator()));
		assertEquals(2, IntIteratorUtils.size(IntArrays.asList(1,2).iterator()));
		assertEquals(1, IntIteratorUtils.size(IntArrays.asList(1).iterator()));
		assertEquals(0, IntIteratorUtils.size(IntArrays.asList().iterator()));
		assertEquals(0, IntIteratorUtils.size(null));
	}
	
	
	@Test
	public void testMap_Iterator() {
        IntList list = new IntArrayList(new int[]{1,2,3,4,5});
        
		IntIterator a = IntIteratorUtils.map((IntIterator)list.iterator(), (int v)->10*v);
		IteratorTester.basicIterator(a, 0, new Integer[]{10,20,30,40,50});
        
        IntIterator b = IntIteratorUtils.map((IntIterator)list.iterator(), (int v)->10*v);
        b.next();
        b.remove();
        b.next();
        b.next();
        b.remove();
        assertEquals(Arrays.asList(2,4,5), list);
	}
    
    @Test
    public void testMap_IteratorFunction() {
        IntList list = new IntArrayList(new int[]{1,2,3,4,5});
		
        Iterator<String> a = IntIteratorUtils.map((IntIterator)list.iterator(), (int v)->"#"+v);
		IteratorTester.basicIterator(a, 0, new String[]{"#1","#2","#3","#4","#5"});
        
        Iterator<String> b = IntIteratorUtils.map((IntIterator)list.iterator(), (int v)->"#"+v);
        b.next();
        b.remove();
        b.next();
        b.next();
        b.remove();
        assertEquals(Arrays.asList(2,4,5), list);
    }
	
	@Test
	public void testMap_ListIterator() {
		IntList list = new IntArrayList(new int[]{1,2,3,4,5});
        
		IntListIterator a = IntIteratorUtils.map(list.iterator(), (int v)->10*v);
		IteratorTester.basicIterator(a, 0, new Integer[]{10,20,30,40,50});
        
        IntListIterator b = IntIteratorUtils.map(list.iterator(), (int v)->10*v);
        b.next();
        b.remove();
        b.next();
        assertThrows(UnsupportedOperationException.class, ()->{ b.set(9); });
        assertThrows(UnsupportedOperationException.class, ()->{ b.add(9); });
        b.next();
        b.remove();
        assertEquals(Arrays.asList(2,4,5), list);
	}
    
    @Test
    public void testMap_ListIteratorFunction() {
        IntList list = new IntArrayList(new int[]{1,2,3,4,5});
		
        ListIterator<String> a = IntIteratorUtils.map(list.iterator(), (int v)->"#"+v);
		IteratorTester.basicIterator(a, 0, new String[]{"#1","#2","#3","#4","#5"});
        
        ListIterator<String> b = IntIteratorUtils.map(list.iterator(), (int v)->"#"+v);
        b.next();
        b.remove();
        b.next();
        assertThrows(UnsupportedOperationException.class, ()->{ b.set("Q"); });
        assertThrows(UnsupportedOperationException.class, ()->{ b.add("Q"); });
        b.next();
        b.remove();
        assertEquals(Arrays.asList(2,4,5), list);
    }
    
    @Test
	public void testFilter_Iterator() {
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9);
        
		IteratorTester.basicIterator(IntIteratorUtils.filter(IntIterator.wrap(list.iterator()), v -> v%2==0), 0, new Integer[]{2,4,6,8});
		IteratorTester.basicIterator(IntIteratorUtils.filter(IntIterator.wrap(list.iterator()), v -> v%2==1), 0, new Integer[]{1,3,5,7,9});
		IteratorTester.basicIterator(IntIteratorUtils.filter(IntIterator.wrap(list.iterator()), v -> v>5), 0, new Integer[]{6,7,8,9});
	}
	
	@Test
	public void testFilter_ListIterator() {
		IntList list = IntArrays.asList(1,2,3,4,5,6,7,8,9);

		IteratorTester.listIterator(IntIteratorUtils.filter(list.listIterator(), v -> v%2==0), 0, new Integer[]{2,4,6,8});
		IteratorTester.listIterator(IntIteratorUtils.filter(list.listIterator(), v -> v%2==1), 0, new Integer[]{1,3,5,7,9});
		IteratorTester.listIterator(IntIteratorUtils.filter(list.listIterator(), v -> v>5), 0, new Integer[]{6,7,8,9});
		
		
		IteratorTester.listIterator(IntIteratorUtils.filter(list.listIterator(2), v -> v%2==0), 0, new Integer[]{4,6,8});
		IteratorTester.listIterator(IntIteratorUtils.filter(list.listIterator(2), v -> v%2==1), 0, new Integer[]{3,5,7,9});
		IteratorTester.listIterator(IntIteratorUtils.filter(list.listIterator(6), v -> v>5), 0, new Integer[]{7,8,9});
	}
    
    @Test
	public void testReverse() {
        IntList list = new IntArrayList(new int[]{1,2,3,4,5,6,7,8,9});
        IntListIterator a = list.listIterator(9);
        IteratorTester.basicIterator(IntIteratorUtils.reverse(a), 0, new Integer[]{9,8,7,6,5,4,3,2,1});
        
        IntIterator b = IntIteratorUtils.reverse(list.listIterator(9));
        IteratorUtils.next(b, 1);
        b.remove();
        IteratorUtils.next(b, 2);
        b.remove();
        IteratorUtils.next(b, 3);
        b.remove();
        assertEquals(new IntArrayList(new int[]{1,2,3,5,6,8}),list);
    }
	
    @Test
    public void testStream() {
        IntList exp = IntArrays.asList(1,2,3,4,5,6,7,8,9);
        IntList out = new IntArrayList();
        IntIteratorUtils.stream( exp.listIterator() ).forEach(v -> out.add(v));
        assertEquals(exp, out);
    }
	
}
