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

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.NoSuchElementException;
import net.ranides.assira.collection.lists.ListUtils;
import org.junit.Test;
import static net.ranides.assira.junit.NewAssert.*;

/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
 */
public class NativeArraySearchTest {
    
    @Test
    public void testBinarySearch() {
        NativeArray array1 = NativeArray.wrap(new Byte[]{1,2,5,6});
        assertEquals(0, NativeArraySearch.binarySearch(array1, (byte)1));
        assertEquals(1, NativeArraySearch.binarySearch(array1, (byte)2));
        assertEquals(2, NativeArraySearch.binarySearch(array1, (byte)5));
        assertEquals(3, NativeArraySearch.binarySearch(array1, (byte)6));
        assertEquals(-5, NativeArraySearch.binarySearch(array1, (byte)9));
        assertEquals(-1, NativeArraySearch.binarySearch(array1, (byte)0));
        assertEquals(-3, NativeArraySearch.binarySearch(array1, (byte)3));
        assertEquals(-3, NativeArraySearch.binarySearch(array1, (byte)4));
        
        assertTrue(NativeArraySearch.binarySearch(array1, null)<0);
        
    }
    
    @Test
    public void testBinarySearch_range() {
        NativeArray array1 = NativeArray.wrap(new Byte[]{4,1,2,5,6,9});
        assertEquals(1, NativeArraySearch.binarySearch(array1, 1, 5, (byte)1));
        assertEquals(2, NativeArraySearch.binarySearch(array1, 1, 5, (byte)2));
        assertEquals(3, NativeArraySearch.binarySearch(array1, 1, 5, (byte)5));
        assertEquals(4, NativeArraySearch.binarySearch(array1, 1, 5, (byte)6));
        assertEquals(-6, NativeArraySearch.binarySearch(array1, 1, 5, (byte)9));
        assertEquals(-2, NativeArraySearch.binarySearch(array1, 1, 5, (byte)0));
        assertEquals(-4, NativeArraySearch.binarySearch(array1, 1, 5, (byte)3));
        assertEquals(-4, NativeArraySearch.binarySearch(array1, 1, 5, (byte)4));
        
        assertTrue(NativeArraySearch.binarySearch(array1, 1, 5, null) < 0);
    }

    @Test
    public void testBinarySearch_cmp() {
        NativeArray array1 = NativeArray.wrap(new Byte[]{31,22,75,46});
        Comparator<Byte> cmp = (a,b) -> (a%10 - b%10);
        assertEquals(0, NativeArraySearch.binarySearch(array1, (byte)1, cmp));
        assertEquals(1, NativeArraySearch.binarySearch(array1, (byte)92, cmp));
        assertEquals(2, NativeArraySearch.binarySearch(array1, (byte)95, cmp));
        assertEquals(3, NativeArraySearch.binarySearch(array1, (byte)96, cmp));
        assertEquals(-5, NativeArraySearch.binarySearch(array1, (byte)99, cmp));
        assertEquals(-1, NativeArraySearch.binarySearch(array1, (byte)90, cmp));
        assertEquals(-3, NativeArraySearch.binarySearch(array1, (byte)93, cmp));
        assertEquals(-3, NativeArraySearch.binarySearch(array1, (byte)94, cmp));
        
        assertThrows(NullPointerException.class, ()->{
            NativeArraySearch.binarySearch(array1, null, cmp);
        });
    }
    
    @Test
    public void testBinarySearch_cmp_range() {
        NativeArray array1 = NativeArray.wrap(new Byte[]{44,31,22,75,46,59});
        Comparator<Byte> cmp = (a,b) -> (a%10 - b%10);
        assertEquals(1, NativeArraySearch.binarySearch(array1, 1, 5, (byte)1, cmp));
        assertEquals(2, NativeArraySearch.binarySearch(array1, 1, 5, (byte)92, cmp));
        assertEquals(3, NativeArraySearch.binarySearch(array1, 1, 5, (byte)95, cmp));
        assertEquals(4, NativeArraySearch.binarySearch(array1, 1, 5, (byte)96, cmp));
        assertEquals(-6, NativeArraySearch.binarySearch(array1, 1, 5, (byte)99, cmp));
        assertEquals(-2, NativeArraySearch.binarySearch(array1, 1, 5, (byte)90, cmp));
        assertEquals(-4, NativeArraySearch.binarySearch(array1, 1, 5, (byte)93, cmp));
        assertEquals(-4, NativeArraySearch.binarySearch(array1, 1, 5, (byte)94, cmp));
        
        assertThrows(NullPointerException.class, ()->{
            NativeArraySearch.binarySearch(array1, 1, 5, null, cmp);
        });
    }
    
    @Test
    public void testFirst() {
		NativeArray list8 = NativeArray.wrap(new String[]{"a", "b", "cc", "d", "ee", "f", "gg", "h"});

		assertThrows(NoSuchElementException.class, ()-> {
			NativeArraySearch.first(list8, v -> false).get();
		});
		assertThrows(NoSuchElementException.class, ()-> {
			NativeArraySearch.first(list8, 1, 3, v -> false).get();
		});
		
		assertEquals("b", NativeArraySearch.first(list8, 1, 3, v -> true).get());
		
		assertEquals("cc", NativeArraySearch.first(list8, (String v) -> v.length()>1).get());
		assertEquals("cc", NativeArraySearch.first(list8, 1, 3, (String v) -> v.length()>1).get());
		assertEquals("ee", NativeArraySearch.first(list8, 3, 5, (String v) -> v.length()>1).get());
    }
	
