/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2006-2011 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
 *
 * Initial developer: Benoit Pelletier
 * --------------------------------------------------------------------------
 * $Id: ClusterDaemon.java 21579 2011-08-08 12:28:46Z cazauxj $
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.antmodular.cluster.clusterdaemon;

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

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.tools.ant.BuildException;
import org.ow2.jonas.antmodular.jonasbase.bootstrap.AbstractJOnASBaseAntTask;
import org.ow2.jonas.antmodular.jonasbase.bootstrap.BaseTaskItf;
import org.ow2.jonas.antmodular.jonasbase.bootstrap.XMLSerializerTask;
import org.ow2.jonas.antmodular.jonasbase.carol.Carol;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.SAXException;

/**
 * Configures the cluster daemon
 * @author Benoit Pelletier
 */
public class ClusterDaemon extends AbstractJOnASBaseAntTask {

    /**
     * Info for the logger
     */
    private static final String INFO = "[ClusterDaemon] ";

    /**
     * Name of the configuration file
     */
    private static final String CLUSTER_DAEMON_CONF_FILE = "clusterd.xml";

    /**
     * Domain.xml structure
     */
    private Document clusterDaemonDoc = null;

    /**
     * Flag indicating if the document has been loaded
     */
    private boolean clusterDaemonDocLoaded = false;

    /**
     * name
     */
    private String name = null;

    /**
     * domain name
     */
    private String domainName = null;

    /**
     * directory
     */
    private String cdDir = null;

    /**
     * protocol
     */
    private String protocol = null;

    /**
     * port number
     */
    private String port = null;

    /**
     * jdk
     */
    private String jdk = null;

    /**
     * interaction mode
     */
    private String interactionMode = null;

    /**
     * autoboot
     */
    private String autoBoot = null;

    /**
     * xprm
     */
    private String xprm = null;

    /**
     * nodes nb
     */
    private int instNb = 0;

    /**
     * JONAS_ROOT
     */
    private String jonasRoot = null;

    /**
     * nodes name
     */
    private String clusterNodesName = null;

    /**
     * Destination directory prefix (used to create the jonasBase(s))
     */
    private String destDirPrefix = null;

    /**
     * Set the destination directory prefix
     * @param destDirPrefix the destination directory prefix
     */
    public void setDestDirPrefix(final String destDirPrefix) {
        this.destDirPrefix = destDirPrefix;
    }

    /**
     * Default constructor
     */
    public ClusterDaemon() {
        super();
    }

    /**
     * load the clusterd.xml file in a DOM structure
     */
    private void loadClusterDaemonXmlDoc() {

        if (!clusterDaemonDocLoaded) {

            // Load the orignal configuration file
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = null;
            try {
                factory.setNamespaceAware(true);
                docBuilder = factory.newDocumentBuilder();
            } catch (ParserConfigurationException e) {
                throw new BuildException(INFO + "Exception during loadClusterDaemonXmlDoc", e);
            }
            try {
                clusterDaemonDoc = docBuilder.parse(jonasRoot + File.separator + "templates" + File.separator + "conf"
                        + File.separator + "conf" + File.separator + CLUSTER_DAEMON_CONF_FILE);
            } catch (SAXException e) {
                throw new BuildException(INFO + "Error during parsing of the file " + CLUSTER_DAEMON_CONF_FILE, e);
            } catch (IOException e) {
                throw new BuildException(INFO + "Error during parsing of the file " + CLUSTER_DAEMON_CONF_FILE, e);
            }

            Element root = clusterDaemonDoc.getDocumentElement();

            // Remove the default servers list
            NodeList serverNodeL = root.getElementsByTagName("server");
            for (int i = 0; i < serverNodeL.getLength(); i++) {
                Node n = serverNodeL.item(i);
                root.removeChild(n);
            }

            // Prepare the serialization
            XMLSerializerTask xmlSerTask = new XMLSerializerTask();
            xmlSerTask.setXmlDoc(clusterDaemonDoc);
            xmlSerTask.setXmlFileName(CLUSTER_DAEMON_CONF_FILE);

            addTask(xmlSerTask);

            clusterDaemonDocLoaded = true;
        }
    }

