package org.mockejb.jms;

import javax.jms.*;
import java.util.*;
import org.mockejb.MethodNotImplementedException;

/**
 * @author Dimitar Gospodinov
 */
abstract class MockConnection implements Connection {

    private String clientId;
    private boolean closed = false;
    private boolean started = false;
    private final List sessions = new ArrayList(); 

    MockConnection(String id) {
        clientId = id;
    }

    public Session createSession(boolean transacted, int acknowledgeMode) throws JMSException {
        checkClosed();
        MockSession sess = createMockSession(transacted, acknowledgeMode);
        sessions.add(sess);
        return sess;                              
    }

    /**
     * Returns client Id for this connection.
     * @see javax.jms.Connection#getClientID()
     */
    public String getClientID() throws JMSException {
        checkClosed();
        return clientId;
    }

    /**
     * @see javax.jms.Connection#setClientID(java.lang.String)
     */
    public void setClientID(String arg0) throws JMSException {
        throw new javax.jms.IllegalStateException("Client ID can not be set!");
    }

    /**
      * Returns metadata for MockEJB JMS connection.
      * @see javax.jms.Connection#getMetaData()
         */
    public ConnectionMetaData getMetaData() throws JMSException {
        checkClosed();
        return new ConnectionMetaDataImpl();
    }

    /**
     * Not implemented.
     * @see javax.jms.Connection#getExceptionListener()
     */
    public ExceptionListener getExceptionListener() throws JMSException {
        throw new MethodNotImplementedException(
            "getExceptionListener",
            "QueueConnectionImpl");
    }

    /**
     * Not implemented.
     * @see javax.jms.Connection#setExceptionListener(javax.jms.ExceptionListener)
     */
    public void setExceptionListener(ExceptionListener listener)
        throws JMSException {

        throw new MethodNotImplementedException(
            "setExceptionListener",
            "QueueConnectionImpl");
    }

    /**
     * Does nothing.
     * @see javax.jms.Connection#close()
     */
    public void close() throws JMSException {
        if (closed) {
            return;
        }
        stop();
        ListIterator it = sessions.listIterator();
        while (it.hasNext()) {
            Session s = (Session)it.next();
            s.close();
            it.remove();
        }
        closed = true;
    }

    /**
     * Not implemented.
     * @see javax.jms.Connection#start()
     */
    public void start() throws JMSException {
        checkClosed();
        started = true;
        // "Asynchronously" deliver any messages received while the connection was stopped.
        // This will simply invoke MessageListeners if any.
        Iterator it = sessions.iterator();
        while (it.hasNext()) {
            MockSession sess = (MockSession)it.next();
            sess.consumeMessages();
        }
    }

    /**
     * Not implemented.
     * @see javax.jms.Connection#stop()
     */
    public void stop() throws JMSException {
        checkClosed();
        started = false;
    }

    public ConnectionConsumer createConnectionConsumer(
        Destination destination,
        java.lang.String messageSelector,
        ServerSessionPool sessionPool,
        int maxMessages)
        throws JMSException {

        throw new MethodNotImplementedException("createConnectionConsumer", "MockConnection");

    }

    public ConnectionConsumer createDurableConnectionConsumer(
        Topic topic,
        java.lang.String subscriptionName,
        java.lang.String messageSelector,
        ServerSessionPool sessionPool,
        int maxMessages)
        throws JMSException {

        throw new MethodNotImplementedException("createDurableConnectionConsumer", "MockConnection");
    }


    // Non-standard methods

    void checkClosed() throws javax.jms.IllegalStateException {
        if (closed) {
            throw new javax.jms.IllegalStateException("Unable to perform operation on closed connection!");
        }
    }

    abstract MockSession createMockSession(boolean transacted, int acknowledgeMode);

    boolean isStarted() {
        return started;
    }

}