/*
 * @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.Random;
import net.ranides.assira.collection.Swapper;
import org.junit.Test;
import static org.junit.Assert.*;

/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
 */
public class NativeArraySortTest {
    
    @Test
    public void testQuickSort_cmp() {
        NativeArray input3 = rangeR(100,200);
        NativeArray input4 = rangeR(100,200);
           
        NativeArraySort.quickSort(input3, (Integer a,Integer b) -> a-b);
        assertEquals(rangeA(100,200), input3);
        
        NativeArraySort.quickSort(input4, (Integer a,Integer b) -> b-a);
        assertEquals(rangeD(100, 200), input4);
    }
    
    @Test
    public void testQuickSort_range() {
        NativeArray input3 = rangeR(100,200);
        NativeArray input4 = rangeR(100,200);
        
        NativeArraySort.quickSort(input3, 0, 100, (Integer a, Integer b) -> a-b);
        assertEquals(rangeA(100,200), input3);
        
        NativeArraySort.quickSort(input4, 0, 100, (Integer a,Integer b) -> b-a);
        assertEquals(rangeD(100, 200), input4);
    }
    
    @Test
    public void testQuickSort_swapper() {
        Integer[] input3 = rangeR(100,200).$array();
        Integer[] input4 = rangeR(100,200).$array();
               
        NativeArraySort.quickSort(0, input3.length, (a,b) -> input3[a]-input3[b], NativeArray.wrap(input3));
        assertArrayEquals(rangeA(100, 200).$array(), input3);
        
        NativeArraySort.quickSort(0, input4.length, (a,b) -> input4[b]-input4[a], NativeArray.wrap(input4));
        assertArrayEquals(rangeD(100, 200).$array(), input4);
    }
    
    @Test
    public void testQuickSort_indirect() {
        NativeArray input1 = NativeArray.wrap(new Integer[]{2,4,1,3});
        NativeArray input2 = NativeArray.wrap(new String[]{"1B","2D","3A","4C"});
               
        NativeArraySort.quickSort(0, input1.size(), input1.comparator(), (a,b) -> {
            input1.swap(a, b);
            input2.swap(a, b);
        });
        
        assertEquals("[1, 2, 3, 4]", input1.toString());
        assertEquals("[3A, 1B, 4C, 2D]", input2.toString());
    }
    
    @Test
    public void testMergeSort_indirect() {
        NativeArray input1 = NativeArray.wrap(new Integer[]{2,4,1,3});
        NativeArray input2 = NativeArray.wrap(new String[]{"1B","2D","3A","4C"});
               
        NativeArraySort.mergeSort(0, input1.size(), input1.comparator(), (a,b) -> {
            input1.swap(a, b);
            input2.swap(a, b);
        });
        
        assertEquals("[1, 2, 3, 4]", input1.toString());
        assertEquals("[3A, 1B, 4C, 2D]", input2.toString());
    }
    
    @Test
    public void testMergeSort() {
        NativeArray input1 = rangeR(100,200);
           
        NativeArraySort.mergeSort(input1);
        assertEquals(rangeA(100,200), input1);
    }
    
    @Test
    public void testMergeSort_range() {
        NativeArray input1 = rangeR(100,200);
           
        NativeArraySort.mergeSort(input1, 0, 100);
        assertEquals(rangeA(100,200), input1);
    }
    
    @Test
    public void testMergeSort_cmp() {
        NativeArray input1 = rangeR(100,200);
        NativeArray input2 = rangeR(100,200);
           
        NativeArraySort.mergeSort(input1, (Integer a,Integer b) -> a-b);
        assertEquals(rangeA(100,200), input1);
        
        NativeArraySort.mergeSort(input2, (Integer a,Integer b) -> b-a);
        assertEquals(rangeD(100,200), input2);
    }
    
    @Test
    public void testMergeSort_swapper() {
        Integer[] input3 = rangeR(100,200).$array();
        Integer[] input4 = rangeR(100,200).$array();
               
        NativeArraySort.mergeSort(0, input3.length, (int a, int b) -> input3[a]-input3[b], NativeArray.wrap(input3));
        assertArrayEquals(rangeA(100, 200).$array(), input3);
        
        NativeArraySort.mergeSort(0, input4.length, (a,b) -> input4[b]-input4[a], NativeArray.wrap(input4));
        assertArrayEquals(rangeD(100, 200).$array(), input4);
    }
    
    private static NativeArray rangeR(int begin, int end) {
        return NativeArrayUtils.shuffle(new Random(333), rangeA(begin,end));
    }
    
    private static NativeArray rangeA(int begin, int end) {
        Integer[] array = new Integer[end-begin];
        for(int i=0; i<array.length; i++) {
            array[i] = i+begin;
        }
        return NativeArray.wrap(array);
    }
    
    private static NativeArray rangeD(int begin, int end) {
        Integer[] array = new Integer[end-begin];
        for(int i=0; i<array.length; i++) {
            array[i] = end-i-1;
        }
        return NativeArray.wrap(array);
    }
    
}
