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

import java.io.EOFException;
import java.io.IOException;
import java.io.UTFDataFormatException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import net.ranides.assira.text.Charsets;
import org.junit.Test;
import static net.ranides.assira.junit.NewAssert.*;

/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
 */
public class DataBufferTest {
    
    private static byte[] DATA = new byte[]{
        44, 104, 101, 108, 108, 111, 1, 0, -12, 35, 69, -9, 1, 0, 81, 51, 68, 85, -86, 16, 32, 48, 
        64, 17, 18, 19, 20, 64, 72, -11, -61, 64, 5, -68, 1, -93, 110, 46, -78, 17, 18, 19, 20, 119, 
        111, 114, 108, 100, 1, 122, 0, 114, 0, 101, 0, 98, 0, 105, 1, 25, 0, 32, 0, 110, 0, 97, 0, 
        32, 1, 66, 1, 5, 0, 99, 0, 101, 0, 32, 0, 27, 112, 97, 116, 114, 122, 121, 32, 110, 97, 32, 
        115, -59, -126, 111, -59, -124, 99, 101, 32, 103, 111, 114, -60, -123, 99, 101, 46, 66
    };
    
    @Test
    public void testWrite() throws IOException {
        String text = "Quick brown\nfox jumps\nover lazy\ndog\n";
        
        DataBuffer db1 = new DataBuffer();
        
        db1.write(text.getBytes(Charsets.US_ASCII));
        db1.write(text.getBytes(Charsets.US_ASCII));
        db1.write(text.getBytes(Charsets.US_ASCII));
        
        byte[] exp = (text+text+text).getBytes(Charsets.US_ASCII);
        byte[] buf = new byte[exp.length];
        db1.seek(0);
        db1.readFully(buf);
        assertArrayEquals(exp, buf);
    }
    
    @Test
    public void testReadLine() throws IOException {
        DataBuffer db1 = new DataBuffer();
        db1.write("Quick brown\nfox jumps\nover lazy\ndog\n".getBytes(Charsets.US_ASCII));
        db1.seek(0);

        assertEquals("Quick brown", db1.readLine());
        assertEquals("fox jumps", db1.readLine());
        assertEquals("over lazy", db1.readLine());
        assertEquals("dog", db1.readLine());
        assertEquals(null, db1.readLine());
        
        DataBuffer db2 = new DataBuffer();
        db2.write("Quick brown\nfox jumps\nover lazy\ndog".getBytes(Charsets.US_ASCII));
        db2.seek(0);
        assertEquals("Quick brown", db2.readLine());
        assertEquals("fox jumps", db2.readLine());
        assertEquals("over lazy", db2.readLine());
        assertEquals("dog", db2.readLine());
        assertEquals(null, db2.readLine());
        
        DataBuffer db3 = new DataBuffer();
        db3.write("Quick brown\rfox jumps\r\nover lazy\n\rdog\r!".getBytes(Charsets.US_ASCII));
        db3.seek(0);
        assertEquals("Quick brown", db3.readLine());
        assertEquals("fox jumps", db3.readLine());
        assertEquals("over lazy", db3.readLine());
        assertEquals("", db3.readLine());
        assertEquals("dog", db3.readLine());
        assertEquals("!", db3.readLine());
        assertEquals(null, db3.readLine());
    }

    @Test
    public void testReadLineCS() throws IOException {
        DataBuffer db1 = new DataBuffer();
        db1.write("Pchnąć w tę\nłódź jeża\nlub ośm\nskrzyń fig\n".getBytes(Charsets.UTF8));
        db1.seek(0);

        assertEquals("Pchnąć w tę", db1.readLine(Charsets.UTF8));
        assertEquals("łódź jeża", db1.readLine(Charsets.UTF8));
        assertEquals("lub ośm", db1.readLine(Charsets.UTF8));
        assertEquals("skrzyń fig", db1.readLine(Charsets.UTF8));
        assertEquals(null, db1.readLine(Charsets.UTF8));
        
        DataBuffer db2 = new DataBuffer();
        db2.write("Pchnąć w tę\nłódź jeża\nlub ośm\nskrzyń fig".getBytes(Charsets.UTF8));
        db2.seek(0);
        assertEquals("Pchnąć w tę", db2.readLine(Charsets.UTF8));
        assertEquals("łódź jeża", db2.readLine(Charsets.UTF8));
        assertEquals("lub ośm", db2.readLine(Charsets.UTF8));
        assertEquals("skrzyń fig", db2.readLine(Charsets.UTF8));
        assertEquals(null, db2.readLine(Charsets.UTF8));
        
        DataBuffer db3 = new DataBuffer();
        db3.write("Pchnąć w tę\rłódź jeża\r\nlub ośm\n\rskrzyń fig\r!".getBytes(Charsets.UTF8));
        db3.seek(0);
        assertEquals("Pchnąć w tę", db3.readLine(Charsets.UTF8));
        assertEquals("łódź jeża", db3.readLine(Charsets.UTF8));
        assertEquals("lub ośm", db3.readLine(Charsets.UTF8));
        assertEquals("", db3.readLine(Charsets.UTF8));
        assertEquals("skrzyń fig", db3.readLine(Charsets.UTF8));
        assertEquals("!", db3.readLine(Charsets.UTF8));
        assertEquals(null, db3.readLine(Charsets.UTF8));
    }
    
