/** 
 * 
 * Copyright 2004 Protique Ltd
 * 
 * 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.activemq.service;

import junit.framework.TestCase;

import javax.jms.JMSException;

/**
 * @version $Revision: 1.1.1.1 $
 */
public abstract class QueueListTestSupport extends TestCase {
    protected QueueList list;

    public void testAddFirst() throws Exception {
        beginTransaction();

        list.clear();
        assertTrue(list.isEmpty());

        list.addFirst("D");
        list.addFirst("C");
        list.add(0, "B");
        list.add(0, "A");

        assertListEquals(list, new Object[]{"A", "B", "C", "D"});

        QueueListEntry entry = list.getFirstEntry();
        assertEquals("A", entry.getElement());
        entry = list.getNextEntry(entry);
        assertEquals("B", entry.getElement());
        entry = list.getNextEntry(entry);
        assertEquals("C", entry.getElement());
        entry = list.getNextEntry(entry);
        assertEquals("D", entry.getElement());
        entry = list.getNextEntry(entry);
        assertEquals(null, entry);

        entry = list.getLastEntry();
        assertEquals("D", entry.getElement());
        entry = list.getPrevEntry(entry);
        assertEquals("C", entry.getElement());
        entry = list.getPrevEntry(entry);
        assertEquals("B", entry.getElement());
        entry = list.getPrevEntry(entry);
        assertEquals("A", entry.getElement());
        entry = list.getPrevEntry(entry);
        assertEquals(null, entry);

        list.set(0, "X");
        list.set(1, "Y");
        list.set(2, "Z");
        list.set(3, "!");
        assertListEquals(list, new Object[]{"X", "Y", "Z", "!"});

        list.clear();
        assertTrue("List should now be empty", list.isEmpty());

        commitTransaction();
    }


    public void testAddAndAddLast() throws Exception {
        beginTransaction();

        list.clear();
        assertTrue(list.isEmpty());

        list.add("A");
        list.add("B");
        list.addLast("C");
        list.addLast("D");

        assertListEquals(list, new Object[]{"A", "B", "C", "D"});

        QueueListEntry entry = list.getFirstEntry();
        assertEquals("A", entry.getElement());
        entry = list.getNextEntry(entry);
        assertEquals("B", entry.getElement());
        entry = list.getNextEntry(entry);
        assertEquals("C", entry.getElement());
        entry = list.getNextEntry(entry);
        assertEquals("D", entry.getElement());
        entry = list.getNextEntry(entry);
        assertEquals(null, entry);

        entry = list.getLastEntry();
        assertEquals("D", entry.getElement());
        entry = list.getPrevEntry(entry);
        assertEquals("C", entry.getElement());
        entry = list.getPrevEntry(entry);
        assertEquals("B", entry.getElement());
        entry = list.getPrevEntry(entry);
        assertEquals("A", entry.getElement());
        entry = list.getPrevEntry(entry);
        assertEquals(null, entry);

        list.clear();
        assertTrue("List should now be empty", list.isEmpty());

        commitTransaction();
    }

    public void testAddAtFrontBackAndMiddle() throws Exception {
        beginTransaction();

        list.clear();
        assertTrue(list.isEmpty());

        list.add("A");
        list.add("B");
        list.addFirst("C");
        list.addLast("D");
        list.add(1, "E");
        list.add(5, "F");

        assertListEquals(list, new Object[]{"C", "E", "A", "B", "D", "F"});

        assertEquals("C", list.getFirst());
        assertEquals("F", list.getLast());

        QueueListEntry entry = list.getLastEntry();
        assertEquals("F", entry.getElement());
        entry = list.getPrevEntry(entry);
        assertEquals("D", entry.getElement());
        entry = list.getPrevEntry(entry);
        assertEquals("B", entry.getElement());
        entry = list.getPrevEntry(entry);
        assertEquals("A", entry.getElement());
        entry = list.getPrevEntry(entry);
        assertEquals("E", entry.getElement());
        entry = list.getPrevEntry(entry);
        assertEquals("C", entry.getElement());
        entry = list.getPrevEntry(entry);
        assertEquals(null, entry);


        entry = list.getFirstEntry();
        assertEquals("C", entry.getElement());
        entry = list.getNextEntry(entry);
        assertEquals("E", entry.getElement());
        entry = list.getNextEntry(entry);
        assertEquals("A", entry.getElement());
        entry = list.getNextEntry(entry);
        assertEquals("B", entry.getElement());
        entry = list.getNextEntry(entry);
        assertEquals("D", entry.getElement());
        entry = list.getNextEntry(entry);
        assertEquals("F", entry.getElement());
        entry = list.getNextEntry(entry);
        assertEquals(null, entry);

        assertTrue(list.contains("C"));
        assertTrue(list.contains("F"));
        assertTrue(list.contains("B"));
        assertTrue(!list.contains("Z"));

        assertTrue(!list.isEmpty());
        assertEquals(6, list.size());

        list.removeFirst();
        assertEquals("E", list.getFirst());
        list.removeLast();
        assertEquals("D", list.getLast());

        list.clear();
        assertTrue("List should now be empty", list.isEmpty());

        commitTransaction();
    }

