/**
 * JOnAS : Java(TM) OpenSource Application Server
 * Copyright (C) 2004 Bull S.A.
 * Contact: jonas-team@objectweb.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.objectweb.jonas_ws.wsgen.generator.axis;

import java.io.File;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import org.apache.velocity.VelocityContext;

import org.objectweb.jonas_lib.genbase.GenBaseException;
import org.objectweb.jonas_lib.genbase.archive.Archive;
import org.objectweb.jonas_lib.genbase.archive.WebApp;
import org.objectweb.jonas_lib.genbase.generator.Config;

import org.objectweb.jonas_ws.deployment.api.JaxRpcPortComponentDesc;
import org.objectweb.jonas_ws.deployment.api.PortComponentDesc;
import org.objectweb.jonas_ws.deployment.api.ServiceDesc;
import org.objectweb.jonas_ws.wsgen.WsGenException;
import org.objectweb.jonas_ws.wsgen.ddmodifier.WebServicesDDModifier;
import org.objectweb.jonas_ws.wsgen.ddmodifier.WsEndpointDDModifier;
import org.objectweb.jonas_ws.wsgen.generator.WsEndpointGenerator;

import org.objectweb.jonas.common.Log;

import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;

/**
 * Generate Axis specific config files for Endpoint
 *
 * @author Guillaume Sauthier
 */
public class AxisWsEndpointGenerator extends WsEndpointGenerator {

    /**
     * unique JVelocity instance
     */
    private static JVelocity jvelocity = null;

    /**
     * logger
     */
    private static Logger logger = Log.getLogger(Log.JONAS_WSGEN_PREFIX);

    /**
     * Axis Servlet classname
     */
    private static final String AXIS_SERVLET_CLASS = "org.objectweb.jonas.ws.axis.JAxisServlet";

    /**
     * init-param name for declaring server configuration file
     */
    private static final String SERVER_CONFIG = "axis.serverConfigFile";

    /**
     * WSDD Extension suffix
     */
    private static final String WSDD_SUFFIX = ".wsdd";

    /**
     * WSDD Extension prefix
     */
    private static final String WSDD_PREFIX = "deploy-server-";

    /**
     * count generated files
     */
    private static int count = 0;

    /**
     * generated server-config file
     */
    private File generatedServerConfig;

    /**
     * Creates a new AxisWsEndpointGenerator
     *
     * @param config Generator Configuration
     * @param serviceDesc WebService Endpoint description
     * @param ddm Web DD Modifier
     * @param wsddm webservices.xml DD modifier
     *
     * @throws GenBaseException When instanciation fails
     * @throws WsGenException When instanciation fails.
     */
    public AxisWsEndpointGenerator(Config config, ServiceDesc serviceDesc, WsEndpointDDModifier ddm,
            WebServicesDDModifier wsddm, Archive arch) throws GenBaseException, WsGenException {
        super(config, serviceDesc, ddm, wsddm, arch);

        // init velocity
        if (jvelocity == null) {
            jvelocity = new JVelocity("deploy_endpoint.vm");
        }
    }

    /**
     * Generate server side configuration file
     *
     * @throws WsGenException When generation fails
     */
    public void generate() throws WsGenException {
        String sName = getService().getName();

        // construct VelocityContext
        VelocityContext vc = VContextFactory.getContext(getService());

        // Generate file
        String filename = WSDD_PREFIX + (count++) + WSDD_SUFFIX;
        generatedServerConfig = new File(getSources(), filename);
        jvelocity.generate(generatedServerConfig, vc);

        // remove existing servlets
        for (Iterator i = getService().getPortComponents().iterator(); i.hasNext();) {
            Object obj = i.next();
            if (obj instanceof JaxRpcPortComponentDesc) {
                JaxRpcPortComponentDesc jax = (JaxRpcPortComponentDesc) obj;

                if (logger.isLoggable(BasicLevel.DEBUG)) {
                    logger.log(BasicLevel.DEBUG, "Removing servlet '" + jax.getSibLink() + "'");
                }

                // remove servlet mapping
                getModifier().removeServletMapping(jax.getSibLink());
                // remove old servlet
                getModifier().removeServlet(jax.getSibLink());
                // change sib-link
                getWsModifier().changeServletLink(sName, jax.getSibLink(), sName);
            }
        }

        // and use our own
        getModifier().addServlet(sName, AXIS_SERVLET_CLASS);
        getModifier().addServletParam(sName, SERVER_CONFIG, filename);

        // setup servlet-mappings
        boolean requireDefaultMapping = false;
        List usedServletMappings = new Vector();
        for (Iterator i = getService().getPortComponents().iterator(); i.hasNext();) {
            PortComponentDesc pcd = (PortComponentDesc) i.next();
            String mapping = pcd.getMapping();
            if (mapping != null) {
                // port has specified an endpoint URI
                // use it for servlet-mapping
                if (!usedServletMappings.contains(mapping)) {
                    usedServletMappings.add(mapping);

                    if (logger.isLoggable(BasicLevel.DEBUG)) {
                        logger.log(BasicLevel.DEBUG, "Adding servlet-mapping for '" + sName + "' -> '" + mapping + "'");
                    }

                    getModifier().addServletMapping(sName, mapping);
                }
            } else {
                // no specified endpoint uri for the port
                requireDefaultMapping = true;
            }
        }
        if (requireDefaultMapping) {
            // try to set a default mapping
            String defaultEndpointURI = getService().getEndpointURI();
            if (defaultEndpointURI == null) {
                // default behavior
                getModifier().addServletMapping(sName, "/" + sName + "/*");
            } else {
                // use retieved value
                getModifier().addServletMapping(sName, defaultEndpointURI);
            }
        }

    }

    /**
     * Add generated files in given Archive
     *
     * @param archive WebApp archive
     *
     * @throws WsGenException When cannot add files in archive
     */
    public void addFiles(Archive archive) throws WsGenException {
        // archive must be a WebApp
        if (!(archive instanceof WebApp)) {
            String err = getI18n().getMessage("AxisWsEndpointGenerator.addFiles.illegal", archive.getRootFile());
            throw new IllegalArgumentException(err);
        }

        WebApp web = (WebApp) archive;
        web.addFileIn("WEB-INF/", generatedServerConfig);

    }
}