/*
 * $Header: /home/cvspublic/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/report/VersionTreeReport.java,v 1.10 2004/12/21 16:04:20 luetzkendorf Exp $
 * $Revision: 1.10 $
 * $Date: 2004/12/21 16:04:20 $
 *
 * ====================================================================
 *
 * 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.method.report;

import java.io.IOException;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;

import org.apache.slide.common.NamespaceAccessToken;
import org.apache.slide.common.PropertyParseException;
import org.apache.slide.common.RequestedProperties;
import org.apache.slide.common.RequestedPropertiesImpl;
import org.apache.slide.common.SlideException;
import org.apache.slide.common.SlideToken;
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.structure.ObjectNode;
import org.apache.slide.util.Configuration;
import org.apache.slide.util.XMLValue;
import org.apache.slide.webdav.WebdavServletConfig;
import org.apache.slide.webdav.util.DeltavConstants;
import org.apache.slide.webdav.util.PreconditionViolationException;
import org.apache.slide.webdav.util.UriHandler;
import org.apache.slide.webdav.util.VersioningHelper;
import org.apache.slide.webdav.util.ViolatedPrecondition;
import org.apache.slide.webdav.util.WebdavStatus;
import org.apache.slide.webdav.util.resourcekind.AbstractResourceKind;
import org.apache.slide.webdav.util.resourcekind.ResourceKind;
import org.apache.slide.webdav.util.resourcekind.Version;
import org.apache.slide.webdav.util.resourcekind.VersionControlled;
import org.apache.slide.webdav.util.resourcekind.VersionHistory;
import org.jdom.Element;
import org.jdom.JDOMException;

/**
 * DAV:version-tree report worker.
 *
 */
public class VersionTreeReport extends AbstractReport implements DeltavConstants {
    
    private RequestedProperties requestedProperties = null;
    private VersioningHelper versioningHelper = null;
    
    /**
     * Constructor
     *
     * @param    slideToken          a  SlideToken
     * @param    token               a  NamespaceAccessToken
     * @param    config              a  WebdavServletConfig
     * @param    servletPath         a String, the result of HttpRequest.getServletPath()
     * @param    contextPath         a  String , the result of HttpRequest.getContextPath()
     */
    public VersionTreeReport(SlideToken slideToken, NamespaceAccessToken token, WebdavServletConfig config, String slideContextPath) {
        super(slideToken, token, config, slideContextPath);
    }
    
    /**
     * Initialize report worker with specified report element
     *
     * @param    resourcePath        a  String
     * @param    versionTreeElm      an Element
     *
     * @throws   PreconditionViolationException
     */
    public void init(String resourcePath, Element versionTreeElm) throws PreconditionViolationException {
        List childrenList = versionTreeElm.getChildren(E_PROP, DNSP);
        if (childrenList.size() == 0) {
            return;
        }
        else if (childrenList.size() > 1) {
            throw new PreconditionViolationException(
                new ViolatedPrecondition("at-most-one-prop-element",
                                         WebdavStatus.SC_BAD_REQUEST,
                                         "the DAV:version-tree element must contain at most one DAV:prop element"),
                resourcePath
            );
        }
        
        Element propElm = (Element)childrenList.get(0);
        try {
            requestedProperties = new RequestedPropertiesImpl(propElm);
        }
        catch (PropertyParseException e) {
            throw new PreconditionViolationException(
                new ViolatedPrecondition("invalid-prop-element",
                                         WebdavStatus.SC_BAD_REQUEST,
                                         e.getMessage()),
                resourcePath
            );
        }
    }
    
    /**
     * Execute report and add results to given multistatus element
     *
     * @param    resourcePath        a  String
     * @param    multistatusElm      an Element
     * @param    depth               an int
     *
     * @throws   SlideException
     * @throws   IOException
     */
    public void execute(String resourcePath, Element multistatusElm, int depth) throws SlideException, IOException {
        if (depth < 0) {
            return;
        }
        writeReport(resourcePath, multistatusElm);
        ObjectNode onode = structure.retrieve(slideToken, resourcePath);
        Enumeration childrenEnum = structure.getChildren(slideToken, onode);
        while  (childrenEnum.hasMoreElements()) {
            ObjectNode cnode = (ObjectNode)childrenEnum.nextElement();
            execute(cnode.getUri(), multistatusElm, depth-1);
        }
    }
    
