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

package net.ranides.assira.collection;

import java.util.*;
import net.ranides.assira.generic.Function;
import static org.junit.Assert.*;
import org.junit.Test;

/**
 *
 * @author ranides
 */
@SuppressWarnings({"UnnecessaryUnboxing", "DLS_DEAD_LOCAL_STORE"})
public class ListUtilsTest {
    
    private void testShift(List<Integer> a, List<Integer> b, List<Integer> c, List<Integer> d) {
        ListUtils.shift(a);
        assertEquals(Arrays.asList(2, 3, 4, 5, 6, 6), a);
        
        ListUtils.shift(a);
        assertEquals(Arrays.asList(3, 4, 5, 6, 6, 6), a);
        
        
        ListUtils.shift(b);
        assertEquals(Arrays.asList(2, 2), b);
        
        
        ListUtils.shift(c);
        assertEquals(Arrays.asList(1), c);

        try {
            ListUtils.shift(d);
            fail("exception expected");
        } catch(EmptyCollectionException cause) {
            assertTrue(true);
        }

    }
    
    private void testUnshift(List<Integer> a, List<Integer> b, List<Integer> c, List<Integer> d) {
        ListUtils.unshift(a);
        assertEquals(Arrays.asList(1, 1, 2, 3, 4, 5), a);
        
        ListUtils.unshift(a);
        assertEquals(Arrays.asList(1, 1, 1, 2, 3, 4), a);
        
        
        ListUtils.unshift(b);
        assertEquals(Arrays.asList(1, 1), b);
        
        
        ListUtils.unshift(c);
        assertEquals(Arrays.asList(1), c);

        try {
            ListUtils.unshift(d);
            fail("exception expected");
        } catch(EmptyCollectionException cause) {
            assertTrue(true);
        }
        
    }
    
    @Test
    public void testShift() {
        testShift(
            new ArrayList<>(Arrays.asList(1,2,3,4,5,6)), 
            new ArrayList<>(Arrays.asList(1,2)), 
            new ArrayList<>(Arrays.asList(1)), 
            new ArrayList<Integer>()
        );
        
        testShift(
            new LinkedList<>(Arrays.asList(1,2,3,4,5,6)), 
            new LinkedList<>(Arrays.asList(1,2)), 
            new LinkedList<>(Arrays.asList(1)), 
            new LinkedList<Integer>()
        );
        
        assertTrue(true);
    }
    
    @Test
    public void testUnshift() {
        testUnshift(
            new ArrayList<>(Arrays.asList(1,2,3,4,5,6)), 
            new ArrayList<>(Arrays.asList(1,2)), 
            new ArrayList<>(Arrays.asList(1)), 
            new ArrayList<Integer>()
        );
        
        testUnshift(
            new LinkedList<>(Arrays.asList(1,2,3,4,5,6)), 
            new LinkedList<>(Arrays.asList(1,2)), 
            new LinkedList<>(Arrays.asList(1)), 
            new LinkedList<Integer>()
        );
        
        assertTrue(true);
    }
    
    @Test
    public void testFirst() {
        assertEquals(1, ListUtils.first(Arrays.asList(1,2,3)).intValue());
        assertEquals(1, ListUtils.first(Arrays.asList(1)).intValue());
        assertNull(ListUtils.first(Arrays.asList()));
        assertNull(ListUtils.first(null));
        
        assertEquals( 1L, ListUtils.first(Arrays.<Object>asList(0f, 7, 1L), Long.class).longValue());
        assertEquals( 7L, ListUtils.first(Arrays.<Object>asList(7L, 0f, 7, 1L), Long.class).longValue());
        assertEquals( 7L, ListUtils.first(Arrays.<Object>asList(7L, 1L), Long.class).longValue());
        assertEquals( 7L, ListUtils.first(Arrays.<Object>asList(7L), Long.class).longValue());
        assertNull( ListUtils.first(Arrays.<Object>asList(0f, 7), Long.class));
        assertNull( ListUtils.first(Arrays.<Object>asList(), Long.class));
        assertNull( ListUtils.first(null, Long.class));
    }
    
    @Test
    public void testLast() {
        assertEquals(3, ListUtils.last(Arrays.asList(1,2,3)).intValue());
        assertEquals(1, ListUtils.last(Arrays.asList(1)).intValue());
        assertNull(ListUtils.last(Arrays.asList()));
        assertNull(ListUtils.last(null));
        
        assertEquals( 1L, ListUtils.last(Arrays.<Object>asList(0f, 7, 1L), Long.class).longValue());
        assertEquals( 1L, ListUtils.last(Arrays.<Object>asList(7L, 0f, 7, 1L), Long.class).longValue());
        assertEquals( 1L, ListUtils.last(Arrays.<Object>asList(7L, 1L), Long.class).longValue());
        assertEquals( 7L, ListUtils.last(Arrays.<Object>asList(7L), Long.class).longValue());
        assertNull( ListUtils.last(Arrays.<Object>asList(0f, 7), Long.class));
        assertNull( ListUtils.last(Arrays.<Object>asList(), Long.class));
        assertNull( ListUtils.last(null, Long.class));
    }
    
