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

import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.function.Function;
import java.util.function.IntFunction;
import net.ranides.assira.ContractTesters;
import net.ranides.assira.collection.mockup.TMaps;
import net.ranides.assira.collection.mockup.TPoint;
import net.ranides.assira.functional.CoFunction;
import net.ranides.assira.functional.ProjectionFunction;
import net.ranides.assira.test.TCollection;
import org.junit.Test;
import static net.ranides.assira.junit.NewAssert.*;

/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
 */
public class ListUtilsTest {
	
	
    @Test
    public void testFirst() {
		List<String> list8= Arrays.asList("a", "b", "cc", "d", "ee", "f", "gg", "h");
		List<String> list1 = Arrays.asList("a");
		List<String> list0 = Arrays.asList();
		
        assertEquals("a", ListUtils.first(list8).get());
        assertEquals("a", ListUtils.first(list1).get());
		
        assertThrows(NoSuchElementException.class, ()-> {
			ListUtils.first(list0).get();
		});
		assertThrows(NoSuchElementException.class, ()-> {
			ListUtils.first(list8, v -> false).get();
		});
		assertThrows(NoSuchElementException.class, ()-> {
			ListUtils.first(list8, 1, 3, v -> false).get();
		});
		
		assertEquals("b", ListUtils.first(list8, 1, 3, v -> true).get());
		
		assertEquals("cc", ListUtils.first(list8, v -> v.length()>1).get());
		assertEquals("cc", ListUtils.first(list8, 1, 3, v -> v.length()>1).get());
		assertEquals("ee", ListUtils.first(list8, 3, 5, v -> v.length()>1).get());
    }
	
	@Test
    public void testLast() {
		List<String> list8= Arrays.asList("a", "b", "cc", "d", "ee", "f", "gg", "h");
		List<String> list1 = Arrays.asList("a");
		List<String> list0 = Arrays.asList();
		
        assertEquals("h", ListUtils.last(list8).get());
        assertEquals("a", ListUtils.last(list1).get());
		
        assertThrows(NoSuchElementException.class, ()-> {
			ListUtils.last(list0).get();
		});
		assertThrows(NoSuchElementException.class, ()-> {
			ListUtils.last(list8, v -> false).get();
		});
		assertThrows(NoSuchElementException.class, ()-> {
			ListUtils.last(list8, 1, 3, v -> false).get();
		});
		
		assertEquals("d", ListUtils.last(list8, 1, 4, v -> true).get());
		
		assertEquals("gg", ListUtils.last(list8, v -> v.length()>1).get());
		assertEquals("ee", ListUtils.last(list8, 1, 6, v -> v.length()>1).get());
		assertEquals("cc", ListUtils.last(list8, 1, 3, v -> v.length()>1).get());
    }
	
	@Test
	public void testFilter() {
		assertEquals(Arrays.asList(2,4,6), ListUtils.filter(Arrays.asList(1,2,3,4,5,6), v -> 0==v%2));
	}
	
	@Test
	public void testMap() {
		
		TCollection<TPoint> $var = TMaps.MAP_PI.keys();
		
		Function<Integer, TPoint> fget = (Function<Integer, TPoint> & Serializable)
			v -> $var.item(v).value();
		
		Function<int[], List<TPoint>> fgen = (Function<int[], List<TPoint>> & Serializable)
			array -> ListUtils.map(new IntArrayList(array), fget);
		
		ContractTesters.runner()
			.ignore("CollectionTester.basicAdd")
			.ignore("CollectionTester.basicAddContains")
			
			.ignore("ListTester.basicAdd")
			.ignore("ListTester.basicAddAll")
			.ignore("ListTester.basicAddAllAt")
			.ignore("ListTester.basicAddAt")
			.ignore("ListTester.basicClearAdd")
			.ignore("ListTester.basicIterator_Add")
			.ignore("ListTester.basicIterator_Set")
			.ignore("ListTester.basicSet")
			.ignore("ListTester.basicSublist_add")
			.ignore("ListTester.basicSublist_addAll")
			.ignore("ListTester.basicSublist_clearAdd")
			.ignore("ListTester.basicSublist_set")
			
			.param("collection!", $var)
			.function(new int[0], fgen)
			.run();
		assertTrue(true);
	}
	
	@Test
	public void testMapProjection() {
		
		TCollection<TPoint> $var = TMaps.MAP_PI.keys();
		
		Function<Integer, TPoint> fget = (Function<Integer, TPoint> & Serializable)
			v -> $var.item(v).value();
		
		CoFunction<Integer, TPoint> fset = (CoFunction<Integer, TPoint> & Serializable)
			v -> v.x;
			
		Function<int[], List<TPoint>> fgen = (Function<int[], List<TPoint>> & Serializable)
			array -> ListUtils.map(new IntArrayList(array), ProjectionFunction.produce(fget, fset));
		
		ContractTesters.runner()
			.param("collection!", $var)
			.function(new int[0], fgen)
			.run();
		assertTrue(true);
	}
	
	@Test
	public void testProduce() {
		
		TCollection<TPoint> $var = TMaps.MAP_PI.keys();
		
		Function<int[], List<TPoint>> fgen = (Function<int[], List<TPoint>> & Serializable)
			array -> ListUtils.produce(
				array.length, 
				(IntFunction<TPoint> & Serializable) i -> $var.item(array[i]).value()
			);
		
		ContractTesters.runner()
			.ignore("CollectionTester.basicAdd")
			.ignore("CollectionTester.basicAddContains")
			.ignore("CollectionTester.basicRemove")
			.ignore("CollectionTester.basicRetainAll")
			
			.ignore("ListTester.basicAdd")
			.ignore("ListTester.basicAddAll")
			.ignore("ListTester.basicAddAllAt")
			.ignore("ListTester.basicAddAt")
			.ignore("ListTester.basicRemove")
			.ignore("ListTester.basicRemoveRetainAll")
			.ignore("ListTester.basicRemoveIndex")
			.ignore("ListTester.basicClear")
			.ignore("ListTester.basicClearAdd")
			.ignore("ListTester.basicIterator_Add")
			.ignore("ListTester.basicIterator_Set")
			.ignore("ListTester.basicIterator_Remove")
			.ignore("ListTester.basicSet")
			.ignore("ListTester.basicSublist_add")
			.ignore("ListTester.basicSublist_addAll")
			.ignore("ListTester.basicSublist_clear")
			.ignore("ListTester.basicSublist_clearAdd")
			.ignore("ListTester.basicSublist_set")
						
			.param("collection!", $var)
			.function(new int[0], fgen)
			.run();
		assertTrue(true);
	}
    
}
