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

import java.util.Enumeration;

import javax.jms.IllegalStateException;
import javax.jms.JMSException;
import javax.jms.Queue;
import javax.jms.QueueBrowser;

import org.activemq.message.ActiveMQQueue;

/**
 * A client uses a <CODE>QueueBrowser</CODE> object to look at messages on a
 * queue without removing them.
 * <p/>
 * <P>
 * The <CODE>getEnumeration</CODE> method returns a <CODE>
 * java.util.Enumeration</CODE> that is used to scan the queue's messages. It
 * may be an enumeration of the entire content of a queue, or it may contain
 * only the messages matching a message selector.
 * <p/>
 * <P>
 * Messages may be arriving and expiring while the scan is done. The JMS API
 * does not require the content of an enumeration to be a static snapshot of
 * queue content. Whether these changes are visible or not depends on the JMS
 * provider.
 * <p/>
 * <P>
 * A <CODE>QueueBrowser</CODE> can be created from either a <CODE>Session
 * </CODE> or a <CODE>QueueSession</CODE>.
 *
 * @see javax.jms.Session#createBrowser
 * @see javax.jms.QueueSession#createBrowser
 * @see javax.jms.QueueBrowser
 * @see javax.jms.QueueReceiver
 */

public class ActiveMQQueueBrowser implements
        QueueBrowser, Enumeration {

    private final ActiveMQSession session;
    private final ActiveMQQueue destination;
    private final String selector;
    private final int cnum;
    
    private ActiveMQMessageConsumer consumer;
    private boolean closed;
    
    /**
     * Constructor for an ActiveMQQueueBrowser - used internally
     *
     * @param theSession
     * @param dest
     * @param selector
     * @param cnum
     * @throws JMSException
     */
    protected ActiveMQQueueBrowser(ActiveMQSession session, ActiveMQQueue destination, String selector, int cnum) throws JMSException {
        this.session = session;
        this.destination = destination;
        this.selector = selector;
        this.cnum = cnum;        
        consumer = createConsumer();
    }

    /**
     * @param session
     * @param destination
     * @param selector
     * @param cnum
     * @return
     * @throws JMSException
     */
    private ActiveMQMessageConsumer createConsumer() throws JMSException {
        return new ActiveMQMessageConsumer(session, destination, "", selector, cnum, session.connection.getPrefetchPolicy().getQueueBrowserPrefetch(), false, true);
    }
    
    private void destroyConsumer() {
        if( consumer == null )
            return;
        
        try {
            consumer.close();
            consumer=null;
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }

    /**
     * Gets an enumeration for browsing the current queue messages in the order
     * they would be received.
     *
     * @return an enumeration for browsing the messages
     * @throws JMSException if the JMS provider fails to get the enumeration for this
     *                      browser due to some internal error.
     */

    public Enumeration getEnumeration() throws JMSException {
        checkClosed();
        
        if( consumer==null )
            consumer = createConsumer();
        
        //ok - started browsing - wait for inbound messages
        if (consumer.messageQueue.size() == 0) {
            try {
                Thread.sleep(1000);
            }
            catch (InterruptedException e) {
            }
        }
        return this;
    }

    private void checkClosed() throws IllegalStateException {
        if (closed) {
            throw new IllegalStateException("The Consumer is closed");
        }
    }

    /**
     * @return true if more messages to process
     */
    public boolean hasMoreElements() {
        if( consumer==null )
            return false;
        
        boolean rc = consumer.messageQueue.size() > 0;
        if( !rc ) {
            destroyConsumer();
        }
        return rc;
    }


    /**
     * @return the next message
     */
    public Object nextElement() {
        if( consumer == null )
            return null;
        
        Object answer = null;
        try {
            answer = consumer.receiveNoWait();
            if( answer==null ) {
                destroyConsumer();
            }
        }
        catch (JMSException e) {
            e.printStackTrace();
        }
        return answer;
    }
    
    public void close() throws JMSException {
        destroyConsumer();
        closed=true;
    }

    /**
     * Gets the queue associated with this queue browser.
     *
     * @return the queue
     * @throws JMSException if the JMS provider fails to get the queue associated
     *                      with this browser due to some internal error.
     */

    public Queue getQueue() throws JMSException {
        return destination;
    }


    public String getMessageSelector() throws JMSException {
        return selector;
    }


}
