/*
 * $Header: /home/cvspublic/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/OptionsMethod.java,v 1.49 2004/12/06 08:54:13 masonjm Exp $
 * $Revision: 1.49 $
 * $Date: 2004/12/06 08:54:13 $
 *
 * ====================================================================
 *
 * 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;

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

import org.apache.slide.common.NamespaceAccessToken;
import org.apache.slide.common.SlideException;
import org.apache.slide.content.NodeRevisionDescriptor;
import org.apache.slide.content.NodeRevisionDescriptors;
import org.apache.slide.event.EventDispatcher;
import org.apache.slide.search.SearchLanguage;
import org.apache.slide.util.Configuration;
import org.apache.slide.webdav.WebdavException;
import org.apache.slide.webdav.WebdavServletConfig;
import org.apache.slide.webdav.event.WebdavEvent;
import org.apache.slide.webdav.util.AclConstants;
import org.apache.slide.webdav.util.BindConstants;
import org.apache.slide.webdav.util.DeltavConstants;
import org.apache.slide.webdav.util.HistoryPathHandler;
import org.apache.slide.webdav.util.UriHandler;
import org.apache.slide.webdav.util.WebdavStatus;
import org.apache.slide.webdav.util.WorkspacePathHandler;
import org.apache.slide.webdav.util.resourcekind.AbstractResourceKind;
import org.apache.slide.webdav.util.resourcekind.ResourceKind;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.output.XMLOutputter;


/**
 * OPTIONS Method.
 *
 */