    @Test
    public void testProduce() {
        Function<String, Integer> gen = new Function<String, Integer>() {
            @Override
            public String apply(Integer source) {
                return String.valueOf(source);
            }
        };
        assertEquals(Arrays.asList(), ListUtils.produce(0, gen));
        assertEquals(Arrays.asList("0"), ListUtils.produce(1, gen));
        assertEquals(Arrays.asList("0","1","2","3"), ListUtils.produce(4, gen));
    }
    
    @Test
    public void testGet() {
        assertNull( ListUtils.get(null, 4) );
        assertNull( ListUtils.get(null, 0) );
        assertNull( ListUtils.get(Arrays.asList(1,2,3), 6) );
        assertNull( ListUtils.get(Arrays.asList(1,2,3), -2) );
        
        assertEquals( 1, ListUtils.get(Arrays.asList(1,2,3), 0).intValue() );
        assertEquals( 3, ListUtils.get(Arrays.asList(1,2,3), 2).intValue() );
        
        assertEquals(99, ListUtils.get(null, 4, 99).intValue() );
        assertEquals(99, ListUtils.get(null, 0, 99).intValue() );
        assertEquals(99, ListUtils.get(Arrays.asList(1,2,3), 6, 99).intValue() );
        assertEquals(99, ListUtils.get(Arrays.asList(1,2,3), -2, 99).intValue() );
        
        assertEquals( 1, ListUtils.get(Arrays.asList(1,2,3), 0, 99).intValue() );
        assertEquals( 3, ListUtils.get(Arrays.asList(1,2,3), 2, 99).intValue() );
    }
    
    @Test
    public void testSize() {
        assertEquals(0, ListUtils.size(null));
        assertEquals(0, ListUtils.size(Collections.emptyList()));
        assertEquals(1, ListUtils.size(Arrays.asList(1)));
        assertEquals(3, ListUtils.size(Arrays.asList(1,1,1)));
        
        assertTrue(ListUtils.isEmpty(null));
        assertTrue(ListUtils.isEmpty(Collections.emptyList()));
        assertFalse(ListUtils.isEmpty(Arrays.asList(1)));
        assertFalse(ListUtils.isEmpty(Arrays.asList(1,1,1)));
        
        assertTrue( ListUtils.equalSize(null, null) );
        assertTrue( ListUtils.equalSize(Collections.emptyList(), null) );
        assertTrue( ListUtils.equalSize(null, Collections.emptyList()) );
        assertTrue( ListUtils.equalSize(Arrays.asList(1,1,1), Arrays.asList(1,3,4)) );
        
        assertFalse( ListUtils.equalSize(Arrays.asList(1,1,1), Arrays.asList(1,1)) );
        assertFalse( ListUtils.equalSize(null, Arrays.asList(1,1)) );
        assertFalse( ListUtils.equalSize(Arrays.asList(1,1),null) );
        
        
        assertTrue( 0 == ListUtils.compareSize(null, null) );
        assertTrue( 0 == ListUtils.compareSize(Collections.emptyList(), null) );
        assertTrue( 0 == ListUtils.compareSize(null, Collections.emptyList()) );
        assertTrue( 0 == ListUtils.compareSize(Arrays.asList(1,1,1), Arrays.asList(1,3,4)) );
        
        assertFalse( ListUtils.compareSize(Arrays.asList(1,1,1), Arrays.asList(1,1)) > 0 );
        assertFalse( ListUtils.compareSize(null, Arrays.asList(1,1)) < 0 );
        assertFalse( ListUtils.compareSize(Arrays.asList(1,1),null) > 0 );
    }

    @Test
    public void testClip() {
        assertEquals(Arrays.asList(1,2,3), ListUtils.clip(Arrays.asList(1,2,3), 5));
        assertEquals(Arrays.asList(1,2,3), ListUtils.clip(Arrays.asList(1,2,3), 3));
        assertEquals(Arrays.asList(1,2), ListUtils.clip(Arrays.asList(1,2,3), 2));
        assertEquals(Arrays.asList(1), ListUtils.clip(Arrays.asList(1,2,3), 1));
        assertEquals(Arrays.asList(), ListUtils.clip(Arrays.asList(1,2,3), 0));
    }
    
    @Test
    public void testToArray() {
        int[] out = ListUtils.toArray(int.class, Arrays.asList(1,2,3,4,5));
        assertArrayEquals(new int[]{1,2,3,4,5}, out);
        
        try {
            ListUtils.toArray(short.class, Arrays.asList(1,2,3,4,5));
            fail();
        } catch(ClassCastException ex) {
            assertTrue(true);
        }
    }
    
    @Test
    public void testConstCopy() {
        List<Integer> out = ListUtils.constCopy(new Integer[]{1,2,3,4,5});
        assertEquals(Arrays.asList(1,2,3,4,5), out);
        assertEquals(5, out.size());
    }

}