    @Test
    public void testWriteTypes() throws IOException {
        DataBuffer dbo = new DataBuffer();
        
        dbo.write(44);
        dbo.write("hello".getBytes(Charsets.US_ASCII));
        dbo.writeBoolean(true);
        dbo.writeBoolean(false);
        dbo.writeByte(0xF4);
        dbo.writeShort(0x2345);
        dbo.writeShort(0xF701);
        dbo.writeChar('Q');
        dbo.writeInt(0x334455AA);
        dbo.writeLong(0x1020304011121314L);
        dbo.writeFloat(3.14f);
        dbo.writeDouble(2.7168);
        
        dbo.writeBuffer(ByteBuffer.wrap(new byte[]{17,18,19,20}));
        dbo.writeBytes("world");
        dbo.writeChars("źrebię na łące ");
        dbo.writeUTF("patrzy na słońce gorące.");
        
        assertThrows(UTFDataFormatException.class, ()->{
            dbo.writeUTF(new String(new char[67000]));
        });
        
        dbo.writeByte(66);
        assertArrayEquals(DATA, dbo.bytes());
        
        ByteBuffer out = dbo.data();
        assertEquals(DATA.length, out.limit());
        assertEquals(0, out.arrayOffset());
        
        byte[] content = new byte[DATA.length];
        out.get(content);
        assertArrayEquals(DATA, content);
        
        assertArrayEquals(DATA, BufferAdapter.toArray(dbo.data()));
        
        
    }
        
    @Test
    public void testReadTypes() throws IOException {
        DataBuffer dbi = new DataBuffer();
        dbi.write(DATA);
        dbi.seek(0);
        
        assertEquals(44, dbi.readByte());
        
        byte[] v1 = new byte[5];
        dbi.readFully(v1);
        assertEquals("hello", new String(v1, Charsets.US_ASCII));
        assertEquals(true, dbi.readBoolean());
        assertEquals(false, dbi.readBoolean());
        assertEquals(0xF4, dbi.readUnsignedByte());
        
        assertEquals(0x2345, dbi.readShort());
        assertEquals(0xF701, dbi.readUnsignedShort());
        assertEquals('Q', dbi.readChar());
        assertEquals(0x334455AA, dbi.readInt());
        assertEquals(0x1020304011121314L, dbi.readLong());
        assertEquals(3.14f, dbi.readFloat(), 1e-5f);
        assertEquals(2.7168f, dbi.readDouble(), 1e-5);
        
        ByteBuffer v4 = ByteBuffer.allocate(4);
        dbi.readBuffer(v4);
        
        byte[] v2 = new byte[5];
        dbi.readFully(v2);
        assertEquals("world", new String(v2, Charsets.US_ASCII));
        
        char[] exp3 = "źrebię na łące ".toCharArray();
        char[] v3 = new char[exp3.length];
        dbi.readChars(v3);
        assertArrayEquals(exp3, v3);
        
        assertEquals("patrzy na słońce gorące.", dbi.readUTF());
        assertEquals(66, dbi.readByte());
        
        assertThrows(EOFException.class, ()->{
            dbi.readLong();
        });
        assertThrows(EOFException.class, ()->{
            dbi.readInt();
        });
    }
    
    @Test
    public void testSeek() throws IOException {
        DataBuffer dbo = new DataBuffer();
        
        dbo.writeBytes("hello world");
        dbo.seek(3);
        assertArrayEquals(new byte[]{104,101,108}, dbo.bytes());
        
        assertThrows(IOException.class, ()->{
            dbo.seek(-2);
        });
        assertThrows(IOException.class, ()->{
            dbo.seek(100);
        });
        
        dbo.seek(4);
        assertEquals('o', dbo.readByte());
        
        assertEquals(3, dbo.skipBytes(3));
        assertEquals('r', dbo.readByte());
        
        assertThrows(IOException.class, ()->{
            dbo.skipBytes(-20);
        });
        
        assertEquals(-3, dbo.skipBytes(-3));
        assertEquals('w', dbo.readByte());
        
        assertEquals(120, dbo.skipBytes(120));
    }
    
}