    /**
     * Add the servers definition in the clusterd.xml
     */
    public void addServersDefinition() {

        // Load the orignal configuration file
        loadClusterDaemonXmlDoc();

        Element root = clusterDaemonDoc.getDocumentElement();

        for (int i = 1; i <= instNb; i++) {

            Text c = clusterDaemonDoc.createTextNode("\n\n  ");
            root.appendChild(c);

            // Element server
            Node s = clusterDaemonDoc.createElement("server");
            root.appendChild(s);

            Text c0 = clusterDaemonDoc.createTextNode("\n    ");
            s.appendChild(c0);

            // Element name
            Node sn = clusterDaemonDoc.createElement("name");
            s.appendChild(sn);

            Text tsn = clusterDaemonDoc.createTextNode(clusterNodesName + i);
            sn.appendChild(tsn);

            Text c1 = clusterDaemonDoc.createTextNode("\n    ");
            s.appendChild(c1);

            // Element description
            Node sd = clusterDaemonDoc.createElement("description");
            s.appendChild(sd);

            Text tsd = clusterDaemonDoc.createTextNode(clusterNodesName + i);
            sd.appendChild(tsd);

            Text c2 = clusterDaemonDoc.createTextNode("\n    ");
            s.appendChild(c2);

            // Element java-home
            Node sjdk = clusterDaemonDoc.createElement("java-home");
            s.appendChild(sjdk);

            Text tsjdk = clusterDaemonDoc.createTextNode(jdk);
            sjdk.appendChild(tsjdk);

            Text c3 = clusterDaemonDoc.createTextNode("\n    ");
            s.appendChild(c3);

            // Element jonas-root
            Node sjr = clusterDaemonDoc.createElement("jonas-root");
            s.appendChild(sjr);

            Text tsjr = clusterDaemonDoc.createTextNode(jonasRoot);
            sjr.appendChild(tsjr);

            Text c4 = clusterDaemonDoc.createTextNode("\n    ");
            s.appendChild(c4);

            // Element jonas-base
            Node sjb = clusterDaemonDoc.createElement("jonas-base");
            s.appendChild(sjb);
            String jb = destDirPrefix + i;

            if (File.separatorChar == '/') {
                jb = jb.replace('\\', File.separatorChar);
            } else {
                jb = jb.replace('/', File.separatorChar);
            }

            Text tsjb = clusterDaemonDoc.createTextNode(destDirPrefix + i);
            sjb.appendChild(tsjb);

            Text c5 = clusterDaemonDoc.createTextNode("\n    ");
            s.appendChild(c5);

            // Element xprm
            Node sxprm = clusterDaemonDoc.createElement("xprm");
            s.appendChild(sxprm);

            Text tsxprm = clusterDaemonDoc.createTextNode(xprm);
            sxprm.appendChild(tsxprm);

            Text c6 = clusterDaemonDoc.createTextNode("\n    ");
            s.appendChild(c6);

            // Element auto-boot
            Node sab = clusterDaemonDoc.createElement("auto-boot");
            s.appendChild(sab);

            Text tsab = clusterDaemonDoc.createTextNode(autoBoot);
            sab.appendChild(tsab);

            Text c7 = clusterDaemonDoc.createTextNode("\n  ");
            s.appendChild(c7);
        }
        Text c10 = clusterDaemonDoc.createTextNode("\n\n");
        root.appendChild(c10);

    }

    /**
     * update the name
     */
    public void updateName() {

        // Load the orignal configuration file
        loadClusterDaemonXmlDoc();

        Element root = clusterDaemonDoc.getDocumentElement();

        // update the name
        NodeList nameNodeL = root.getElementsByTagName("name");
        nameNodeL.item(0).getFirstChild().setNodeValue(name);

    }

