/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2005 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
 *
 * Inital Developer : Matt Wringe
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.generators.wsgen.generator;

import org.ow2.jonas.generators.wsgen.ddmodifier.ContextDDModifier;
import org.ow2.jonas.generators.wsgen.ddmodifier.WebJettyDDModifier;
import org.ow2.jonas.generators.wsgen.ddmodifier.WsEndpointDDModifier;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;


/**
 * Generates the necessary security files to the generated
 * webapp for a stateless session bean endpoint.
 *
 * @author Matt Wringe
 */
public class SecurityGenerator {

    /**
     * Document that contains the security configurations to be used
     */
    private Document securityDesc = null;

    /**
     * WsEndpointDDModifier used to add security settings to the web.xml
     */
    private WsEndpointDDModifier wsddm = null;

    /**
     * ContextDDModifier used to add Realm settings to the context.xml
     */
    private ContextDDModifier cddm = null;

    /**
     * WebJettyDDModifuer used to add Realm settings to web-jetty.xml
     */
    private WebJettyDDModifier wjddm = null;

    /**
     * The name of the node in securityDesc that contains the login-config settings
     */
    private static final String LOGIN_CONFIG = "endpoint-login-config";

    /**
     * The name of the node in securityDesc that contains the security-constraint settings
     */
    private static final String SECURITY_CONSTRAINT = "endpoint-security-constraint";

    /**
     * The name of the node that contains the realm
     */
    private static final String REALM = "endpoint-realm";

    /**
     * The name of the node that contains the name of the realm
     */
    private static final String REALM_NAME = "endpoint-realm-name";

    /**
     * The name of the node that contains the security role
     */
    private static final String SECURITY_ROLE = "endpoint-security-role";

    /**
     * The realm the webapp should use
     */
    private String realm = null;

    /**
     * The name of the realm that the webapp should use
     */
    private String realmName = null;


    /**
     * Creates a new SecurityGenerator object
     * @param securityDesc Dom Document that contains the security settings
     */
    public SecurityGenerator(final Document securityDesc) {
        this.securityDesc = securityDesc;
    }

    /**
     * Generates the security settings specified in securityDesc document
     *
     * @param ddm    Used to add security to the web.xml
     * @param cddm   Used to add a security realm to the context.xml
     * @param wjddm  Used to add a security realn to the web-jetty.xml
     */
    public void generate(final WsEndpointDDModifier ddm, final ContextDDModifier cddm, final WebJettyDDModifier wjddm) {
        this.wsddm = ddm;
        this.cddm = cddm;
        this.wjddm = wjddm;

        if (securityDesc != null) {

            realm = getRealm();
            realmName = getRealmName();

            if (ddm != null) {
                addEndpointSecurity();
            }
            if (cddm != null) {
                addContextRealm();
            }
            // Do not add the realm in web-jetty.xml (already in jetty6.xml)
            // TODO has to be refined
            /*
            if (wjddm != null) {
                addWebJettyRealm();
            }
            */
        }
    }


    /**
     * Add realm settings to the context.xml
     *
     */
    private void addContextRealm() {
        if (realm != null) {
            cddm.addContextRealm(realm);
        }
    }

    /**
     * Add realm settings to web-jetty.xml
     *
     */
    private void addWebJettyRealm() {
        if (realm != null) {
            if (realmName != null) {
                wjddm.configRealm(realmName, realm);
            } else {
                wjddm.configRealm(realm);
            }
        }
    }

    /**
     * Setup the web security in the web.xml
     *
     */
    private void addEndpointSecurity() {

        //Add the security constraints
        NodeList securityConstraints = getEndpointSecurityConstraints();
        if (securityConstraints != null) {
            for (int i = 0; i < securityConstraints.getLength(); i++) {
                //remove the j2ee prefix of this node
                removePrefix(securityConstraints.item(i));
                wsddm.addEndpointSecurityConstraint(securityConstraints.item(i));
            }
        }

        //Add the login configs
        NodeList loginConfigs = getEndpointLoginConfig();
        if (loginConfigs != null) {
            for (int i = 0; i < loginConfigs.getLength(); i++) {
                //remove the j2ee prefix from this node
                removePrefix(loginConfigs.item(i));
                wsddm.addEndpointLoginConfig((Element) loginConfigs.item(i));
            }
        }

        //Add the security roles
        NodeList securityRoles = getEndpointSecurityRole();
        if (securityRoles != null) {
            for (int i = 0; i < securityRoles.getLength(); i++) {
                //remove the j2ee prefix from thie node
                removePrefix(securityRoles.item(i));
                wsddm.addSecurityRole(securityRoles.item(i));
            }
        }
    }

    /**
     * Returns the DocumentElement for the securityDesc document
     *
     * @return DocumentElement for the securityDesc document
     */
    private Element getElement() {
        return securityDesc.getDocumentElement();
    }

    /**
     * Returns the login-config nodes from the securityDesc document
     * @return the login-config nodes from the securityDesc document
     */
    public NodeList getEndpointLoginConfig() {
        NodeList nodeList = getElement().getElementsByTagName(LOGIN_CONFIG);
        return nodeList;
    }

    /**
     * Returns the security-constraint nodes from the securityDesc document
     *
     * @return the security-constraint nodes from the securityDesc document
     */
    public NodeList getEndpointSecurityConstraints() {
        NodeList nodeList = getElement().getElementsByTagName(SECURITY_CONSTRAINT);
        return nodeList;
    }

    /**
     * Returns the security-role nodes from the securityDesc document
     *
     * @return the security-role nodes from the securityDesc document
     */
    public NodeList getEndpointSecurityRole() {
        NodeList nodeList = getElement().getElementsByTagName(SECURITY_ROLE);
        return nodeList;
    }

    /**
     * Returns the context-realm node from the securityDesc document
     *
     * @return the realm node from the securityDesc document
     */
    public String getRealm() {
        NodeList nodeList = getElement().getElementsByTagName(REALM);
        Node node = nodeList.item(0);

        if (node != null && node.hasChildNodes()) {
            Node realmNode = nodeList.item(0).getFirstChild();
            realm = realmNode.getNodeValue();
        }
        return realm;
    }

    /**
     * Returns the realm name
     *
     * @return the realm name
     */
    public String getRealmName() {
        String realmName = null;
        NodeList nodeList = getElement().getElementsByTagName(REALM_NAME);
        Node node = nodeList.item(0);

        if (node != null && node.hasChildNodes()) {
            Node realmNameNode = nodeList.item(0).getFirstChild();
            realmName = realmNameNode.getNodeValue();
        }
        return realmName;
    }

    /**
     * Returns the Document that contains the security settings
     *
     * @return Document that contains the security settings
     */
    public Document getSecurityDesc() {
        return securityDesc;
    }

    /**
     * Removes the prefix from all the children of a node
     *
     * @param node Node
     */
    private void removePrefix (final Node node) {
        if (node != null) {
            if (node.getPrefix() != null) {
               node.setPrefix(null);
            }
            if (node.hasChildNodes()) {
                for (int i = 0; i < node.getChildNodes().getLength(); i++) {
                    removePrefix (node.getChildNodes().item(i));
                }
            }
        }
    }

}