/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2004-2007 Bull S.A.S.
 * Contact: jonas-team@ow2.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.ow2.jonas.generators.genclientstub.generator;

import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;
import org.ow2.carol.util.configuration.ConfigurationRepository;
import org.ow2.fastrmic.RMIC;
import org.ow2.jonas.deployment.api.IEJBRefDesc;
import org.ow2.jonas.generators.genbase.GenBaseException;
import org.ow2.jonas.generators.genbase.archive.Archive;
import org.ow2.jonas.generators.genbase.archive.Client;
import org.ow2.jonas.generators.genbase.archive.EjbJar;
import org.ow2.jonas.generators.genbase.archive.J2EEArchive;
import org.ow2.jonas.generators.genbase.archive.WebApp;
import org.ow2.jonas.generators.genbase.generator.AbsGenerator;
import org.ow2.jonas.generators.genbase.generator.Config;
import org.ow2.jonas.generators.genclientstub.ClientStubGenException;
import org.ow2.jonas.lib.bootstrap.JProp;
import org.ow2.jonas.lib.loader.AbsModuleClassLoader;
import org.ow2.jonas.lib.util.Cmd;
import org.ow2.jonas.lib.util.I18n;
import org.ow2.jonas.lib.util.Log;

import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;

/**
 * Generator used to generate Stubs for clients.
 * @author Florent Benoit
 */
public class Generator extends AbsGenerator {

        /**
     * logger.
     */
    private static Logger logger = Log.getLogger("org.ow2.jonas.generators.genclientstub");
    /**
     * i18n.
     */
    private static I18n i18n = I18n.getInstance(Generator.class);

    /**
     * EjbRef used for this generator.
     */
    private IEJBRefDesc ejbRef = null;

    /**
     * Class used if no ejbRef is given.
     */
    private String intfStubClassName = null;

    /**
     * Archive used by the modifier.
     */
    private Archive archive = null;

    /**
     * Creates a new Generator with the given Config.
     * @param config internal configuration object.
     * @param ejbRef reference to the ejb on which we want create the stub
     * @param intfStubClassName name of the interface
     * @param archive given ejbjar, webapp, ...
     * @throws GenBaseException When sources and target temporary directory
     *         cannot be created
     */
    public Generator(Config config, IEJBRefDesc ejbRef, String intfStubClassName, Archive archive) throws GenBaseException {
        super(config);
        this.ejbRef = ejbRef;
        this.intfStubClassName = intfStubClassName;
        this.archive = archive;
    }

    /**
     * Generate stub files.
     * @throws ClientStubGenException When generation fails.
     */
    public void generate() throws ClientStubGenException {

        try {
            //URL[] urls = null;
            String archiveClasspath = null;

            J2EEArchive arch = (J2EEArchive) this.archive;
            AbsModuleClassLoader loader = (AbsModuleClassLoader) arch.getModuleClassloader();

            archiveClasspath = loader.getClasspath();

            // itf class
            String itfClass = null;
            if (ejbRef != null) {
                itfClass = ejbRef.getHome();
            } else {
                itfClass = intfStubClassName;
            }

            // TODO Now try to load the class and check if stub is here

            // Add to the rmic Classpath all the lib and classes of the archive
            String classpath = getConfig().getClasspath() + File.pathSeparator + archiveClasspath;

            // Add client.jar to the classpath
            String jRoot = JProp.getJonasRoot();
            if (jRoot != null) {
                classpath = jRoot + File.separator + "lib" + File.separator + "client.jar" + File.pathSeparator + classpath;
            }

            if (logger.isLoggable(BasicLevel.DEBUG)) {
                logger.log(BasicLevel.DEBUG, "Using classpath '" + classpath + "'.");
            }


            // Get current protocol
            String rmiName = ConfigurationRepository.getCurrentConfiguration().getProtocol().getName();

            if (rmiName.equalsIgnoreCase("iiop") && itfClass != null) {
                Cmd iiopCmd = new Cmd(getConfig().getJavaHomeBin() + getConfig().getNameRmic());
                iiopCmd.addArgument("-classpath");
                iiopCmd.addArgument(classpath);
                iiopCmd.addArgument("-iiop");
                iiopCmd.addArgument("-poa");
                iiopCmd.addArgument("-always");
                iiopCmd.addArgument("-keepgenerated");
                iiopCmd.addArgument("-g");

                iiopCmd.addArgument("-d");
                iiopCmd.addArgument(getClasses().getCanonicalPath());
                iiopCmd.addArguments(getConfig().getJavacOpts());

                // add itf class as arg name
                iiopCmd.addArgument(itfClass);

                if (getLogger().isLoggable(BasicLevel.DEBUG)) {
                    getLogger().log(BasicLevel.DEBUG, "Running '" + iiopCmd.toString() + "'");
                }
                if (iiopCmd.run()) {
                    getLogger().log(BasicLevel.INFO,
                            "Client stubs for classname '" + itfClass + "' successfully generated for protocol 'iiop'.");
                } else {
                    String err = i18n.getMessage("Generator.generate.error");
                    getLogger().log(BasicLevel.ERROR, err);
                    throw new ClientStubGenException(err);
                }

            } else if (itfClass != null && (("jrmp".equalsIgnoreCase(rmiName) || "irmi".equalsIgnoreCase(rmiName)))) {
                Cmd jrmpCmd = new Cmd(getConfig().getJavaHomeBin() + getConfig().getNameRmic());
                jrmpCmd.addArgument("-classpath");
                jrmpCmd.addArgument(classpath);
                jrmpCmd.addArgument("-keepgenerated");
                jrmpCmd.addArgument("-g");
                jrmpCmd.addArgument("-d");
                jrmpCmd.addArgument(getClasses().getCanonicalPath());
                jrmpCmd.addArguments(getConfig().getJavacOpts());

                // add itf class as arg name
                jrmpCmd.addArgument(itfClass);

                ArrayList args = new ArrayList();
                boolean skip = true;
                for (Iterator it = jrmpCmd.getCommandLine(); it.hasNext();) {
                    Object o = it.next();
                    if (skip) {
                        skip = false;
                        continue;
                    }
                    args.add(o);
                }

                // Build the stub using Fast RMIC
                String[] a = (String[]) args.toArray(new String[] {});
                RMIC rmic = new RMIC(a);

                if (rmic.run()) {
                    getLogger().log(BasicLevel.INFO,
                            "Client stubs for classname '" + itfClass + "' successfully generated for protocol '" + rmiName + "'.");
                } else {
                    String err = i18n.getMessage("Generator.generate.error");
                    getLogger().log(BasicLevel.ERROR, err);
                    throw new ClientStubGenException(err, rmic.getException());
                }

            }



        } catch (Exception e) {
            String err = i18n.getMessage("Generator.generate.error");
            getLogger().log(BasicLevel.ERROR, err);
            throw new ClientStubGenException(err, e);
        }

    }

    /**
     * Compile generated java files into classes directory. Do nothing in case
     * of clientstub generator as all classes are generated
     * @throws ClientStubGenException When compilation fails
     */
    public void compile() throws ClientStubGenException {
    }

    /**
     * Add generated files into an Archive
     * @param archive the archive destination of generated files.
     * @throws ClientStubGenException When files cannot be added in the given
     *         Archive.
     */
    public void addFiles(Archive archive) throws ClientStubGenException {
        if (archive instanceof WebApp) {
            archive.addDirectoryIn("WEB-INF/classes/", getClasses());
        } else if (archive instanceof EjbJar) {
            archive.addDirectory(getClasses());
        } else if (archive instanceof Client) {
            archive.addDirectory(getClasses());
        }
    }

}