/**
 * 
 * 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.test;

import javax.jms.JMSException;

import junit.framework.TestCase;

import org.activemq.message.ActiveMQMessage;
import org.activemq.message.ActiveMQTextMessage;
import org.activemq.message.MessageAck;
import org.activemq.service.MessageContainer;
import org.activemq.service.MessageIdentity;
import org.activemq.service.impl.DurableQueueMessageContainer;
import org.activemq.service.impl.DurableTopicMessageContainer;
import org.activemq.store.PersistenceAdapter;
import org.activemq.util.Callback;
import org.activemq.util.IdGenerator;
import org.activemq.util.TransactionTemplate;

/**
 * @version $Revision: 1.1.1.1 $
 */
public abstract class MessageContainerTestSupport extends TestCase {
    protected MessageContainer container;
    protected int messageCount = 50;
    protected IdGenerator idGenerator = new IdGenerator();
    protected String[] messageIds;
    protected MessageIdentity[] messageIdenties;
    private String[] messageTexts;
    protected PersistenceAdapter persistenceAdapter;
    protected boolean topic = false;
    private String destinationName;
    protected TransactionTemplate transactionTemplate;

    public void testWriteLoop() throws Exception {
        transactionTemplate.run(new Callback() {
            public void execute() throws Throwable {
                writeMessage(0);

                // lets delete using a String which should cause a warning
                MessageIdentity messageIdentity = new MessageIdentity(messageIds[0]);
                container.delete(messageIdentity, createMessageAck(messageIdentity));
            }
        });

        System.out.println("About to write: " + messageCount + " messages to the container: " + container);

        transactionTemplate.run(new Callback() {
            public void execute() throws Throwable {
                for (int i = 0; i < messageCount; i++) {
                    writeMessage(i + 1);
                }
            }
        });


        System.out.println("About to read: " + messageCount + " messages");

        transactionTemplate.run(new Callback() {
            public void execute() throws Throwable {
                for (int i = 0; i < messageCount; i++) {
                    readMessage(i + 1);
                }
            }
        });

        System.out.println("About to delete: " + messageCount + " messages");

        transactionTemplate.run(new Callback() {
            public void execute() throws Throwable {
                for (int i = 0; i < messageCount; i++) {
                    deleteMessage(i + 1);
                }
            }
        });

        if (!topic) {
            System.out.println("About to check that all the messages are consumed");
            transactionTemplate.run(new Callback() {
                public void execute() throws Throwable {
                    for (int i = 0; i < messageCount; i++) {
                        assertNoMessage(i + 1);
                    }
                }
            });
        }
    }

    // Implementation methods
    //-------------------------------------------------------------------------
    public String getDestinationName() {
        if (destinationName == null) {
            destinationName = getClass().getName() + "." + getName();
        }
        return destinationName;
    }

    public void setDestinationName(String destinationName) {
        this.destinationName = destinationName;
    }

    protected long startUnitOfWork() throws Exception {
        return System.currentTimeMillis();
    }

    protected long endUnitOfWork() throws Exception {
        return System.currentTimeMillis();
    }

    protected void setUp() throws Exception {
        super.setUp();
        String value = System.getProperty("messageCount");
        if (value != null) {
            messageCount = Integer.parseInt(value);
        }
        messageIds = new String[messageCount + 1];
        messageTexts = new String[messageCount + 1];
        messageIdenties = new MessageIdentity[messageCount + 1];
        persistenceAdapter = createPersistenceAdapter();
        persistenceAdapter.start();

        transactionTemplate = new TimedTransactionTemplate(persistenceAdapter, messageCount);

        container = createContainer();
        assertTrue("Should have created a container: " + container != null);
        container.start();
    }

    protected void tearDown() throws Exception {
        super.tearDown();

        if (container != null) {
            container.stop();
        }

        persistenceAdapter.stop();
    }

    protected MessageContainer createContainer() throws JMSException {
        if (topic) {
            return new DurableTopicMessageContainer(persistenceAdapter.createTopicMessageStore(getDestinationName()), getDestinationName());
        }
        else {
            return new DurableQueueMessageContainer(persistenceAdapter, persistenceAdapter.createQueueMessageStore(getDestinationName()), getDestinationName());
        }
    }

    protected PersistenceAdapter createPersistenceAdapter() throws Exception {
        assertTrue("Must overload this method to create a PersistenceAdapater", false);
        return null;
    }


    protected void writeMessage(int i) throws JMSException {
        ActiveMQMessage message = createMessage(i);
        String id = idGenerator.generateId();
        messageIds[i] = id;
        message.setJMSMessageID(id);
        container.addMessage(message);
        messageIdenties[i] = message.getJMSMessageIdentity();
    }

    protected void readMessage(int i) throws JMSException {
        ActiveMQTextMessage message = (ActiveMQTextMessage) container.getMessage(messageIdenties[i]);
        assertTrue("Message should not be null", message != null);

        String text = message.getText();
        assertEquals("Message text should be equal", messageTexts[i], text);
        assertEquals(messageIds[i], message.getJMSMessageID());
    }

    protected MessageAck createMessageAck(MessageIdentity messageIdentity) {
        MessageAck answer = new MessageAck();
        answer.setConsumerId(idGenerator.generateId());
        answer.setMessageID(messageIdentity.getMessageID());
        answer.setMessageRead(true);
        return answer;
    }

    protected void deleteMessage(int i) throws JMSException {
        container.delete(messageIdenties[i], createMessageAck(messageIdenties[i]));
    }

    protected void assertNoMessage(int i) throws JMSException {
        ActiveMQMessage message = container.getMessage(messageIdenties[i]);
        assertTrue("Message should be null", message == null);
    }

    protected ActiveMQMessage createMessage(int i) throws JMSException {
        ActiveMQTextMessage answer = new ActiveMQTextMessage();
        String text = "Message: " + i;
        messageTexts[i] = text;
        answer.setText(text);
        return answer;
    }
}
