/*
 *  Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you 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.apache.synapse.transport.fix;

import org.apache.axis2.AxisFault;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.description.AxisService;
import org.apache.axis2.description.TransportInDescription;
import org.apache.axis2.transport.base.AbstractTransportListener;

/**
 * The FIX transport listener implementation. A FIX Transport Listner will hold
 * a FIX session factory, which would be created at initialization
 * time. This implementation supports the creation of FIX sessions at runtime
 * as and when required. This FIX Listener registers with Axis to be notified
 * of service deployment/undeployment/start/stop, and enables or disables
 * listening for FIX messages on the destinations as appropriate.
 * <p/>
 * Service must state where the FIX configuration file is located so
 * that  the required FIX sessions can be initialized for the service.
 * FIX configuration file should be a valid Quickfix/J session
 * configuration file. A URL to the file should be provided.
 * <p/>
 * <parameter name="transport.fix.AcceptorConfigURL">
 * http://www.mycompany.org/fixconfig/file.cfg</parameter>
 */
public class FIXTransportListener extends AbstractTransportListener {

    /**
     * The FIXSessionFactory takes care of creating and managing all the
     * FIX sessions.
     */
    private FIXSessionFactory fixSessionFactory;

    /**
     * This is the TransportListener initialization method invoked by Axis2
     *
     * @param cfgCtx    the Axis configuration context
     * @param trpInDesc the TransportIn description
     */
    @Override
    public void init(ConfigurationContext cfgCtx,
                     TransportInDescription trpInDesc) throws AxisFault {

        super.init(cfgCtx, trpInDesc);
        fixSessionFactory = FIXSessionFactory.getInstance(new FIXApplicationFactory(cfgCtx));
        fixSessionFactory.setListenerThreadPool(this.workerPool);
        log.info("FIX transport listener initialized...");
    }

    /**
     * Prepare to listen for FIX messages on behalf of the given service
     * by first creating and starting a FIX session
     *
     * @param service the service for which to listen for messages
     */
    @Override
    public void startListeningForService(AxisService service) {
        try {
            boolean acceptorCreated = fixSessionFactory.createFIXAcceptor(service);
            boolean initiatorCreated = fixSessionFactory.createFIXInitiator(service);

            if (!acceptorCreated && !initiatorCreated) {
                log.warn("No acceptor or initiator has been configured for the " +
                        "service " + service.getName() + " - Disabling the FIX transport for " +
                        "this service");
                disableTransportForService(service);
            }
        } catch (AxisFault axisFault) {
            disableTransportForService(service);
        }
    }

    /**
     * Stops listening for messages for the service thats undeployed or stopped
     * by stopping and disposing the appropriate FIX session
     *
     * @param service the service that was undeployed or stopped
     */
    @Override
    protected void stopListeningForService(AxisService service) {
        fixSessionFactory.disposeFIXAcceptor(service);
    }

    /**
     * Returns EPRs for the given service and IP over the FIX transport
     *
     * @param serviceName service name
     * @param ip          ignored
     * @return the EPR for the service
     * @throws AxisFault
     */
    @Override
    public EndpointReference[] getEPRsForService(String serviceName, String ip) throws AxisFault {

        if (serviceName.indexOf('.') != -1) {
            serviceName = serviceName.substring(0, serviceName.indexOf('.'));
        }
        
        //Try to get the list of EPRs from the FIXSessionFactory
        String[] serviceEPRStrings = fixSessionFactory.getServiceEPRs(serviceName, ip);
        if (serviceEPRStrings != null) {
            EndpointReference[] serviceEPRs = new EndpointReference[serviceEPRStrings.length];
            for (int i = 0; i < serviceEPRStrings.length; i++) {
                serviceEPRs[i] = new EndpointReference(serviceEPRStrings[i]);
            }
            return serviceEPRs;
        }
        throw new AxisFault("Unable to get EPRs for the service " + serviceName);
    }
}