/*
 * $Header: /home/cvspublic/jakarta-slide/src/webdav/server/org/apache/slide/webdav/util/properties/CurrentuserPrivilegeSetProperty.java,v 1.3 2005/01/03 15:04:44 luetzkendorf Exp $
 * $Revision: 1.3 $
 * $Date: 2005/01/03 15:04:44 $
 *
 * ====================================================================
 *
 * Copyright 1999-2002 The Apache Software Foundation 
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package org.apache.slide.webdav.util.properties;

import java.util.Enumeration;

import org.apache.slide.common.NamespaceAccessToken;
import org.apache.slide.common.NamespaceConfig;
import org.apache.slide.common.PropertyName;
import org.apache.slide.common.ServiceAccessException;
import org.apache.slide.common.SlideException;
import org.apache.slide.common.SlideToken;
import org.apache.slide.common.Uri;
import org.apache.slide.content.NodeProperty;
import org.apache.slide.content.NodeRevisionDescriptor;
import org.apache.slide.content.NodeRevisionDescriptors;
import org.apache.slide.content.NodeRevisionNumber;
import org.apache.slide.content.RevisionDescriptorNotFoundException;
import org.apache.slide.content.NodeProperty.NamespaceCache;
import org.apache.slide.security.Security;
import org.apache.slide.structure.ActionNode;
import org.apache.slide.structure.ObjectNode;
import org.apache.slide.structure.ObjectNotFoundException;
import org.apache.slide.structure.Structure;
import org.apache.slide.util.XMLValue;
import org.apache.slide.webdav.util.AclConstants;
import org.apache.slide.webdav.util.WebdavContext;
import org.apache.slide.webdav.util.resourcekind.ResourceKind;
import org.jdom.Element;
import org.jdom.Namespace;


/**
 * Computes the ACL <code>current-user-privilege-set</code> property.
 */
public class CurrentuserPrivilegeSetProperty extends
        AbstractComputedProperty
{
    public PropertyName getPropertyName() {
        return AclConstants.PN_CURRENT_USER_PRIVILEGE_SET;
    }
    
    public Object computeValue(NamespaceAccessToken nsaToken,
            NodeRevisionDescriptors revisionDescriptors,
            NodeRevisionDescriptor revisionDescriptor, 
            ResourceKind resourceKind, WebdavContext context)
            throws SlideException
    {
        XMLValue xmlValue = new XMLValue();
        
        try {
            NamespaceConfig config = nsaToken.getNamespaceConfig();
            Structure structure = nsaToken.getStructureHelper();
            ObjectNode object =  structure.retrieve(context.getSlideToken(), 
                    revisionDescriptors.getUri());
    
            // check read-own-permissions permission
            Security security = nsaToken.getSecurityHelper();
            security.checkCredentials(context.getSlideToken(), object, 
                    config.getReadOwnPermissionsAction());
        
            String actionsPath = config.getActionsPath();
            Uri actionsPathUri = nsaToken.getUri(context.getSlideToken(), 
                    actionsPath);
            ObjectNode actionsPathNode = 
                actionsPathUri.getStore().retrieveObject(actionsPathUri);
            Enumeration actions = actionsPathNode.enumerateChildren();
            addGrantedActionsToPrivilegeSet(nsaToken, context.getSlideToken(),
                    xmlValue, object, actions);
        }
        catch (ServiceAccessException e) {
            throw e;
        }
        catch (SlideException e) {
            return xmlValue;
        }
        return xmlValue;
    }

    /**
     * Build a set of privileges a subject has for an object for use in the
     * result of <code>current-user-privilege-set</code> queries.
     * 
     * This method modifies <code>xmlValue</code>.
     * 
     * @param xmlValue The element to which to add the actions which have been
     *                 granted to the subject.
     * @param object The object for which to determine which actions have been
     *               granted.
     * @param actions The URIs (as <code>String</code>s) of the actions to
     *                check.
     */
    private void addGrantedActionsToPrivilegeSet(NamespaceAccessToken nsaToken,
            SlideToken sToken,
            XMLValue xmlValue, ObjectNode object, Enumeration actions) 
        throws ServiceAccessException, ObjectNotFoundException, 
        RevisionDescriptorNotFoundException 
    {
        while (actions.hasMoreElements()) {
            Uri aNodeUri = nsaToken.getUri(sToken, (String)actions.nextElement());
            ObjectNode oNode = aNodeUri.getStore().retrieveObject(aNodeUri);
            if (oNode.hasChildren()) {
                addGrantedActionsToPrivilegeSet(nsaToken, sToken, xmlValue, 
                        object, oNode.enumerateChildren());
            } else {
                ActionNode aNode = ActionNode.getActionNode(oNode.getUri());
                if (nsaToken.getSecurityHelper().hasPermission(sToken, object, aNode)) {
                    xmlValue.add(createPrivilege(aNode, aNodeUri));
                }
            }
        }
    }
    
    /**
     * Creates a <code>&lt;privilege&gt;</code> element containing an
     * element with the given <code>privilegeName</code>.
     *
     * @param      privilegeName  the name of the privilege.
     *
     * @return     the <code>&lt;privilege&gt;</code> element.
     * @throws ServiceAccessException
     * @throws RevisionDescriptorNotFoundException
     */
    private Element createPrivilege(ActionNode privilege, Uri privilegeUri) throws RevisionDescriptorNotFoundException, ServiceAccessException {
        return createPrivilege(privilege, true, privilegeUri);
    }
    
    /**
     * Creates a <code>&lt;privilege&gt;</code> element containing an
     * element with the given <code>privilegeName</code>.
     *
     * @param      privilegeName    the name of the privilege.
     * @param      useDavNamespace  if <code>true</code> the <code>DAV:</code>
     *                              namespace will be used for the contained element,
     *                              otherwise the slide namespace.
     *
     * @return     the <code>&lt;privilege&gt;</code> element.
     * @throws ServiceAccessException
     * @throws RevisionDescriptorNotFoundException
     */
    private Element createPrivilege(ActionNode privilege, boolean useDavNamespace, Uri privilegeUri) throws RevisionDescriptorNotFoundException, ServiceAccessException {
        NodeRevisionNumber latestRevisionNumber = privilegeUri.getStore().retrieveRevisionDescriptors(privilegeUri).getLatestRevision();
        NodeProperty privilegeNamespaceProperty = privilegeUri.getStore().retrieveRevisionDescriptor(privilegeUri, latestRevisionNumber).getProperty(AclConstants.PN_PRIVILEGE_NAMESPACE);
        Namespace privilegeNamespace = null;
        if (privilegeNamespaceProperty != null && privilegeNamespaceProperty.getValue() instanceof String) {
            privilegeNamespace = Namespace.getNamespace((String) privilegeNamespaceProperty.getValue());
        } else {
            privilegeNamespace = DNSP;
            if ( ! useDavNamespace ) {
                privilegeNamespace = NamespaceCache.SLIDE_NAMESPACE;
            }
        }
        Element privilegeElement = new Element(AclConstants.E_PRIVILEGE, 
                DNSP);
        Element privilegeNameElement = new Element(privilege.getPath().lastSegment(), privilegeNamespace);
        privilegeElement.addContent(privilegeNameElement);
        return privilegeElement;
    }
}
