/*
 * $Header: /home/cvspublic/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/MkredirectrefMethod.java,v 1.2 2005/02/25 17:03:52 luetzkendorf Exp $
 * $Revision: 1.2 $
 * $Date: 2005/02/25 17:03:52 $
 *
 * ====================================================================
 *
 * 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.Date;
import java.util.List;

import org.apache.slide.common.NamespaceAccessToken;
import org.apache.slide.common.ServiceAccessException;
import org.apache.slide.common.SlideException;
import org.apache.slide.content.NodeProperty;
import org.apache.slide.content.NodeRevisionDescriptor;
import org.apache.slide.structure.LinkedObjectNotFoundException;
import org.apache.slide.structure.ObjectAlreadyExistsException;
import org.apache.slide.structure.ObjectNotFoundException;
import org.apache.slide.structure.SubjectNode;
import org.apache.slide.util.Configuration;
import org.apache.slide.webdav.WebdavException;
import org.apache.slide.webdav.WebdavServletConfig;
import org.apache.slide.webdav.util.DeltavConstants;
import org.apache.slide.webdav.util.UriHandler;
import org.apache.slide.webdav.util.WebdavStatus;
import org.jdom.Element;
import org.jdom.JDOMException;


/**
 * MKCOL method.
 *
 * @author <a href="mailto:snmvaughan92@yahoo.com">Steve Vaughan</a>
 */
