/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999-2004 Bull S.A.
 * 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.genic;

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

import org.ow2.jonas.deployment.ejb.BeanDesc;
import org.ow2.jonas.deployment.ejb.EntityCmp2Desc;
import org.ow2.jonas.deployment.ejb.EntityDesc;
import org.ow2.jonas.deployment.ejb.EntityJdbcCmp1Desc;
import org.ow2.jonas.deployment.ejb.SessionStatelessDesc;
import org.ow2.jonas.lib.ejb21.jorm.RdbMappingBuilder;
import org.ow2.jonas.lib.util.BeanNaming;
import org.ow2.jonas.lib.util.Log;

import org.apache.velocity.app.VelocityEngine;

import org.objectweb.jorm.compiler.api.JormCompilerParameter;
import org.objectweb.jorm.compiler.lib.JormCompiler;
import org.objectweb.jorm.metainfo.api.Manager;

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

/**
 * This class allows to generate the sources of: the class that implements the
 * Enterprise bean's remote interface, the class that implements the Enterprise
 * bean's home interface, the class that implements the Enterprise bean's local
 * interface, the class that implements the Enterprise bean's localhome
 * interface, the class of the Entity Handle in case of entity, and the extended
 * class of the Bean for persistence in case of entity with CMP, of a given
 * Enterprise Java Bean.
 * @author Helene Joanin : Initial developer
 * @author Philippe Durieux
 * @author Sebastien Chassande
 */
public class BeanSources {

    /**
     * java file suffix
     */
    private static final String JAVA_SUFFIX = ".java";

    /**
     * EJBObject (Remote). May be null if no Remote interface.
     */
    private String wrpRemoteFileName = null;

    /**
     * EJBLocalObject (Local). May be null if no Local interface.
     */
    private String wrpLocalFileName = null;

    /**
     * Home. May be null if no Home interface.
     */
    private String wrpHomeFileName = null;

    /**
     * Home cluster file name. May be null if no Home interface.
     */
    private String wrpHomeClusterFileName = null;

    /**
     * Remote cluster file name. May be null if no Remote interface.
     */
    private String wrpRemoteClusterFileName = null;

    /**
     * LocalHome. May be null if no LocalHome interface.
     */
    private String wrpLocalHomeFileName = null;

    /**
     * Handle (for Entity only)
     */
    private String wrpHandleFileName = null;

    /**
     * Bean (for CMP Entity only)
     */
    private String wrpBeanFileName = null;

    /**
     * Service Endpoint filename
     */
    private String wrpServiceEndpointFileName = null;

    /**
     * Service Endpoint Home filename
     */
    private String wrpSEHomeFileName = null;

    /**
     * Interface for Cmp2 Entity coherence
     */
    private String itfCohCmp2Entity = null;

    /**
     * Source objects used to generate classes
     */
    private ArrayList sources;

    /**
     * Java sources that are not Remote
     */
    private ArrayList noRemoteJava;

    /**
     * directory where to place the generated files
     */
    private String outdir = null;

    /**
     * bean descriptor
     */
    private BeanDesc dd = null;

    /**
     * JORM compiler
     */
    private JormCompiler jormCompiler;

    /**
     * Jorm Manager
     */
    private Manager manager = null;

    /**
     * logger
     */
    private Logger logger = null;

    private GenICParameters gp;

    private VelocityEngine ve;


    /**
     * BeanSources Constructor for bean that is not a entity with CMP2
     * @param beanDesc deployment descriptor of the bean
     * @param gp @param gp GenIC parameters
     * @param ve the Velocity engine
     */
    public BeanSources(BeanDesc beanDesc, GenICParameters gp, VelocityEngine ve) {
        logger = Log.getLogger(Log.JONAS_GENIC_PREFIX);
        dd = beanDesc;
        this.gp = gp;
        outdir = gp.getOutputDirectory();
        this.ve = ve;
        sources = new ArrayList();
        noRemoteJava = new ArrayList();
    }


