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

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.activemq.broker.BrokerContainer;
import org.activemq.service.Service;
import org.activemq.ActiveMQPrefetchPolicy;
import EDU.oswego.cs.dl.util.concurrent.BoundedBuffer;
import EDU.oswego.cs.dl.util.concurrent.Executor;
import EDU.oswego.cs.dl.util.concurrent.PooledExecutor;

import javax.jms.JMSException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * Represents a connector to one or more remote brokers.
 * This class manages a number of {@link NetworkChannel} instances
 * which may or may not be connected to a
 * remote broker at any point in time.
 * <p/>
 * The implementation of this class could use a fixed number of
 * configured {@link NetworkChannel} instances or could use
 * discovery to find them.
 *
 * @version $Revision: 1.1.1.1 $
 */
public class NetworkConnector implements Service {
    private static final Log log = LogFactory.getLog(NetworkConnector.class);

    private BrokerContainer brokerContainer;
    private TransportChannelListener transportChannelListener;
    private List networkChannels = new ArrayList();
    private Map localDetails = new HashMap();
    private String remoteUserName;
    private String remotePassword;
    protected PooledExecutor threadPool;
    private ActiveMQPrefetchPolicy localPrefetchPolicy = new ActiveMQPrefetchPolicy();
    private ActiveMQPrefetchPolicy remotePrefetchPolicy = new ActiveMQPrefetchPolicy();


    public NetworkConnector(BrokerContainer brokerContainer) {
        this.brokerContainer = brokerContainer;
        this.threadPool = new PooledExecutor();
    }

    public void start() throws JMSException {
        for (Iterator iter = networkChannels.iterator(); iter.hasNext();) {
            NetworkChannel networkChannel = (NetworkChannel) iter.next();
            networkChannel.setBrokerContainer(getBrokerContainer());
            networkChannel.setThreadPool(threadPool);
            networkChannel.start();
        }
    }

    public void stop() throws JMSException {
        for (Iterator iter = networkChannels.iterator(); iter.hasNext();) {
            NetworkChannel networkChannel = (NetworkChannel) iter.next();
            try {
                networkChannel.stop();
            }
            catch (JMSException e) {
                log.warn("Failed to stop network channel: " + e, e);
            }
        }
    }

    public void setTransportChannelListener(TransportChannelListener listener) {
        this.transportChannelListener = listener;
    }
    
    


    // Properties
    //-------------------------------------------------------------------------
    
    public BrokerContainer getBrokerContainer() {
        return brokerContainer;
    }
    

    /**
     * @return Returns the threadPool.
     */
    public PooledExecutor getThreadPool() {
        return threadPool;
    }
   

    public List getNetworkChannels() {
        return networkChannels;
    }
    
    public Map getLocalDetails() {
        return localDetails;
    }

    public void setLocalDetails(Map localDetails) {
        this.localDetails = localDetails;
    }

    public String getRemotePassword() {
        return remotePassword;
    }

    public void setRemotePassword(String remotePassword) {
        this.remotePassword = remotePassword;
    }

    public String getRemoteUserName() {
        return remoteUserName;
    }

    public void setRemoteUserName(String remoteUserName) {
        this.remoteUserName = remoteUserName;
    }


    /**
     * Sets a list of {@link NetworkChannel} instances
     *
     * @param networkChannels
     */
    public void setNetworkChannels(List networkChannels) {
        this.networkChannels = networkChannels;
    }

    /**
     * Adds a new network channel for the given URI
     *
     * @param uri
     * @return
     */
    public NetworkChannel addNetworkChannel(String uri) throws JMSException {
        NetworkChannel networkChannel = createNetworkChannel(uri);
        addNetworkChannel(networkChannel);
        return networkChannel;
    }
    

    /**
     * Adds a new network channel
     */
    public void addNetworkChannel(NetworkChannel networkChannel) throws JMSException {
        configure(networkChannel);
        networkChannels.add(networkChannel);
    }

