/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2004-2005 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.ant;

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

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.taskdefs.Copy;
import org.apache.tools.ant.types.FileSet;

import org.objectweb.jonas.ant.jonasbase.BaseTaskItf;
import org.objectweb.jonas.ant.jonasbase.Carol;
import org.objectweb.jonas.ant.jonasbase.Db;
import org.objectweb.jonas.ant.jonasbase.Dbm;
import org.objectweb.jonas.ant.jonasbase.Discovery;
import org.objectweb.jonas.ant.jonasbase.JdbcRa;
import org.objectweb.jonas.ant.jonasbase.JonasProperties;
import org.objectweb.jonas.ant.jonasbase.Jms;
import org.objectweb.jonas.ant.jonasbase.Lib;
import org.objectweb.jonas.ant.jonasbase.Mail;
import org.objectweb.jonas.ant.jonasbase.Services;
import org.objectweb.jonas.ant.jonasbase.Tasks;
import org.objectweb.jonas.ant.jonasbase.WebContainer;
import org.objectweb.jonas.ant.jonasbase.wsdl.WsdlPublish;

/**
 * Class used to create a JOnAS base with different configuration like port, url
 * for JNDI, etc
 * @author Florent Benoit
 */
public class JOnASBaseTask extends Task {

    /**
     * Name of JOnAS configuration file
     */
    public static final String JONAS_CONF_FILE = "jonas.properties";

    /**
     * Name of Joram configuration file
     */
    public static final String JORAM_CONF_FILE = "a3servers.xml";

    /**
     * Name of Joram admin configuration file (resource adaptor)
     */
    public static final String JORAM_ADMIN_CONF_FILE = "joramAdmin.xml";

    /**
     * Name of Carol configuration file
     */
    public static final String CAROL_CONF_FILE = "carol.properties";

    /**
     * Name of JGroups CMI configuration file
     */
    public static final String JGROUPS_CMI_CONF_FILE = "jgroups-cmi.xml";

    /**
     * Name of JGroups HA configuration file
     */
    public static final String JGROUPS_HA_CONF_FILE = "jgroups-ha.xml";

    /**
     * Name of Tomcat configuration file
     */
    public static final String TOMCAT_CONF_FILE = "server.xml";

    /**
     * Name of Tomcat configuration file
     */
    public static final String JETTY_CONF_FILE = "jetty5.xml";

    /**
     * Name of P6Spy configuration file
     */
    public static final String P6SPY_CONF_FILE = "spy.properties";

    /**
     * Name of domain management file
     */
    public static final String DOMAIN_CONF_FILE = "domain.xml";

    /**
     * List of Wars to copy for each JONAS_BASE
     */
    public static final String[] WARS_LIST = new String[] {"juddi.war", "autoload/jonasAdmin.war"};

    /**
     * List of Rars to copy for each JONAS_BASE
     */
    public static final String[] RARS_LIST =  new String[] {"autoload/JOnAS_jdbcCP.rar", "autoload/JOnAS_jdbcDM.rar", "autoload/JOnAS_jdbcDS.rar", "autoload/JOnAS_jdbcXA.rar", "autoload/joram_for_jonas_ra.rar"};

    /**
     * List of EjbJars to copy for each JONAS_BASE
     */
    public static final String[] EJBJARS_LIST = new String[] {""};

    /**
     * List of Apps to copy for each JONAS_BASE
     */
    public static final String[] APPS_LIST = new String[] {"autoload/mejb.ear"};


    /**
     * Source directory (JOnAS root)
     */
    private File jonasRoot = null;

    /**
     * Destination directory (Where create the jonasBase)
     */
    private File destDir = null;

    /**
     * Update only JONAS_BASE without erasing it
     */
    private boolean onlyUpdate = false;

    /**
     * List of tasks to do
     */
    private List tasks = null;

    /**
     * Constructor
     */
    public JOnASBaseTask() {
        tasks = new ArrayList();
    }