public class MkredirectrefMethod
    extends AbstractWebdavMethod
    implements DeltavConstants {
    
    
    // ----------------------------------------------------- Instance Variables
    
    
    /**
     * Redirect reference name.
     */
    protected String redirectRefName;
    
    /**
     * Redirect reference target.
     */
    protected String refTarget;
    
    /**
     * Redirect lifetime.
     */
    protected String redirectLifetime;
    
    /**
     * Constructor.
     *
     * @param token     the token for accessing the namespace
     * @param config    configuration of the WebDAV servlet
     */
    public MkredirectrefMethod(NamespaceAccessToken token,
                       WebdavServletConfig config) {
        super(token, config);
    }
    
    
    // ------------------------------------------------------ Protected Methods
    
    
    /**
     * Parse XML request.
     */
    protected void parseRequest()
        throws WebdavException {
        
        redirectRefName = requestUri;
        if (redirectRefName == null) {
            redirectRefName = "/";
        }

        if (req.getContentLength() > 0) {
           try {
               Element mkredirectrefElement = parseRequestContent(
                       E_MKREDIRECTREF);
                       
               // Parse the reference target.
               Element reftargetElement = mkredirectrefElement.getChild(
                       E_REFTARGET, DNSP);
               if (reftargetElement != null) {
                  refTarget = reftargetElement.getChildText("href", DNSP);
                  if (refTarget == null)
                     throw new JDOMException ("Required Element <" + E_HREF
                           + "> Missing");
               }
               else {
                  throw new JDOMException ("Required Element <" + E_REFTARGET
                          + "> Missing");
               }
               
               // Parse the optional lifetime of the redirect.
               Element redirectLifetimeElement = mkredirectrefElement.getChild(
                       E_REDIRECT_LIFETIME, DNSP);
               if (redirectLifetimeElement != null) {
                   List children = redirectLifetimeElement.getChildren();
                   if (children.isEmpty())
                       throw new JDOMException ("Required Element <"
                               + E_PERMANENT + "> or <" + E_TEMPORARY
                               + "> Missing");

                   Element child = (Element)children.get(0);
                   if (E_PERMANENT.equals(child.getName()))
                       redirectLifetime = NodeRevisionDescriptor.PERMANENT_LIFETIME;
                   else if (E_TEMPORARY.equals(child.getName()))
                       redirectLifetime = NodeRevisionDescriptor.TEMPORARY_LIFETIME;
                   else
                       throw new JDOMException ("Expected Element <"
                               + E_PERMANENT + "> or <" + E_TEMPORARY
                               + "> but found <" + child.getName() + ">");
               }
               else
                   redirectLifetime = NodeRevisionDescriptor.TEMPORARY_LIFETIME;
           }
           catch( Exception e ) {
               int statusCode = getErrorCode( e );
               sendError( statusCode, e );
               throw new WebdavException( statusCode );
           }
        }
        else {
            int statusCode = WebdavStatus.SC_BAD_REQUEST;
            sendError( statusCode, getClass().getName()+".missingRequestBody" );
            throw new WebdavException( statusCode );
        }
    }
    
    
    /**
     * Execute request.
     *
     * @exception WebdavException Bad request
     */
    protected void executeRequest() throws WebdavException, IOException {
        
        // Prevent dirty reads
        slideToken.setForceStoreEnlistment(true);
        NodeRevisionDescriptor revisionDescriptor = null;
        
        // check lock-null resources
        boolean isLockNull = false;
        try {
            revisionDescriptor =
                content.retrieve(slideToken, content.retrieve(slideToken,
                redirectRefName));
            isLockNull = isLockNull( revisionDescriptor );
        }
        catch (ServiceAccessException e) {
            int statusCode = getErrorCode((Exception)e);
            sendError( statusCode, e );
            throw new WebdavException( statusCode );
        }
        catch (SlideException e) {
            // ignore silently
        }
        
        if (revisionDescriptor == null) {
            revisionDescriptor =
                new NodeRevisionDescriptor(0);
        }
        
        // check destination URI
        UriHandler destinationUriHandler = UriHandler.getUriHandler(redirectRefName);
        if (destinationUriHandler.isRestrictedUri()) {
            int statusCode = WebdavStatus.SC_FORBIDDEN;
            sendError( statusCode, getClass().getName()+".restrictedDestinationUri", new Object[]{redirectRefName} );
            throw new WebdavException( statusCode );
        }
        
        // Resource type
        revisionDescriptor.setResourceType(NodeRevisionDescriptor.REDIRECTREF_TYPE);
        
        // Reference target
        revisionDescriptor.setRefTarget(refTarget);
        
        // Redirect lifetime
        revisionDescriptor.setRedirectLifetime(redirectLifetime);
        
        // Creation date
        Date creationDate = new Date();
        revisionDescriptor.setCreationDate(creationDate);
        
        // Last modification date
        revisionDescriptor.setLastModified(creationDate);
        
        // Content length name
        revisionDescriptor.setContentLength(0);
        
        // Source
        revisionDescriptor.setSource("");
        
        // Owner
        try {
            String creator = ((SubjectNode)security.getPrincipal(slideToken)).getPath().lastSegment();
            revisionDescriptor.setCreationUser(creator);
            revisionDescriptor.setOwner(creator);
        } catch (Exception e) {
            int statusCode = getErrorCode( e );
            sendError( statusCode, e );
            throw new WebdavException( statusCode );
        }
        
        // Added for DeltaV --start--
        if( Configuration.useVersionControl() ) {
            // Workspace
            versioningHelper.setWorkspaceProperty(redirectRefName, revisionDescriptor);
        }
        // Added for DeltaV --end--
        
        if (isMsProprietarySupport()) {
            
            NodeProperty property = null;
            
            // Is hidden
            property = new NodeProperty("ishidden", "0", "MICROSOFT");
            revisionDescriptor.setProperty(property);
            
            // Is read only
            property = new NodeProperty("isreadonly", "0", "MICROSOFT");
            revisionDescriptor.setProperty(property);
            
            // Last accessed
            property = new NodeProperty("lastaccessed",
                                            (creationDate).toString(), "MICROSOFT");
            revisionDescriptor.setProperty(property);
            
        }
        
        // If everything is ok : 201 - Created / OK
        resp.setStatus(WebdavStatus.SC_CREATED);
        
        try {
            if (!isLockNull) {
                SubjectNode collection = new SubjectNode();
                structure.create(slideToken, collection, redirectRefName);
                content.create(slideToken, redirectRefName, revisionDescriptor, null);
            }
            else {
                content.store(slideToken, redirectRefName, revisionDescriptor, null);
            }
        } catch (Exception e) {
            int statusCode = getErrorCode( e );
            sendError( statusCode, e );
            throw new WebdavException( statusCode );
        }
        
        // 507 - Insufficient storage
        // Would be returned as a ServiceAccessException, so it would
        // return an Internal Server Error, which is probably acceptable.
    }
    
    
    /**
     * Get return status based on exception type.
     */
    protected int getErrorCode(Exception ex) {
        try {
            throw ex;
        } catch (ObjectNotFoundException e) {
            return WebdavStatus.SC_CONFLICT;
        } catch (LinkedObjectNotFoundException e) {
            return WebdavStatus.SC_NOT_FOUND;
        } catch (ObjectAlreadyExistsException e) {
            return WebdavStatus.SC_METHOD_NOT_ALLOWED;
        } catch (Exception e) {
            return super.getErrorCode(e);
        }
        
    }
    
    
    
    /**
     * Returns true
     */
    protected boolean methodNeedsTransactionSupport() {
        return true;
    }
    
    
}