    /**
     * Removes a network channel
     */
    public void removeNetworkChannel(NetworkChannel networkChannel) {
        networkChannels.remove(networkChannel);
    }

    public ActiveMQPrefetchPolicy getLocalPrefetchPolicy() {
        return localPrefetchPolicy;
    }

    public void setLocalPrefetchPolicy(ActiveMQPrefetchPolicy localPrefetchPolicy) {
        this.localPrefetchPolicy = localPrefetchPolicy;
    }

    public ActiveMQPrefetchPolicy getRemotePrefetchPolicy() {
        return remotePrefetchPolicy;
    }

    public void setRemotePrefetchPolicy(ActiveMQPrefetchPolicy remotePrefetchPolicy) {
        this.remotePrefetchPolicy = remotePrefetchPolicy;
    }


    // Expose individual prefetch properties as individual properties
    //-------------------------------------------------------------------------
    public int getLocalDurableTopicPrefetch() {
        return localPrefetchPolicy.getDurableTopicPrefetch();
    }

    public void setLocalDurableTopicPrefetch(int durableTopicPrefetch) {
        localPrefetchPolicy.setDurableTopicPrefetch(durableTopicPrefetch);
    }

    public int getLocalQueuePrefetch() {
        return localPrefetchPolicy.getQueuePrefetch();
    }

    public void setLocalQueuePrefetch(int queuePrefetch) {
        localPrefetchPolicy.setQueuePrefetch(queuePrefetch);
    }

    public int getLocalQueueBrowserPrefetch() {
        return localPrefetchPolicy.getQueueBrowserPrefetch();
    }

    public void setLocalQueueBrowserPrefetch(int queueBrowserPrefetch) {
        localPrefetchPolicy.setQueueBrowserPrefetch(queueBrowserPrefetch);
    }

    public int getLocalTopicPrefetch() {
        return localPrefetchPolicy.getTopicPrefetch();
    }

    public void setLocalTopicPrefetch(int topicPrefetch) {
        localPrefetchPolicy.setTopicPrefetch(topicPrefetch);
    }


    public int getRemoteDurableTopicPrefetch() {
        return remotePrefetchPolicy.getDurableTopicPrefetch();
    }

    public void setRemoteDurableTopicPrefetch(int durableTopicPrefetch) {
        remotePrefetchPolicy.setDurableTopicPrefetch(durableTopicPrefetch);
    }

    public int getRemoteQueuePrefetch() {
        return remotePrefetchPolicy.getQueuePrefetch();
    }

    public void setRemoteQueuePrefetch(int queuePrefetch) {
        remotePrefetchPolicy.setQueuePrefetch(queuePrefetch);
    }

    public int getRemoteQueueBrowserPrefetch() {
        return remotePrefetchPolicy.getQueueBrowserPrefetch();
    }

    public void setRemoteQueueBrowserPrefetch(int queueBrowserPrefetch) {
        remotePrefetchPolicy.setQueueBrowserPrefetch(queueBrowserPrefetch);
    }

    public int getRemoteTopicPrefetch() {
        return remotePrefetchPolicy.getTopicPrefetch();
    }

    public void setRemoteTopicPrefetch(int topicPrefetch) {
        remotePrefetchPolicy.setTopicPrefetch(topicPrefetch);
    }


    // Implementation methods
    //-------------------------------------------------------------------------


    /**
     * Create a channel from the url
     * @param url
     * @return
     */
    protected NetworkChannel createNetworkChannel(String url) {
        NetworkChannel answer = new NetworkChannel(this,getBrokerContainer(), url);
        answer.setRemoteUserName(getRemoteUserName());
        answer.setRemotePassword(getRemotePassword());
        return answer;
    }

    /**
     * Performs any network connector based configuration; such as setting the dispatch policies
     *
     * @param networkChannel
     */
    protected void configure(NetworkChannel networkChannel) throws JMSException {
        networkChannel.getLocalConnection().setPrefetchPolicy(localPrefetchPolicy);
        networkChannel.getRemoteConnection().setPrefetchPolicy(remotePrefetchPolicy);
    }

}