    public void setVersioningHelper(VersioningHelper versioningHelper) {
        this.versioningHelper = versioningHelper;
    }
    
    private void writeReport(String resourcePath, Element multistatusElm) throws SlideException {
        NodeRevisionDescriptors nrds = content.retrieve(slideToken, resourcePath);
        NodeRevisionDescriptor nrd = content.retrieve(slideToken, nrds);
        ResourceKind resourceKind =
            AbstractResourceKind.determineResourceKind(token, nrds, nrd);
        
        if (resourceKind instanceof VersionControlled) {
            resourcePath = versioningHelper.getUriOfAssociatedVR(resourcePath);
            nrds = content.retrieve(slideToken, resourcePath);
            nrd = content.retrieve(slideToken, nrds);
            resourceKind =
                AbstractResourceKind.determineResourceKind(token, nrds, nrd);
        }
        else if (resourceKind instanceof VersionHistory) {
            NodeProperty rootVersion = nrd.getProperty(PN_ROOT_VERSION);
            if (rootVersion != null) {
                XMLValue value;
                if (rootVersion.getValue() instanceof XMLValue) {
                    value = (XMLValue)rootVersion.getValue();
                } else {
                    try {
                        value = new XMLValue(rootVersion.getValue().toString());
                    } catch (JDOMException e) {
                        throw new SlideException("Could not parse DAV:root-version: "+nrds.getUri());
                    }
                }
                Iterator i = value.iterator();
                if (i.hasNext()) {
                    resourcePath = ((Element)i.next()).getText();
                }
            }
            resourcePath += "/";
            resourcePath += nrds.getInitialRevision();
            nrds = content.retrieve(slideToken, resourcePath);
            nrd = content.retrieve(slideToken, nrds);
            resourceKind =
                    AbstractResourceKind.determineResourceKind(token, nrds, nrd);
        }
        
        if ( Configuration.useVersionControl() && (resourceKind instanceof Version) ) {
            writeReport(nrds, slideToken, multistatusElm);
        }
        else {
            multistatusElm.addContent(getErrorResponse(resourcePath, WebdavStatus.SC_FORBIDDEN, C_SUPPORTED_REPORT));
        }
    }
    
    private void writeReport(NodeRevisionDescriptors nrds, SlideToken slideToken, Element multistatusElm) throws SlideException {
        // this is a versioned resource
        NodeRevisionDescriptor hNrd = content.retrieve(slideToken, nrds, NodeRevisionNumber.HIDDEN_0_0);
        NodeProperty versionSetProperty = hNrd.getProperty(PN_VERSION_SET);
        if ( (versionSetProperty != null) && (versionSetProperty.getValue() != null) ) {
            XMLValue xmlValue;
            try {
                xmlValue =  new XMLValue(versionSetProperty.getValue().toString());
            }
            catch (JDOMException e) {
                throw new SlideException("Could not parse DAV:version-set: "+nrds.getUri());
            }
            Iterator hrefIterator = xmlValue.iterator();
            
            NodeRevisionNumber currentNrn= null;
            UriHandler currentUh = null;
            String currentPath = null;
            
            while (hrefIterator.hasNext()) {
                currentPath = ((Element)hrefIterator.next()).getText();
                currentUh = UriHandler.getUriHandler(currentPath);
                currentNrn = new NodeRevisionNumber(currentUh.getVersionName());
                multistatusElm.addContent(getResponseElement(slideToken, currentPath, currentNrn, getRequestedVersionTreeProperties()));
            }
        }
    }
    
    private RequestedProperties getRequestedVersionTreeProperties() {
        if (requestedProperties == null) {
            requestedProperties = new RequestedPropertiesImpl();
        }
        return requestedProperties;
    }
}