    /**
     * BeanSources initialization.
     * @param jc
     * @param mgr
     * @exception GenICException In error case
     */
    public void init(JormCompiler jc, Manager mgr) throws GenICException {
        jormCompiler = jc;
        manager = mgr;

        // generated Home
        if (dd.getHomeClass() != null) {
            if (outdir.length() > 0) {
                wrpHomeFileName = outdir + File.separatorChar + BeanNaming.getPath(dd.getFullWrpHomeName());
            } else {
                wrpHomeFileName = dd.getWrpHomeName();
            }

            wrpHomeFileName = wrpHomeFileName.concat(JAVA_SUFFIX);
            sources.add(new Source(dd, wrpHomeFileName, Source.HOME, ve, manager));

            // generated Handle for Remote Entity bean
            if (dd instanceof EntityDesc) {
                if (outdir.length() > 0) {
                    wrpHandleFileName = outdir + File.separatorChar + BeanNaming.getPath(dd.getFullWrpHandleName());
                } else {
                    wrpHandleFileName = dd.getWrpHandleName();
                }
                wrpHandleFileName = wrpHandleFileName.concat(JAVA_SUFFIX);
                noRemoteJava.add(wrpHandleFileName);
                sources.add(new Source(dd, wrpHandleFileName, Source.ENTITY_HANDLE, ve, manager));
            }
        }

        // generated EJBObject (Remote)
        if (dd.getRemoteClass() != null) {
            if (outdir.length() > 0) {
                wrpRemoteFileName = outdir + File.separatorChar + BeanNaming.getPath(dd.getFullWrpRemoteName());
            } else {
                wrpRemoteFileName = dd.getWrpRemoteName();
            }

            wrpRemoteFileName = wrpRemoteFileName.concat(JAVA_SUFFIX);
            sources.add(new Source(dd, wrpRemoteFileName, Source.REMOTE, ve, manager));
        }

        // generated LocalHome
        if (dd.getLocalHomeClass() != null) {
            if (outdir.length() > 0) {
                wrpLocalHomeFileName = outdir + File.separatorChar + BeanNaming.getPath(dd.getFullWrpLocalHomeName());
            } else {
                wrpLocalHomeFileName = dd.getWrpLocalHomeName();
            }
            wrpLocalHomeFileName = wrpLocalHomeFileName.concat(JAVA_SUFFIX);
            noRemoteJava.add(wrpLocalHomeFileName);
            sources.add(new Source(dd, wrpLocalHomeFileName, Source.LOCAL_HOME, ve, manager));
        }

        // generated EJBLocalObject (Local)
        if (dd.getLocalClass() != null) {
            if (outdir.length() > 0) {
                wrpLocalFileName = outdir + File.separatorChar + BeanNaming.getPath(dd.getFullWrpLocalName());
            } else {
                wrpLocalFileName = dd.getWrpLocalName();
            }
            wrpLocalFileName = wrpLocalFileName.concat(JAVA_SUFFIX);
            noRemoteJava.add(wrpLocalFileName);
            sources.add(new Source(dd, wrpLocalFileName, Source.LOCAL, ve, manager));
        }

        // generated ServiceEndpoint and SEHome
        if (dd instanceof SessionStatelessDesc) {
            SessionStatelessDesc ssd = (SessionStatelessDesc) dd;
            if (ssd.getServiceEndpointClass() != null) {
                // ServiceEndpoint
                if (outdir.length() > 0) {
                    wrpServiceEndpointFileName = outdir + File.separatorChar
                            + BeanNaming.getPath(ssd.getFullWrpServiceEndpointName());
                } else {
                    wrpServiceEndpointFileName = ssd.getWrpServiceEndpointName();
                }
                wrpServiceEndpointFileName = wrpServiceEndpointFileName.concat(JAVA_SUFFIX);
                //noRemoteJava.add(wrpServiceEndpointFileName); // Accessed locally only
                sources.add(new Source(dd, wrpServiceEndpointFileName, Source.SERVICE_ENDPOINT, ve, manager));
                // ServiceEndpointHome
                if (outdir.length() > 0) {
                    wrpSEHomeFileName = outdir + File.separatorChar + BeanNaming.getPath(ssd.getFullWrpSEHomeName());
                } else {
                    wrpSEHomeFileName = ssd.getWrpSEHomeName();
                }
                wrpSEHomeFileName = wrpSEHomeFileName.concat(JAVA_SUFFIX);
                noRemoteJava.add(wrpSEHomeFileName); // Accessed locally only
                sources.add(new Source(dd, wrpSEHomeFileName, Source.SERVICE_ENDPOINT_HOME, ve, manager));
            }
        }

        // generated derived bean class for Entity Bean CMP
        if (dd instanceof EntityJdbcCmp1Desc) {
            if (outdir.length() > 0) {
                wrpBeanFileName = outdir + File.separatorChar + BeanNaming.getPath(dd.getFullDerivedBeanName());
            } else {
                wrpBeanFileName = dd.getDerivedBeanName();
            }
            wrpBeanFileName = wrpBeanFileName.concat(JAVA_SUFFIX);
            noRemoteJava.add(wrpBeanFileName);
            sources.add(new Source(dd, wrpBeanFileName, Source.ENTITY_CMP_JDBC, ve, manager));
        }
        if (dd instanceof EntityCmp2Desc) {
            EntityCmp2Desc ecd = (EntityCmp2Desc) dd;
            if (outdir.length() > 0) {
                wrpBeanFileName = outdir + File.separatorChar + BeanNaming.getPath(dd.getFullDerivedBeanName())
                        + JAVA_SUFFIX;
                if (ecd.needJormCoherenceHelper()) {
                    itfCohCmp2Entity = outdir + File.separatorChar
                            + BeanNaming.getPath(ecd.getJormCoherenceHelperFQItfName()) + JAVA_SUFFIX;
                }
            } else {
                wrpBeanFileName = BeanNaming.getPath(dd.getDerivedBeanName()) + JAVA_SUFFIX;
                if (ecd.needJormCoherenceHelper()) {
                    itfCohCmp2Entity = BeanNaming.getPath(ecd.getJormCoherenceHelperItfName()) + JAVA_SUFFIX;
                }
            }
            if (ecd.needJormCoherenceHelper()) {
                sources.add(new Source(dd, itfCohCmp2Entity, Source.ITF_COH_CMP2_ENTITY, ve, manager));
                noRemoteJava.add(itfCohCmp2Entity);
            }
            noRemoteJava.add(wrpBeanFileName);
            sources.add(new Source(dd, wrpBeanFileName, Source.ENTITY_CMP_JDBC, ve, manager));
        }
    }

