/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 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
 *
 * Initial developer: Florent BENOIT
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.deployment.web;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * Defines the methods class managing all http methods
 * @author Florent Benoit
 */
public class MethodsDesc {

    /**
     * List of Methods
     */
    private Map httpMethods = null;

    /**
     * Available HTTP METHODS
     */
    public static final String[] METHODS = new String[] {
        "DELETE", "GET", "HEAD", "OPTIONS", "POST", "PUT", "TRACE"
    };

    /**
     * Constructor
     * Build new Http Methods
     */
    public MethodsDesc() {
        httpMethods = new HashMap();
        for (int m = 0; m < METHODS.length; m++) {
            httpMethods.put(METHODS[m], new MethodDesc(METHODS[m]));
        }
    }

    /**
     * Add Http methods (Excluded or Unchecked)
     * @param methods array of methods to add
     * @param transportGuarantee Transport Guarantee for these methods
     * @param isExcluded if true add methods as excluded
     */
    public void addMethods(final String[] methods, final String transportGuarantee, final boolean isExcluded) {
        MethodDesc method = null;
        for (int m = 0; m < methods.length; m++) {
            method = getMethod(methods[m]);
            method.addTransportGuarantee(transportGuarantee);
            if (isExcluded) {
                method.setExcluded();
            }
        }
    }

    /**
     * Add pattern information for a given role
     * @param methods methods to add to the given role
     * @param role role which have the given methods
     * @param transportGuarantee Transport Guarantee for these methods
     */
    public void addMethodsOnRole(final String[] methods, final String role, final String transportGuarantee) {
        for (int m = 0; m < methods.length; m++) {
            getMethod(methods[m]).addRole(role, transportGuarantee);
            getMethod(methods[m]).setUnchecked(false);
        }
    }


    /**
     * Gets the method object
     * @param methodName name of the method
     * @return Method object
     */
    private MethodDesc getMethod(final String methodName) {
        MethodDesc m = (MethodDesc) httpMethods.get(methodName.toUpperCase());
        // If method not found, add it as an extended method
        if (m == null) {
            m = new MethodDesc(methodName);
            httpMethods.put(methodName, m);
        }
        return m;
    }



    /**
     * Gets the excluded actions in order to build permissions
     * @return actions in order to build permissions
     */
    public String getExcludedActions() {
        StringBuffer actions = new StringBuffer();
        MethodDesc method = null;
        for (Iterator it = httpMethods.values().iterator(); it.hasNext();) {
            method = (MethodDesc) it.next();
            if (method.isExcluded()) {
                // first item or append item ?
                if (actions.length() > 0) {
                    actions.append(",");
                }
                actions.append(method.getName());
            }
        }
        return actions.toString();
    }


    /**
     * Gets the unchecked actions in order to build permissions
     * @return actions in order to build permissions
     */
    public String getUncheckedActions() {
        StringBuffer actions = new StringBuffer();
        MethodDesc method = null;
        for (Iterator it = httpMethods.values().iterator(); it.hasNext();) {
            method = (MethodDesc) it.next();
            if (!method.isUnchecked()) {
                // first item or append item ?
                if (actions.length() > 0) {
                    actions.append(",");
                }
                actions.append(method.getName());
            }
        }
        // Contains no actions
        if (actions.length() == 0) {
            return null;
        } else {
            // Return a list of HTTP method exception
            return "!".concat(actions.toString());
        }
    }

    /**
     * Gets the Map between roles and their actions
     * @return map between roles and their actions in order to build permissions
     */
    public Map getRoleMapActions() {
        MethodDesc method = null;
        Map rolesMap = new HashMap();
        for (Iterator it = httpMethods.values().iterator(); it.hasNext();) {
            method = (MethodDesc) it.next();
            if (method.hasRole()) {
                for (Iterator itRoles = method.getRolesIterator(); itRoles.hasNext();) {

                    String roleName = (String) itRoles.next();
                    String actions = (String) rolesMap.get(roleName);
                    if (actions == null) {
                        actions = method.getName();
                    } else {
                        actions += ",";
                        actions += method.getName();
                    }
                    rolesMap.put(roleName, actions);
                }
            }
        }
        return rolesMap;
    }


    /**
     * Gets the list of unchecked permissions for all element
     * that do not contain an excluding auth-constraint
     * @see 3.1.3.1 WebUserDataPermission for excluding auth constraint
     * @return list of actions for WebUserData permissions
     */
    public List getUncheckedWebUserDataActionsRoleList() {

        MethodDesc method = null;
        // Temporary list.
        StringBuffer nones = null;
        StringBuffer confidentials = null;
        StringBuffer integrals = null;

        // Build unchecked actions
        for (Iterator it = httpMethods.values().iterator(); it.hasNext();) {
            method = (MethodDesc) it.next();
            String methodName = method.getName();
            // Only if not contain an excluding auth-constraint
            if (!method.isExcluded() && method.hasRole()) {
                // Add NONE for each method found
                if (method.getTransportGuarantee().hasNone()) {
                    if (nones == null) {
                        nones = new StringBuffer(methodName);
                    } else {
                        nones.append(",");
                        nones.append(methodName);
                    }
                }
                // Add INTEGRAL on method if it is the case
                if (method.getTransportGuarantee().isIntegral()) {
                    if (integrals == null) {
                        integrals = new StringBuffer(methodName);
                    } else {
                        integrals.append(",");
                        integrals.append(methodName);
                    }
                }

                // Add CONFIDENTIAL on method if it is the case
                if (method.getTransportGuarantee().isConfidential()) {
                    if (confidentials == null) {
                        confidentials = new StringBuffer(methodName);
                    } else {
                        confidentials.append(",");
                        confidentials.append(methodName);
                    }
                }
            }
        }

        // Now there are 3 StringBuffer (which can be null) with all the actions
        // by transport Guarantee
        // Build the list of actions with adding transport guarantee name.

        List unchecked = new ArrayList();
        if (nones != null) {
            // Including no user-data-constraint
            unchecked.add((String) null);
        }
        if (integrals != null) {
            integrals.append(":");
            integrals.append(TransportGuaranteeDesc.INTEGRAL_TRANSPORT);
            unchecked.add(integrals.toString());
        }
        if (confidentials != null) {
            confidentials.append(":");
            confidentials.append(TransportGuaranteeDesc.CONFIDENTIAL_TRANSPORT);
            unchecked.add(confidentials.toString());
        }

        return unchecked;
    }



}
