/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2004-2010 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.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.ow2.jonas.ant.jonasbase.BaseTaskItf;
import org.ow2.jonas.ant.jonasbase.Carol;
import org.ow2.jonas.ant.jonasbase.Db;
import org.ow2.jonas.ant.jonasbase.Dbm;
import org.ow2.jonas.ant.jonasbase.Discovery;
import org.ow2.jonas.ant.jonasbase.JMkdir;
import org.ow2.jonas.ant.jonasbase.JdbcRa;
import org.ow2.jonas.ant.jonasbase.JdbcXml;
import org.ow2.jonas.ant.jonasbase.Jms;
import org.ow2.jonas.ant.jonasbase.JonasProperties;
import org.ow2.jonas.ant.jonasbase.Lib;
import org.ow2.jonas.ant.jonasbase.Mail;
import org.ow2.jonas.ant.jonasbase.Services;
import org.ow2.jonas.ant.jonasbase.Tasks;
import org.ow2.jonas.ant.jonasbase.WebContainer;
import org.ow2.jonas.ant.jonasbase.jaas.Jaas;
import org.ow2.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 = "tomcat7-server.xml";

    /**
     * Name of Tomcat configuration file.
     */
    public static final String JETTY_CONF_FILE = "jetty6.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";

    /**
     * Name of JAAS configuration file.
     */
    public static final String JAAS_CONF_FILE = "jaas.config";

    /**
     * Name of logs directory.
     */
    public static final String LOG_DIR_NAME = "logs";

    /**
     * Name of deploy directory.
     */
    public static final String DEPLOY_DIR_NAME = "deploy";

    /**
     * Name of datasources configuration file
     */
    public static final String JDBC_DS_CONF_FILE = "jdbc-ds.xml";
    /**
     * Name of lib/ext directory.
     */
    public static final String LIB_EXT_DIR_NAME = "lib/ext";

    /**
     * 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()
     */
    @Override
    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()) {
                throw new BuildException("JOnAS base directory '" + destDir.getPath() + "' doesn't exists. Cannot update.");
            }
        }

        if (!onlyUpdate) {
            // 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();

            log("Creating logs in the directory '" + destDir, Project.MSG_INFO);
            JMkdir mkdir = new JMkdir();
            JOnASAntTool.configure(this, mkdir);
            mkdir.setDestDir(new File(destDir + File.separator + LOG_DIR_NAME));
            mkdir.execute();

            log("Creating deploy in the directory '" + destDir, Project.MSG_INFO);
            mkdir = new JMkdir();
            JOnASAntTool.configure(this, mkdir);
            mkdir.setDestDir(new File(destDir + File.separator + DEPLOY_DIR_NAME));
            mkdir.execute();

            log("Creating lib/ext in the directory '" + destDir, Project.MSG_INFO);
            mkdir = new JMkdir();
            JOnASAntTool.configure(this, mkdir);
            mkdir.setDestDir(new File(destDir + File.separator + LIB_EXT_DIR_NAME));
            mkdir.execute();
        } else {
            log("Only updating JONAS_BASE in the directory '" + destDir + "' from source directory '" + jonasRoot + "'",
                    Project.MSG_INFO);
        }


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

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

    /**
     * Add tasks for configured object.
     * @param subTasks some tasks to do on files
     */
    public void addTasks(final 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(final 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(final Services servicesTasks) {
        addTask(servicesTasks);
    }

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

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

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

    /**
     * Add task for Resource adaptor.
     * @param jdbcRaTask task to do
     */
    public void addConfiguredJdbcXml(final JdbcXml jdbcXmlTask) {
        addTask(jdbcXmlTask);
    }

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

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

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

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

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

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

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

    /**
     * Add tasks for JAAS configuration.
     * @param jaasTasks tasks to do on files
     */
    public void addConfiguredJaas(final Jaas jaasTasks) {
        addTasks(jaasTasks);
    }

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

    /**
     * Set the source directory for the replacement.
     * @param jonasRoot the source directory
     */
    public void setJonasRoot(final 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(final boolean onlyUpdate) {
        this.onlyUpdate = onlyUpdate;
    }

}