    /**
     * Generates the java sources
     * @throws GenICException in error case
     */
    public void generate() throws GenICException {
        // Generates the java sources
        for (Iterator it = sources.iterator(); it.hasNext();) {
            Source src = (Source) it.next();
            src.generate();
        }
    }

    public void jormCompile(ArrayList jormList) throws GenICException {

        // In case of Cmp2, call jorm compiler.
        if (dd instanceof EntityCmp2Desc) {
            EntityCmp2Desc ecd = (EntityCmp2Desc) dd;

            // Build and fill a JormCompilerParameter dedicated to the bean
            JormCompilerParameter cp = jormCompiler.getCompilerParameter();
            cp.setProjectName(RdbMappingBuilder.getProjectName());
            cp.setKeepSrc(true);
            cp.setOutput(outdir);
            cp.setClassMappingInheritance("org.ow2.jonas.lib.ejb21.jorm.RdbFactory");
            cp.setStateGenerated(true);
            cp.setStateInheritance(ecd.getEjbClass().getName());
            switch (ecd.getLockPolicy()) {
                case EntityDesc.LOCK_CONTAINER_READ_UNCOMMITTED:
                    cp.setBindingInheritance("org.ow2.jonas.lib.ejb21.JEntitySwitchCRU");
                    break;
                case EntityDesc.LOCK_CONTAINER_SERIALIZED:
                    cp.setBindingInheritance("org.ow2.jonas.lib.ejb21.JEntitySwitchCS");
                    break;
                case EntityDesc.LOCK_CONTAINER_SERIALIZED_TRANSACTED:
                    cp.setBindingInheritance("org.ow2.jonas.lib.ejb21.JEntitySwitchCST");
                    break;
                case EntityDesc.LOCK_CONTAINER_READ_COMMITTED:
                    cp.setBindingInheritance("org.ow2.jonas.lib.ejb21.JEntitySwitchCRC");
                    break;
                case EntityDesc.LOCK_DATABASE:
                    cp.setBindingInheritance("org.ow2.jonas.lib.ejb21.JEntitySwitchDB");
                    break;
                case EntityDesc.LOCK_READ_ONLY:
                    cp.setBindingInheritance("org.ow2.jonas.lib.ejb21.JEntitySwitchRO");
                    break;
                case EntityDesc.LOCK_CONTAINER_READ_WRITE:
                    cp.setBindingInheritance("org.ow2.jonas.lib.ejb21.JEntitySwitchCRW");
                    break;
                default:
                    throw new GenICException("Cannot find JEntitySwitch: Unknown lock policy");
            }

            // Run the Jorm Compiler
            Collection jormflist = null;
            try {
                jormflist = jormCompiler.generateFiles(jormList);
            } catch (Exception e) {
                throw new GenICException("Problem during jorm generation", e);
            }
            // Save the list of Jorm generated files
            for (Iterator i = jormflist.iterator(); i.hasNext();) {
                String file = (String) i.next();
                logger.log(BasicLevel.DEBUG, "Jorm generated file: " + file);
                noRemoteJava.add(file);
            }
        }
    }