    /**
     * update the domain name
     */
    public void updateDomainName() {

        // Load the orignal configuration file
        loadClusterDaemonXmlDoc();

        Element root = clusterDaemonDoc.getDocumentElement();

        // update the domain name
        NodeList nameNodeL = root.getElementsByTagName("domain-name");
        nameNodeL.item(0).getFirstChild().setNodeValue(domainName);

    }

    /**
     * update the interaction mode
     */
    public void updateInteractionMode() {

        // Load the orignal configuration file
        loadClusterDaemonXmlDoc();

        Element root = clusterDaemonDoc.getDocumentElement();

        // update the domain name
        NodeList nameNodeL = root.getElementsByTagName("jonas-interaction-mode");
        nameNodeL.item(0).getFirstChild().setNodeValue(interactionMode);

    }

    /**
     * Set nodes number
     * @param instNb nodes nb
     */
    public void setInstNb(final int instNb) {
        this.instNb = instNb;
    }

    /**
     * cluster daemon directory
     * @param cdDir directory
     */
    public void setCdDir(final String cdDir) {
        this.cdDir = cdDir;
        if (File.separatorChar == '/') {
            this.cdDir = this.cdDir.replace('\\', File.separatorChar);
        } else {
            this.cdDir = this.cdDir.replace('/', File.separatorChar);
        }
    }

    /**
     * Set the name
     * @param name name
     */
    public void setName(final String name) {
        this.name = name;
    }

    /**
     * Set the domain name
     * @param domainName domain name
     */
    public void setDomainName(final String domainName) {
        this.domainName = domainName;
    }

    /**
     * interaction mode
     * @param interactionMode loosely/tighly coupled
     */
    public void setInteractionMode(final String interactionMode) {
        this.interactionMode = interactionMode;
    }

    /**
     * jdk to use
     * @param jdk jdk
     */
    public void setJdk(final String jdk) {

        this.jdk = jdk;

        if (File.separatorChar == '/') {
            this.jdk = this.jdk.replace('\\', File.separatorChar);
        } else {
            this.jdk = this.jdk.replace('/', File.separatorChar);
        }
    }

    /**
     * port number
     * @param port port number
     */
    public void setPort(final String port) {
        this.port = port;
    }

    /**
     * set the protocol
     * @param protocol protocol
     */
    public void setProtocol(final String protocol) {
        this.protocol = protocol;
    }

    /**
     * Set JONAS_ROOT
     * @param jonasRoot JONAS_ROOT
     */
    public void setJonasRoot(final String jonasRoot) {
        this.jonasRoot = jonasRoot;

        if (File.separatorChar == '/') {
            this.jonasRoot = this.jonasRoot.replace('\\', File.separatorChar);
        } else {
            this.jonasRoot = this.jonasRoot.replace('/', File.separatorChar);
        }

    }

    /**
     * set the name prefix for the cluster nodes
     * @param clusterNodesName prefix of the nodes names in the cluster
     */
    public void setClusterNodesName(final String clusterNodesName) {
        this.clusterNodesName = clusterNodesName;
    }

    /**
     * Set auto boot
     * @param autoBoot true/false
     */
    public void setAutoBoot(final String autoBoot) {
        this.autoBoot = autoBoot;
    }

    /**
     * Set xprm
     * @param xprm xprm
     */
    public void setXprm(final String xprm) {
        this.xprm = xprm;
    }

    /**
     * update the carol.properties
     */
    public void updateCarol() {

        Carol carol = new Carol();
        carol.setDefaultPort(port);
        carol.setProtocols(protocol);
        this.tasks.add(carol);
    }

    /**
     * Generates the script tasks
     */
    public void generatesTasks() {

        updateDomainName();
        updateInteractionMode();
        addServersDefinition();
        updateCarol();

        // set destDir for each task
        for (Iterator it = this.getTasks().iterator(); it.hasNext();) {
            BaseTaskItf task = (BaseTaskItf) it.next();
            task.setDestDir(new File(cdDir));
        }
    }

    public void execute() {
        super.execute();
        this.generatesTasks();
        super.executeAllTask();
    }

}
