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

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.SeekableByteChannel;
import net.ranides.assira.collection.ArrayUtils;
import net.ranides.assira.collection.ByteArray;
import net.ranides.assira.text.Strings;
import org.junit.Test;
import static org.junit.Assert.*;

/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
 */
public class ChannelAdapterTest {
    
    private static final String INPUT = 
        "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F " +
        "10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F " +
        "20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F " +
        "30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F";
    
    private static final String EXPECTED = 
        "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F " +
        "71 72 73 74 61 62 63 64 65 66 67 68 1C 1D 1E 1F " +
        "91 92 93 94 95 96 97 98 99 9A 2A 2B 2C 2D 41 42 " +
        "43 44 45 46 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F";
    
    private static final char[] INPUT_LE = {
        0x0100, 0x0302, 0x0504, 0x0706, 0x0908, 0x0B0A, 0x0D0C, 0x0F0E,
        0x1110, 0x1312, 0x1514, 0x1716, 0x1918, 0x1B1A, 0x1D1C, 0x1F1E,
        0x2120, 0x2322, 0x2524, 0x2726, 0x2928, 0x2B2A, 0x2D2C, 0x2F2E,
        0x3130, 0x3332, 0x3534, 0x3736, 0x3938, 0x3B3A, 0x3D3C, 0x3F3E,
    };
        
    private static final char[] EXPECTED_LE = {
        0x0100, 0x0302, 0x0504, 0x0706, 0x0908, 0x0B0A, 0x0D0C, 0x0F0E,
        0x7271, 0x7473, 0x6261, 0x6463, 0x6665, 0x6867, 0x1D1C, 0x1F1E,
        0x9291, 0x9493, 0x9695, 0x9897, 0x9A99, 0x2B2A, 0x2D2C, 0x4241,
        0x4443, 0x4645, 0x3534, 0x3736, 0x3938, 0x3B3A, 0x3D3C, 0x3F3E,
    };
    
    private static final char[] INPUT_BE = {
        0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F,
        0x1011, 0x1213, 0x1415, 0x1617, 0x1819, 0x1A1B, 0x1C1D, 0x1E1F,
        0x2021, 0x2223, 0x2425, 0x2627, 0x2829, 0x2A2B, 0x2C2D, 0x2E2F,
        0x3031, 0x3233, 0x3435, 0x3637, 0x3839, 0x3A3B, 0x3C3D, 0x3E3F,
    };
        
    private static final char[] EXPECTED_BE = {
        0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F,
        0x7172, 0x7374, 0x6162, 0x6364, 0x6566, 0x6768, 0x1C1D, 0x1E1F,
        0x9192, 0x9394, 0x9596, 0x9798, 0x999A, 0x2A2B, 0x2C2D, 0x4142,
        0x4344, 0x4546, 0x3435, 0x3637, 0x3839, 0x3A3B, 0x3C3D, 0x3E3F,
    };

    @Test
    public void testArrayWrapper() throws IOException {
        byte[] data = NIOTester.array(INPUT);
        SeekableByteChannel channel = ChannelAdapter.wrap(data);
        NIOTester.testRWChannel(channel);
        assertEquals(EXPECTED, NIOTester.hex(data));
    }
    
    @Test
    public void testByteBufferWrapper() throws IOException {
        byte[] data = NIOTester.array(INPUT);
        ByteBuffer buffer = ByteBuffer.wrap(data);
        
        SeekableByteChannel channel = ChannelAdapter.wrap(buffer);
        NIOTester.testRWChannel(channel);
        assertEquals(EXPECTED, NIOTester.hex(data));
    }
    
    @Test
    public void testByteArrayChannel() throws IOException {
        byte[] data = NIOTester.array(INPUT);
        ByteArray array = new ByteArray(data);
        
        SeekableByteChannel channel = ChannelAdapter.wrap(array);
        NIOTester.testRWChannel(channel);
        assertEquals(EXPECTED, NIOTester.hex(data));
    }
    
    @Test
    public void testByteArrayChannel2() throws IOException {
        // we are using here ByteArray with "native" endianess - that means: LITTLE
        char[] data = ArrayUtils.arraycopy(INPUT_LE);
        ByteArray array = new ByteArray(data);
        
        SeekableByteChannel channel = ChannelAdapter.wrap(array);
        NIOTester.testRWChannel(channel);
        assertArrayEquals(EXPECTED_LE, data);
    }
    
    @Test
    public void testSequenceChannel() throws IOException {
        // we are using here endianess defined in ByteBuffers - that means: BIG
        char[] data = ArrayUtils.arraycopy(INPUT_BE);
        CharSequence sequence = Strings.asSequence(data);
        
        SeekableByteChannel channel = ChannelAdapter.wrap(sequence);
        NIOTester.testROChannel(channel);
        // it's read-only buffer, so it shouldn't change anything
        assertArrayEquals(INPUT_BE, data); 
    }
    
    @Test
    public void testSequenceChannelEndian() throws IOException {
        char[] data = {0x1112, 0x1314, 0x1516, 0x1718 };
        char[] expected = ArrayUtils.arraycopy(data);
        CharSequence sequence = Strings.asSequence(data);
        
        SeekableByteChannel channel = ChannelAdapter.wrap(sequence);
        NIOTester.testEndianReads(channel);
        assertArrayEquals(expected, data);
    }
    
    @Test
    public void testCharsChannel() throws IOException {
        // we are using here endianess defined in ByteBuffers - that means: BIG
        char[] data = ArrayUtils.arraycopy(INPUT_BE);
        
        SeekableByteChannel channel = ChannelAdapter.wrap(data);
        NIOTester.testRWChannel(channel);
        assertArrayEquals(EXPECTED_BE, data);
    }
    
    @Test
    public void testCharsChannelEndian() throws IOException {
        char[] data = { 0x1112, 0x1314, 0x1516, 0x1718, 0x2021, 0x2223 };
        
        SeekableByteChannel channel = ChannelAdapter.wrap(data);
        NIOTester.testEndianReads(channel);
        
        ByteBuffer buffer1B = NIOTester.buffer("A1 A2 A3 A4 A5 A6 A7").order(ByteOrder.BIG_ENDIAN);
        channel.position(0);
        channel.write(buffer1B);
        assertArrayEquals(new char[]{0xA1A2, 0xA3A4, 0xA5A6, 0xA718, 0x2021, 0x2223}, data);
        
        ByteBuffer buffer1L = NIOTester.buffer("B1 B2 B3 B4 B5 B6 B7").order(ByteOrder.LITTLE_ENDIAN);
        channel.position(0);
        channel.write(buffer1L);
        assertArrayEquals(new char[]{0xB2B1, 0xB4B3, 0xB6B5, 0xA7B7, 0x2021, 0x2223}, data);
        
        
        ByteBuffer buffer2B = NIOTester.buffer("C1 C2 C3 C4 C5 C6 C7").order(ByteOrder.BIG_ENDIAN);
        channel.position(1);
        channel.write(buffer2B);
        assertArrayEquals(new char[]{0xB2C1, 0xC2C3, 0xC4C5, 0xC6C7, 0x2021, 0x2223}, data);
        
        ByteBuffer buffer2L = NIOTester.buffer("D1 D2 D3 D4 D5 D6 D7").order(ByteOrder.LITTLE_ENDIAN);
        channel.position(1);
        channel.write(buffer2L);
        assertArrayEquals(new char[]{0xD1C1, 0xD3D2, 0xD5D4, 0xD7D6, 0x2021, 0x2223}, data);
        
    }
    
    
    
    
    
}
