package arrayOperations;

import static arrayOperations.ArrayOperations.*;

import java.util.Arrays;

import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;

public class ArrayOperationsTest {
    
    int[] singleElementOneDimensionalArray = new int[] { 1 };
    int[] arrayOfFive = new int[] { 1, 2, 3, 4, 5 };
    int[] arrayOfFifteen = new int[] {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
    
    int[][] singleElementTwoDimensionalArray = new int[][] { { 1 } };
    int[][] threeByFiveArray = new int[][] { {  1,  2,  3,  4,  5 },
                                             {  6,  7,  8,  9, 10 }, 
                                             { 11, 12, 13, 14, 15 } };
    

    int[] singleElementOneDimensionalArrayCopy = new int[] { 1 };
    int[] arrayOfFiveCopy = new int[] { 1, 2, 3, 4, 5 };
    int[] arrayOfFifteenCopy = new int[] {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
    
    int[][] singleElementTwoDimensionalArrayCopy = new int[][] { { 1 } };
    int[][] threeByFiveArrayCopy = new int[][] { {  1,  2,  3,  4,  5 },
                                                 {  6,  7,  8,  9, 10 }, 
                                                 { 11, 12, 13, 14, 15 } };
    
    @Before
    public void setUp() throws Exception {}

    @Test
    public void testFill() {
        assertArrayEquals(arrayOfFive, fill(5));
        assertArrayEquals(arrayOfFiveCopy, arrayOfFive);
    }

    @Test
    public void testReverse() {
        int[] expected = new int[] { 5, 4, 3, 2, 1 };
        assertArrayEquals(expected, reverse(arrayOfFive));
        assertArrayEquals(arrayOfFiveCopy, arrayOfFive);
    }

    @Test
    public void testRotateRight() {
        int[][] expected = new int[][] { { 11,  6,  1 },
                                         { 12,  7,  2 },
                                         { 13,  8,  3 },
                                         { 14,  9,  4 },
                                         { 15, 10,  5 } };
        assertArrayEquals(expected, rotateRight(threeByFiveArray));
        assertArrayEquals(threeByFiveArray, threeByFiveArrayCopy);
    }

    @Test
    public void testRotateRight_ZeroLength() {
        int[][] expected = new int[0][0];
        assertArrayEquals(expected, rotateRight(expected));
        assertNotSame(expected, rotateRight(expected));
    }        

    @Test
    public void testRotateLeft() {
        int[][] expected = new int[][] { { 5, 10, 15 },
                                         { 4,  9, 14 },
                                         { 3,  8, 13 },
                                         { 2,  7, 12 },
                                         { 1,  6, 11 } };
        assertArrayEquals(expected, rotateLeft(threeByFiveArray));
        assertArrayEquals(threeByFiveArray, threeByFiveArrayCopy);
    }

    @Test
    public void testRotateLeft_ZeroLength() {
        int[][] expected = new int[0][0];
        assertArrayEquals(expected, rotateLeft(expected));
        assertNotSame(expected, rotateLeft(expected));
    }

    @Test
    public void testTranspose() {
        int[][] expected = new int[][] { { 1,  6, 11 },
                                         { 2,  7, 12 },
                                         { 3,  8, 13 },
                                         { 4,  9, 14 },
                                         { 5, 10, 15 } };
        assertArrayEquals(expected, transpose(threeByFiveArray));
        assertArrayEquals(threeByFiveArray, threeByFiveArrayCopy);
    }

    @Test
    public void testTranspose_ZeroLength() {
        int[][] expected = new int[0][0];
        assertArrayEquals(expected, transpose(expected));
        assertNotSame(expected, transpose(expected));
    }

    @Test
    public void testRavel() {
        assertArrayEquals(threeByFiveArray, ravel(arrayOfFifteen, 5));
        assertArrayEquals(threeByFiveArrayCopy, threeByFiveArray);
        assertArrayEquals(arrayOfFifteenCopy, arrayOfFifteen);
    }

    @Test(expected=IllegalArgumentException.class)
    public void testRavel_BadParameters() {
        ravel(arrayOfFifteen, 6);
    }

    @Test
    public void testRavel_ZeroLength() {
        int[][] expected = new int[0][0];
        assertArrayEquals(expected, ravel(new int[0], 4));
        assertNotSame(expected, ravel(new int[0], 4));
    }

    @Test
    public void testUnravel() {
        assertArrayEquals(arrayOfFifteen, unravel(threeByFiveArray));
        assertArrayEquals(threeByFiveArrayCopy, threeByFiveArray);
        assertArrayEquals(arrayOfFifteenCopy, arrayOfFifteen);
    }

    @Test
    public void testUnravel_ZeroLength() {
        int[] expected = new int[0];
        assertArrayEquals(expected, unravel(new int[0][0]));
        assertNotSame(expected, unravel(new int[0][0]));
    }

    @Test
    public void testReshape() {
        int[][] threeByFourArray = new int[][] { { 1,  2,  3,  4 },
                                                 { 5,  6,  7,  8 },
                                                 { 9, 10, 11, 12 } };
        
        int[][] fourByThreeArray = new int[][] { {  1, 2,  3 },
                                                 {  4, 5,  6 },
                                                 {  7, 8,  9 },
                                                 { 10, 11,12 } };
        assertArrayEquals(threeByFourArray, reshape(fourByThreeArray, 4));
        assertArrayEquals(fourByThreeArray, reshape(threeByFourArray, 3));
        
        assertArrayEquals(threeByFourArray, reshape(threeByFourArray, 4));
    }

    @Test(expected=IllegalArgumentException.class)
    public void testReshape_BadParameters() {
        int[][] threeByFourArray = new int[][] { { 1,  2,  3,  4 },
                                                 { 5,  6,  7,  8 },
                                                 { 9, 10, 11, 12 } };
        reshape(threeByFourArray, 5);
    }

    @Test
    public void testReshape_ZeroLength() {
        int[][] expected = new int[0][0];
        assertArrayEquals(expected, reshape(new int[0][0], 5));
        assertNotSame(expected, reshape(new int[0][0], 5));
    }

    @Test
    public void testJoin() {
        int[][] threeByFourArray = new int[][] { { 1,  2,  3,  4 },
                                                 { 5,  6,  7,  8 },
                                                 { 9, 10, 11, 12 } };
        int[][] expected = new int[][] { {  1,  2,  3,  4,  5, 1,  2,  3,  4 },
                                         {  6,  7,  8,  9, 10, 5,  6,  7,  8 }, 
                                         { 11, 12, 13, 14, 15, 9, 10, 11, 12 } };
        assertArrayEquals(expected, join(threeByFiveArray, threeByFourArray));
    }

    @Test
    public void testJoin_ZeroLength() {
        int[][] threeByFourArray = new int[][] { { 1,  2,  3,  4 },
                                                 { 5,  6,  7,  8 },
                                                 { 9, 10, 11, 12 } };
        int[][] nothing = new int[3][0];
        assertArrayEquals(threeByFourArray, join(nothing, threeByFourArray));
        assertArrayEquals(threeByFourArray, join(threeByFourArray, nothing));
        assertNotSame(threeByFourArray, join(nothing, threeByFourArray));
        assertNotSame(threeByFourArray, join(threeByFourArray, nothing));
    }

    @Test(expected=IllegalArgumentException.class)
    public void testJoin_UnequalRows() {
        int[][] threeByFourArray = new int[][] { { 1,  2,  3,  4 },
                                                 { 5,  6,  7,  8 },
                                                 { 9, 10, 11, 12 } };
        int[][] twoByTwoArray = new int[][] { { 1, 2 }, { 3, 4 } };
        join(threeByFourArray, twoByTwoArray);
    }

    @Test
    public void testToChars() {
        char[] chars = new char[] { 'H', 'e', 'l', 'l', 'o' };
        int[] ints = new int[] { 72, 101, 108, 108, 111 };
        assertArrayEquals(chars, toChars(ints));
    }

    @Test
    public void testToChars_ZeroLength() {
        char[] chars = new char[] { };
        int[] ints = new int[] { };
        assertArrayEquals(chars, toChars(ints));
    }

    @Test(expected=IllegalArgumentException.class)
    public void testToChars_InvalidCharacter1() {
        toChars(new int[] { 47, 38, 128, 90 });
    }

    @Test(expected=IllegalArgumentException.class)
    public void testToChars_InvalidCharacter2() {
        toChars(new int[] { 47, 38, -18, 90 });
    }

    @Test
    public void testToString_IntArray() {
            int[] ints = new int[] { 72, 101, 108, 108, 111 };
            assertEquals("Hello", ArrayOperations.toString(ints));
    }

    @Test(expected=IllegalArgumentException.class)
    public void testToString_InvalidCharacter1() {
        ArrayOperations.toString(new int[] { 47, 38, 128, 90 });
    }

    @Test(expected=IllegalArgumentException.class)
    public void testToString_InvalidCharacter2() {
        ArrayOperations.toString(new int[] { 47, 38, -1, 90 });
    }

    @Test
    public void testToString_ZeroLengthIntArray() {
            int[] ints = new int[0];
            assertEquals("", ArrayOperations.toString(ints));
    }

    @Test
    public void testToInts_CharArray() {
        char[] chars = new char[] { 'H', 'e', 'l', 'l', 'o' };
        int[] ints = new int[] { 72, 101, 108, 108, 111 };
        assertArrayEquals(ints, toInts(chars));
    }

    @Test
    public void testToInts_ZeroLengthCharArray() {
        char[] chars = new char[0];
        int[] ints = new int[0];
        assertArrayEquals(ints, toInts(chars));
    }

    @Test
    public void testToInts_String() {
        int[] ints = new int[] { 72, 101, 108, 108, 111 };
        assertArrayEquals(ints, toInts("Hello"));

    }

    @Test
    public void testToInts_EmptyString() {
        int[] ints = new int[0];
        assertArrayEquals(ints, toInts(""));

    }
    
//    private void assertEqualsAndShow(int[][] array1, int[][] array2) {
//        
//    }

}