    /**
     * @return Return the bean's name
     */
    public String getEjbName() {
        return dd.getEjbName();
    }

    /**
     * @return Return the file name of the generated source for the Home (null
     *         if none)
     */
    public String getWrpHomeFileName() {
        return wrpHomeFileName;
    }

    /**
     * @return Return the file name of the cluster configuration for the Home
     *         (null if none)
     */
    public String getWrpHomeClusterFileName() {
        return wrpHomeClusterFileName;
    }

    /**
     * @return Return the file name of the cluster configuration for the Remote
     *         (null if none)
     */
    public String getWrpRemoteClusterFileName() {
        return wrpRemoteClusterFileName;
    }


    /**
     * @return Return the file name of the generated source for the Remote (null
     *         if none)
     */
    public String getWrpRemoteFileName() {
        return wrpRemoteFileName;
    }

    /**
     * @return Return the class name of the generated source for the Remote
     *         (package included)
     */
    public String getWrpRemoteClassName() {
        return dd.getFullWrpRemoteName();
    }

    /**
     * @return Return the file name of the generated source for the
     *         ServiceEndpoint (null if none)
     */
    public String getWrpServiceEndpointFileName() {
        return wrpServiceEndpointFileName;
    }

    /**
     * @return Return the file name of the generated source for the
     *         ServiceEndpointHome (null if none)
     */
    public String getWrpSEHomeFileName() {
        return wrpSEHomeFileName;
    }

    /**
     * @return Return the class name of the generated source for the
     *         ServiceEndpoint (package included)
     */
    public String getWrpServiceEndpointClassName() {
        if (dd instanceof SessionStatelessDesc) {
            return ((SessionStatelessDesc) dd).getFullWrpServiceEndpointName();
        }
        return null;
    }

    /**
     * @return Return the class name of the generated source for the Home
     *         (package included)
     */
    public String getWrpHomeClassName() {
        return dd.getFullWrpHomeName();
    }

    /**
     * @return Returns the list of the sources that are not Remote
     */
    public Collection getNoRemoteJavas() {
        return noRemoteJava;
    }
}