    /**
     * Run this task
     * @see org.apache.tools.ant.Task#execute()
     */
    public void execute() {
        if (jonasRoot == null) {
            throw new BuildException("jonasRoot element is not set");
        }

        if (destDir == null) {
            throw new BuildException("destDir element is not set");
        }

        if (jonasRoot.getPath().equals(destDir.getPath())) {
            throw new BuildException("jonasRoot and destDir is the same path !");
        }

        File jprops = new File(destDir.getPath() + File.separator + "conf" + File.separator + "jonas.properties");

        if (onlyUpdate) {
            if (jprops.exists()) {
                log("Only updating JONAS_BASE in the directory '" + destDir + "' from source directory '" + jonasRoot + "'",
                    Project.MSG_INFO);
                JOnASAntTool.updateJonasBase(this, jonasRoot, destDir);
                return;
            } else {
                throw new BuildException("JOnAS base directory '" + destDir.getPath() + "' doesn't exists. Cannot update.");
            }
        }

        // First, create JOnAS base
        log("Creating JONAS_BASE in the directory '" + destDir + "' from source directory '" + jonasRoot + "'",
                Project.MSG_INFO);
        Copy copy = new Copy();
        JOnASAntTool.configure(this, copy);
        copy.setTodir(destDir);
        FileSet fileSet = new FileSet();
        fileSet.setDir(new File(new File(jonasRoot, "templates"), "conf"));
        copy.addFileset(fileSet);
        copy.setOverwrite(true);
        copy.execute();

        for (Iterator it = tasks.iterator(); it.hasNext();) {
            BaseTaskItf task = (BaseTaskItf) it.next();
            task.setDestDir(destDir);
            task.setJonasRoot(jonasRoot);
            JOnASAntTool.configure(this, (Task) task);
            String info = task.getLogInfo();
            if (info != null) {
                log(info, Project.MSG_INFO);
            }
            task.execute();
        }

        // Then update JonasBase
        JOnASAntTool.updateJonasBase(this, jonasRoot, destDir);
    }

    /**
     * Add tasks for configured object
     * @param subTasks some tasks to do on files
     */
    public void addTasks(Tasks subTasks) {
        if (subTasks != null) {
            for (Iterator it = subTasks.getTasks().iterator(); it.hasNext();) {
                tasks.add(it.next());
            }
        }
    }

    /**
     * Add a task for configure some objects
     * @param task the task to do
     */
    public void addTask(BaseTaskItf task) {
        if (task != null) {
            tasks.add(task);
        }
    }

    /**
     * Add tasks for services (wrapped to default method)
     * @param servicesTasks tasks to do on files
     */
    public void addConfiguredServices(Services servicesTasks) {
        addTask(servicesTasks);
    }

    /**
    * Add tasks for jonas.properties global properties configuration
    * @param servicesTasks tasks to do on files
    */
    public void addConfiguredJonasProperties(JonasProperties servicesTasks) {
        addTask(servicesTasks);
    }

    /**
     * Add tasks for JMS configuration
     * @param jmsTasks tasks to do on files
     */
    public void addConfiguredJms(Jms jmsTasks) {
        addTasks(jmsTasks);
    }

    /**
     * Add task for Resource adaptor
     * @param jdbcRaTask task to do
     */
    public void addConfiguredJdbcRa(JdbcRa jdbcRaTask) {
        addTask(jdbcRaTask);
    }

    /**
     * Add task for Resource adaptor
     * @param mailTask task to do
     */
    public void addConfiguredMail(Mail mailTask) {
        addTask(mailTask);
    }

    /**
     * Add task for the DB service
     * @param dbTask task to do
     */
    public void addConfiguredDb(Db dbTask) {
        addTask(dbTask);
    }

    /**
     * Add task for the DBM service
     * @param dbTask task to do
     */
    public void addConfiguredDbm(Dbm dbTask) {
        addTask(dbTask);
    }
    /**
     * Add task for library to put in JONAS_BASE/lib/ext
     * @param libTask task to do
     */
    public void addConfiguredLib(Lib libTask) {
        addTask(libTask);
    }

    /**
     * Add task for WSDL
     * @param wsdlTask task to do
     */
    public void addConfiguredWsdlPublish(WsdlPublish wsdlTask) {
        addTask(wsdlTask);
    }

    /**
     * Add tasks for Carol configuration
     * @param carolTasks tasks to do on files
     */
    public void addConfiguredCarol(Carol carolTasks) {
        addTasks(carolTasks);
    }

    /**
     * Add tasks for Discovery configuration
     * @param discoveryTasks tasks to do on files
     */
    public void addConfiguredDiscovery(Discovery discoveryTasks) {
        addTasks(discoveryTasks);
    }

    /**
     * Add tasks for the web container configuration
     * @param webContainerTasks tasks to do on files
     */
    public void addConfiguredWebContainer(WebContainer webContainerTasks) {
        addTasks(webContainerTasks);
    }

    /**
     * Set the destination directory for the replacement
     * @param destDir the destination directory
     */
    public void setDestDir(File destDir) {
        this.destDir = destDir;
    }

    /**
     * Set the source directory for the replacement
     * @param jonasRoot the source directory
     */
    public void setJonasRoot(File jonasRoot) {
        this.jonasRoot = jonasRoot;
    }

    /**
     * Set if this is only an update or a new JONAS_BASE
     * @param onlyUpdate If true update, else create and then update
     */
    public void setUpdate(boolean onlyUpdate) {
        this.onlyUpdate = onlyUpdate;
    }

}