public class OptionsMethod extends AbstractWebdavMethod
    implements DeltavConstants, AclConstants, BindConstants, ReadMethod, FineGrainedLockingMethod {
    
    // An XML outputter
    private XMLOutputter xmlOut;
    //  private Namespace xmlNs = Namespace.getNamespace(DEFAULT_NAMESPACE);
    
    // the collections which may contain VH or workspace resources are requested
    private boolean versionHistoryCollectionSetRequested = false;
    private boolean workspaceCollectionSetRequested = false;
    private boolean responseBodyNeeded = false;
    
    // ----------------------------------------------------------- Constructors
    
    
    /**
     * Constructor.
     *
     * @param token     the token for accessing the namespace
     * @param config    configuration of the WebDAV servlet
     */
    public OptionsMethod(NamespaceAccessToken token,
                         WebdavServletConfig config) {
        super(token, config);
        org.jdom.output.Format format = org.jdom.output.Format.getPrettyFormat();
        format.setIndent(XML_RESPONSE_INDENT);
        xmlOut = new XMLOutputter(format);
    }
    
    /**
     * @see org.apache.slide.webdav.method.FineGrainedLockingMethod#acquireFineGrainLocks()
     */
    public void acquireFineGrainLocks() {
        String resourceUri = requestUri;
        if (resourceUri == null) {
            resourceUri = "/";
        }

        acquireStandardLocks(resourceUri);
    }

    protected void parseRequest() throws WebdavException {
        
        if( req.getContentLength() > 0 || isRequestChunked()) {
            try {
                Iterator i = parseRequestContent(E_OPTIONS).getChildren().iterator();
                while( i.hasNext() ) {
                    Element e = (Element)i.next();
                    if( e.getName().equals(E_VERSION_HISTORY_COLLECTION_SET) )
                        versionHistoryCollectionSetRequested = true;
                    if( e.getName().equals(E_WORKSPACE_COLLECTION_SET) )
                        workspaceCollectionSetRequested = true;
                }
                if( versionHistoryCollectionSetRequested || workspaceCollectionSetRequested )
                    responseBodyNeeded = true;
            }
            catch(JDOMException e ){
                int statusCode = WebdavStatus.SC_BAD_REQUEST;
                sendError( statusCode, e );
                throw new WebdavException( statusCode );
            }
            catch( IOException e ){
                int statusCode = WebdavStatus.SC_INTERNAL_SERVER_ERROR;
                sendError( statusCode, e );
                throw new WebdavException( statusCode );
            }
        }
    }
    
    protected void executeRequest() throws WebdavException {
        
        /*
         We have been experiencing a strange behaviour with the *creation* of a
         Microsoft webfolder. When the DAV: header of an OPTIONS response
         becomes too long, an <The folder you entered does not appear to be
         valid. Please choose another.> error occurs.
         
         As a workaround we break-up the DAV: header into multiple DAV: header
         lines.
         */
        
        StringBuffer davHeader = new StringBuffer();
        davHeader.append( F_WEBDAV );
        
        if( Configuration.useIntegratedLocking() )
            davHeader.append( ", " ).append( F_LOCKING );
        
        davHeader.append( ", " ).append( F_SLIDE );
        
        if( Configuration.useIntegratedSecurity() )
            davHeader.append( ", " ).append( F_ACCESS_CONTROL );
        
        if( Configuration.useGlobalBinding() )
            davHeader.append( ", " ).append( F_BINDING );
        
        if (Configuration.useRedirectReferences())
            davHeader.append(", ").append(F_REDIRECTREFS);
        
        resp.addHeader( "DAV", davHeader.toString() );
        
        if( Configuration.useVersionControl() ) {
            davHeader = new StringBuffer();
            davHeader.append( F_VERSION_CONTROL );
            davHeader.append( ", " ).append( F_VERSION_HISTORY );
            davHeader.append( ", " ).append( F_CHECKOUT_IN_PLACE );
            resp.addHeader( "DAV", davHeader.toString() );
            
            davHeader = new StringBuffer();
            davHeader.append( F_WORKSPACE );
            davHeader.append( ", " ).append( F_WORKING_RESOURCE );
            davHeader.append( ", " ).append( F_UPDATE );
            davHeader.append( ", " ).append( F_LABEL );
            resp.addHeader( "DAV", davHeader.toString() );
        }
        
        String resourceUri = requestUri;
        if (resourceUri == null) {
            resourceUri = "/";
        }
        
        // prepare for allow-header
        boolean resourceExists = false;
        //boolean resourceIsCollection = false;
        SearchLanguage[] languages =
            token.getSearchHelper().getSupportedLanguages ();
        
        ResourceKind resourceKind = null;
        try {
            if ( WebdavEvent.OPTIONS.isEnabled() ) EventDispatcher.getInstance().fireVetoableEvent(WebdavEvent.OPTIONS, new WebdavEvent(this));

            NodeRevisionDescriptors revisionDescriptors =
                content.retrieve(slideToken, resourceUri);
            NodeRevisionDescriptor revisionDescriptor =
                content.retrieve(slideToken, revisionDescriptors);
            resourceKind = AbstractResourceKind.determineResourceKind(token, revisionDescriptors, revisionDescriptor);
            resourceExists = true;
            //if( WebdavUtils.isCollection(revisionDescriptor) )
                //resourceIsCollection = true;
        } catch (SlideException e) {
            if (resourceUri.equals("/")) {
                resourceExists = true;
                //resourceIsCollection = true;
            } else {
                resourceExists = false;
            }
        }
        
        // build allow-header
        StringBuffer methodsAllowed = new StringBuffer();
        if( resourceKind != null ) {
            Iterator methodIterator = resourceKind.getSupportedMethods().iterator();
            while (methodIterator.hasNext()) {
                methodsAllowed.append((String)methodIterator.next());
                methodsAllowed.append(", ");
            }
            if (methodsAllowed.length() > 1) {
                methodsAllowed.setLength(methodsAllowed.length()-2);
            }
        }
        else {
            methodsAllowed.append( "OPTIONS, MKCOL, PUT" );
            if( Configuration.useIntegratedLocking() )
                methodsAllowed.append( ", LOCK" );
            if (Configuration.useRedirectReferences())
                methodsAllowed.append(", MKREDIRECTREF");
        }
        
        resp.addHeader("Allow", methodsAllowed.toString());
        
        if (Configuration.useSearch () && languages != null && resourceExists)
            for (int i = 0; i < languages.length; i++)
                resp.addHeader ("DASL", "<" + languages [i].getGrammarUri() +
                                    languages [i].getName () + ">");
        
        resp.addHeader("MS-Author-Via", "DAV");
        
        // build response body if needed
        if( responseBodyNeeded ) {
            resp.setContentType( TEXT_XML_UTF_8 );
            UriHandler uh = UriHandler.getUriHandler( resourceUri );
            String storeName = uh.getAssociatedBaseStoreName(token.getName());
            UriHandler hpath = HistoryPathHandler.getHistoryPathHandler();
            UriHandler wspath = WorkspacePathHandler.getWorkspacePathHandler();
            Element ore =
                new Element( E_OPTIONS_RESPONSE, DNSP );
            if( versionHistoryCollectionSetRequested ) {
                Element vhcse =
                    new Element( E_VERSION_HISTORY_COLLECTION_SET, DNSP );
                Iterator i = ((HistoryPathHandler)hpath).getResolvedHistoryPaths(storeName).iterator();
                while( i.hasNext() ) {
                    Element hre =
                        new Element( E_HREF,DNSP );
                    hre.addContent( getFullPath(String.valueOf(i.next())) );
                    vhcse.addContent( hre );
                }
                ore.addContent( vhcse );
            }
            if( workspaceCollectionSetRequested ) {
                Element wscse =
                    new Element( E_WORKSPACE_COLLECTION_SET, DNSP );
                Iterator i = ((WorkspacePathHandler)wspath).getResolvedWorkspacePaths(storeName).iterator();
                while( i.hasNext() ) {
                    Element hre =
                        new Element( E_HREF, DNSP );
                    hre.addContent( getFullPath(String.valueOf(i.next())) );
                    wscse.addContent( hre );
                }
                ore.addContent( wscse );
            }
            try {
                xmlOut.output(new Document(ore), resp.getWriter());
            }
            catch( IOException e ) {
                int statusCode = WebdavStatus.SC_INTERNAL_SERVER_ERROR;
                sendError( statusCode, e );
                throw new WebdavException( statusCode );
            }
        }
    }
}
