/** 
 * 
 * Copyright 2004 Hiram Chirino
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 * 
 **/
package org.codehaus.activemq.journal.impl;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;

import junit.framework.TestCase;

/**
 * Tests the data structures used JournalImpl
 * 
 * @version $Revision: 1.1 $
 */
public class DataStruturesTest extends TestCase {
    
    public void testMarkSerialization() throws IOException {
        doTestSerialization(Integer.MIN_VALUE,Long.MIN_VALUE);        
        doTestSerialization(Integer.MAX_VALUE,Long.MAX_VALUE);        
        doTestSerialization(0,0);        
        doTestSerialization(-1,1);        
    }
    
    public void doTestSerialization(int value1, long value2) throws IOException {
        Mark mark = new Mark();
        mark.offsetId = value1;
        mark.sequenceId = value2;
        
        byte[] data = mark.writeExternal();
        assertNotNull(data);
        
        Mark mark2 = new Mark();
        mark2.readExternal(data);
        assertEquals(mark.offsetId, mark2.offsetId);
        assertEquals(mark.sequenceId, mark2.sequenceId);
        
        assertEquals(data.length, Mark.MARK_RECORD_SIZE);
    }
    
    public void testRecordHeaderSerialization() throws IOException {
        doTestRecordHeader(Integer.MIN_VALUE,Long.MIN_VALUE,Byte.MIN_VALUE);        
        doTestRecordHeader(Integer.MAX_VALUE,Long.MAX_VALUE,Byte.MAX_VALUE);        
    }

    public void doTestRecordHeader(int value1, long value2, byte value3) throws IOException {
        RecordHeader header = new RecordHeader();
        header.length = value1;
        header.sequenceId = value2;
        header.recordType = value3;
        
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(os);
        header.writeRecordHeader(dos);        
        byte[] data = os.toByteArray();
        assertNotNull(data);
        
        RecordHeader header2 = new RecordHeader();
        DataInputStream is = new DataInputStream(new ByteArrayInputStream(data));
        header2.readRecordHeader(is);
        
        assertEquals(header.length, header2.length);
        assertEquals(header.sequenceId, header2.sequenceId);
        assertEquals(header.recordType, header2.recordType);
        assertEquals(data.length, RecordHeader.RECORD_HEADER_SIZE);
        
        // Validate that the toByteBuffer serializes correctly.
        ByteBuffer buffer = header.toByteBuffer();
        data = buffer.array();
        assertNotNull(data);
        
        header2 = new RecordHeader();
        is = new DataInputStream(new ByteArrayInputStream(data));
        header2.readRecordHeader(is);
        
        assertEquals(header.length, header2.length);
        assertEquals(header.sequenceId, header2.sequenceId);
        assertEquals(header.recordType, header2.recordType);
        assertEquals(data.length, RecordHeader.RECORD_HEADER_SIZE);
        
    }
    public void testRecordFooterSerialization() throws IOException {
        doTestRecordFooter(Long.MIN_VALUE,Long.MIN_VALUE);        
        doTestRecordFooter(Long.MAX_VALUE,Long.MAX_VALUE);        
    }

    public void doTestRecordFooter(long value1, long value2) throws IOException {
        RecordFooter footer = new RecordFooter();
        footer.sequenceId = value1;
        footer.checksum=value2;
        
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(os);
        footer.writeRecordFooter(dos);        
        byte[] data = os.toByteArray();
        assertNotNull(data);
        
        RecordFooter footer2 = new RecordFooter();
        DataInputStream is = new DataInputStream(new ByteArrayInputStream(data));
        footer2.readRecordFooter(is);
        
        assertEquals(footer.checksum, footer2.checksum);
        assertEquals(footer.sequenceId, footer2.sequenceId);
        assertEquals(data.length, RecordFooter.RECORD_FOOTER_SIZE);
        
        // Validate that the toByteBuffer serializes correctly.
        ByteBuffer buffer = footer.toByteBuffer();
        data = buffer.array();
        assertNotNull(data);
        
        footer2 = new RecordFooter();
        is = new DataInputStream(new ByteArrayInputStream(data));
        footer2.readRecordFooter(is);
        
        assertEquals(footer.checksum, footer2.checksum);
        assertEquals(footer.sequenceId, footer2.sequenceId);
        assertEquals(data.length, RecordFooter.RECORD_FOOTER_SIZE);        
    }

    public void testRecordLocationImplComparison() throws IOException {
        RecordLocationImpl l1 = new RecordLocationImpl((byte)0,(byte)0,0, 1L); 
        RecordLocationImpl l2 = new RecordLocationImpl((byte)0,(byte)0,0, 2L);
        RecordLocationImpl l3 = new RecordLocationImpl((byte)0,(byte)0,0, 3L);

        assertTrue( l1.compareTo(l2)<0 );
        
        // Sort them using a list.  Put them in the wrong order.
        ArrayList l = new ArrayList();
        l.add(l2);
        l.add(l3);
        l.add(l1);        
        Collections.sort(l);
        
        // Did they get sorted to the correct order?
        assertSame( l.get(0), l1 );
        assertSame( l.get(1), l2 );
        assertSame( l.get(2), l3 );
    }
}