    public void testEmptyList() throws Exception {
        beginTransaction();

        list.clear();
        assertTrue(list.isEmpty());
        assertEquals(0, list.size());

        assertEquals(null, list.getFirst());
        assertEquals(null, list.getLast());
        assertEquals(-1, list.indexOf("foo"));
        assertEquals(-1, list.lastIndexOf("foo"));

        commitTransaction();
    }

    public void testIndexOf() throws Exception {
        beginTransaction();

        list.clear();

        list.add("A");
        list.add("B");
        list.add("C");
        list.add("B");
        list.add("D");

        assertListEquals(list, new Object[]{"A", "B", "C", "B", "D"});

        assertEquals(0, list.indexOf("A"));
        assertEquals(1, list.indexOf("B"));
        assertEquals(2, list.indexOf("C"));
        assertEquals(4, list.indexOf("D"));
        assertEquals(-1, list.indexOf("cheese"));

        assertEquals(0, list.lastIndexOf("A"));
        assertEquals(3, list.lastIndexOf("B"));
        assertEquals(2, list.lastIndexOf("C"));
        assertEquals(4, list.lastIndexOf("D"));
        assertEquals(-1, list.lastIndexOf("cheese"));

        commitTransaction();
    }

    protected void beginTransaction() throws JMSException {
    }

    protected void commitTransaction() throws JMSException {
    }

    protected void setUp() throws Exception {
        super.setUp();
        list = createQueueList();
    }

    protected abstract QueueList createQueueList() throws JMSException;

    protected void assertListEquals(QueueList list, Object[] expected) throws JMSException {
        assertArrayEquals(expected, list.toArray());

        for (int i = 0; i < expected.length; i++) {
            Object expectedValue = expected[i];
            Object value = list.get(i);
            assertEquals("get(int) at index: " + i, expectedValue, value);
        }

        QueueListEntry entry = list.getFirstEntry();
        for (int i = 0; i < expected.length; i++) {
            //System.out.println("Entry: " + entry);
            Object expectedValue = expected[i];
            assertTrue("Should have an entry for index: " + i, entry != null);
            assertEquals("element for entry at index: " + i, expectedValue, entry.getElement());
            entry = list.getNextEntry(entry);
        }
        assertTrue("entry should now be null", entry == null);

        entry = list.getLastEntry();
        for (int i = expected.length - 1; i >= 0; i--) {
            Object expectedValue = expected[i];
            assertTrue("Should have an entry for index: " + i, entry != null);
            assertEquals("element for entry at index: " + i, expectedValue, entry.getElement());
            entry = list.getPrevEntry(entry);
        }
        assertTrue("entry should now be null", entry == null);

        if (expected.length > 0) {
            assertEquals("first value", expected[0], list.getFirst());
            assertEquals("last value", expected[expected.length - 1], list.getLast());
            assertTrue("Should not be empty!", !list.isEmpty());
        }
        else {
            assertTrue("Should be empty!", list.isEmpty());
        }
    }

    protected void assertArrayEquals(Object[] expected, Object[] objects) {
        String expectedText = asText(expected);
        String valueText = asText(objects);
        assertEquals("Sizes wrong. Expected: " + expectedText + " was: " + valueText, expected.length, objects.length);
        for (int i = 0; i < expected.length; i++) {
            Object expectedValue = expected[i];
            Object value = objects[i];
            assertEquals("Value at index: " + i + ". Expected: " + expectedText + " was: " + valueText, expectedValue, value);
        }
    }

    protected String asText(Object[] objects) {
        StringBuffer buffer = new StringBuffer("[ ");
        for (int i = 0; i < objects.length; i++) {
            if (i > 0) {
                buffer.append(", ");
            }
            buffer.append(objects[i]);
        }
        buffer.append(" ]");
        return buffer.toString();
    }
}