	@Test
    public void testLast() {
		NativeArray list8 = NativeArray.wrap(new String[]{"a", "b", "cc", "d", "ee", "f", "gg", "h"});

		assertThrows(NoSuchElementException.class, ()-> {
			NativeArraySearch.last(list8, v -> false).get();
		});
		assertThrows(NoSuchElementException.class, ()-> {
			NativeArraySearch.last(list8, 1, 3, v -> false).get();
		});
		
		assertEquals("d", NativeArraySearch.last(list8, 1, 4, v -> true).get());
		
		assertEquals("gg", NativeArraySearch.last(list8, (String v) -> v.length()>1).get());
		assertEquals("ee", NativeArraySearch.last(list8, 1, 6, (String v) -> v.length()>1).get());
		assertEquals("cc", NativeArraySearch.last(list8, 1, 3, (String v) -> v.length()>1).get());
    }
    
    @Test
    public void testIndexOf() {
        NativeArray list0 = NativeArray.wrap(new String[]{});
        NativeArray list1 = NativeArray.wrap(new String[]{"a"});
        NativeArray list8 = NativeArray.wrap(new String[]{"a", "b", "c", "d", "c", "e", "d", "f"});
        
        assertEquals(-1, NativeArraySearch.indexOf(list0, "q"));
        assertEquals(-1, NativeArraySearch.indexOf(list1, "q"));
        assertEquals(-1, NativeArraySearch.indexOf(list8, "q"));
        
        assertEquals(0, NativeArraySearch.indexOf(list1, "a"));
        assertEquals(2, NativeArraySearch.indexOf(list8, "c"));
        assertEquals(7, NativeArraySearch.indexOf(list8, "f"));
        
        assertThrows(IndexOutOfBoundsException.class, ()->{
            NativeArraySearch.indexOf(list1, 1, 3, "a");
        });
        
        assertEquals(0, NativeArraySearch.indexOf(list8, 0, 3, "a"));
        assertEquals(-1, NativeArraySearch.indexOf(list8, 1, 3, "a"));
        assertEquals(2, NativeArraySearch.indexOf(list8, 1, 6, "c"));
        assertEquals(4, NativeArraySearch.indexOf(list8, 3, 6, "c"));
    }
    
    @Test
    public void testLastIndexOf() {
        NativeArray list0 = NativeArray.wrap(new String[]{});
        NativeArray list1 = NativeArray.wrap(new String[]{"a"});
        NativeArray list8 = NativeArray.wrap(new String[]{"a", "b", "c", "d", "c", "e", "d", "f"});
        
        assertEquals(-1, NativeArraySearch.lastIndexOf(list0, "q"));
        assertEquals(-1, NativeArraySearch.lastIndexOf(list1, "q"));
        assertEquals(-1, NativeArraySearch.lastIndexOf(list8, "q"));
        
        assertEquals(0, NativeArraySearch.lastIndexOf(list1, "a"));
        assertEquals(4, NativeArraySearch.lastIndexOf(list8, "c"));
        assertEquals(7, NativeArraySearch.lastIndexOf(list8, "f"));
        
        assertThrows(IndexOutOfBoundsException.class, ()->{
            NativeArraySearch.lastIndexOf(list1, 1, 3, "a");
        });
        
        assertEquals(0, NativeArraySearch.lastIndexOf(list8, 0, 3, "a"));
        assertEquals(-1, NativeArraySearch.lastIndexOf(list8, 1, 3, "a"));
        assertEquals(4, NativeArraySearch.lastIndexOf(list8, 1, 6, "c"));
        assertEquals(2, NativeArraySearch.lastIndexOf(list8, 1, 3, "c"));
    }
    
    @Test
    public void testContains() {
        NativeArray list0 = NativeArray.wrap(new String[]{});
        NativeArray list1 = NativeArray.wrap(new String[]{"a"});
        NativeArray list8 = NativeArray.wrap(new String[]{"a", "b", "c", "d", "c", "e", "d", "f"});
        
        assertEquals(false, NativeArraySearch.contains(list0, "q"));
        assertEquals(false, NativeArraySearch.contains(list1, "q"));
        assertEquals(false, NativeArraySearch.contains(list8, "q"));
        
        assertEquals(true, NativeArraySearch.contains(list1, "a"));
        assertEquals(true, NativeArraySearch.contains(list8, "c"));
        assertEquals(true, NativeArraySearch.contains(list8, "f"));
        
        assertThrows(IndexOutOfBoundsException.class, ()->{
            NativeArraySearch.contains(list1, 1, 3, "a");
        });
        
        assertEquals(true, NativeArraySearch.contains(list8, 0, 3, "a"));
        assertEquals(false, NativeArraySearch.contains(list8, 1, 3, "a"));
        assertEquals(true, NativeArraySearch.contains(list8, 2, 6, "c"));
        assertEquals(false, NativeArraySearch.contains(list8, 2, 2, "c"));
        assertEquals(true, NativeArraySearch.contains(list8, 1, 6, "c"));
        assertEquals(true, NativeArraySearch.contains(list8, 3, 6, "c"));
    }
    
}
