/*
 * @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.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import net.ranides.assira.ContractTesters;
import net.ranides.assira.collection.arrays.ArrayUtils;
import net.ranides.assira.collection.mockup.TMaps;
import net.ranides.assira.collection.mockup.TPoint;
import net.ranides.assira.test.TCollection;
import static net.ranides.assira.junit.NewAssert.*;
import org.junit.Test;

/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
 */
public class FlatListTest {

	private final TCollection<TPoint> $var = TMaps.MAP_PI.keys();
	
	@Test
	public void testContract() {
		
		ContractTesters.runner()
			.param("collection!", $var)
			.function(new int[0], this::jlist1)
			.run();
		
		ContractTesters.runner()
			.param("collection!", $var)
			.function(new int[0], this::jlist2)
			.run();
		
		ContractTesters.runner()
			.param("collection!", $var)
			.function(new int[0], (array) -> jlist3(new int[]{1,3,4}, array))
			.run();
		
		ContractTesters.runner()
			.param("collection!", $var)
			.function(new int[0], (array) -> jlist4(new int[]{1,3,4}, array))
			.run();
		
		ContractTesters.runner()
			.param("collection!", $var)
			.function(new int[0], (array) -> jlist5(new int[]{1,3,4}, array))
			.run();
	
	}
	
	@Test
	public void testJoinAll() {
		FlatList<Integer> list= new FlatList<>();
		list.join(a(10,11,12,13));
		list.joinAll(a(a(21,22),a(31,32)));
		list.joinAll(1, a(a(41,42),a(51,52)));
		list.join(2, a(61,62));
		
		assertEquals(a(10, 11, 12, 13, 41, 42, 61, 62, 51, 52, 21, 22, 31, 32), list);
	}
	
    @SafeVarargs
	private static <T> List<T> a(T... values) {
		return Arrays.asList(values);
	}
	
	private FlatList<TPoint> jlist1(int[] array) {
		FlatList<TPoint> ret = new FlatList<>();
		ret.join($var.list(array).into(new ArrayList<>()));
		return ret;
	}
	
	private FlatList<TPoint> jlist2(int[] array) {
		TPoint[] src = $var.list(array).values();
		FlatList<TPoint> ret = new FlatList<>();

		List<TPoint> now = new ArrayList<>();
		for(int i=0; i<src.length; i++) {
			now.add(src[i]);
			if(4 == i % 5) {
				ret.join(now);
				now = new ArrayList<>();
			}
		}
		ret.join(now);
		return ret;
	}

	private FlatList<TPoint> jlist3(int[] sizes, int[] array) {
		FlatList<TPoint> ret = new FlatList<>();
		for(List<TPoint> now : split(sizes, array)) {
			ret.join(now);
		}
		return ret;
	}
	
	private FlatList<TPoint> jlist4(int[] sizes, int[] array) {
		return new FlatList<>(split(sizes, array));
	}
	
    @SuppressWarnings("unchecked")
	private FlatList<TPoint> jlist5(int[] sizes, int[] array) {
		return new FlatList<>( split(sizes, array).toArray(new List[0]));
	}
	
	private List<List<TPoint>> split(int[] sizes, int[] array) {
		Iterator<TPoint> src = ArrayUtils.iterator($var.list(array).values());
		List<List<TPoint>> ret = new ArrayList<>();

		for(int isize : sizes) {
			List<TPoint> now = new ArrayList<>();
			for(int c=0; c<isize && src.hasNext(); c++) {
				now.add(src.next());
			}
			ret.add(now);
		}
		
		if( !src.hasNext() ) {
			return ret;
		}
					
		List<TPoint> now = new ArrayList<>();
		while(src.hasNext()) {
			now.add(src.next());
		}
		ret.add(now);
		return ret;
	}
	
}
