/*
 * Copyright 2004 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.modeshape.webdav;

import java.io.InputStream;
import java.security.Principal;
import java.util.List;
import java.util.Map;
import org.modeshape.webdav.exceptions.WebdavException;

/**
 * Interface for simple implementation of any store for the WebdavServlet
 * <p>
 * based on the BasicWebdavStore from Oliver Zeigermann, that was part of the
 * Webdav Construcktion Kit from slide
 */
public interface IWebdavStore {

    /**
     * Life cycle method, called by WebdavServlet's destroy() method. Should be used to clean up resources.
     */
    void destroy();

    /**
     * Indicates that a new request or transaction with this store involved has
     * been started. The request will be terminated by either {@link #commit(ITransaction)}
     * or {@link #rollback(ITransaction)}. If only non-read methods have been called, the
     * request will be terminated by a {@link #commit(ITransaction)}. This method will be
     * called by (@link WebdavStoreAdapter} at the beginning of each request.
     *
     * @param principal the principal that started this request or <code>null</code> if
     * there is non available
     * @throws WebdavException
     * @return a new {@link ITransaction transaction}
     */
    ITransaction begin( Principal principal );

    /**
     * Checks if authentication information passed in is valid. If not throws an
     * exception.
     *
     * @param transaction indicates that the method is within the scope of a WebDAV
     * transaction
     */
    void checkAuthentication( ITransaction transaction );

    /**
     * Indicates that all changes done inside this request shall be made
     * permanent and any transactions, connections and other temporary resources
     * shall be terminated.
     *
     * @param transaction indicates that the method is within the scope of a WebDAV
     * transaction
     * @throws WebdavException if something goes wrong on the store level
     */
    void commit( ITransaction transaction );

    /**
     * Indicates that all changes done inside this request shall be undone and
     * any transactions, connections and other temporary resources shall be
     * terminated.
     *
     * @param transaction indicates that the method is within the scope of a WebDAV
     * transaction
     * @throws WebdavException if something goes wrong on the store level
     */
    void rollback( ITransaction transaction );

    /**
     * Creates a folder at the position specified by <code>folderUri</code>.
     *
     * @param transaction indicates that the method is within the scope of a WebDAV
     * transaction
     * @param folderUri URI of the folder
     * @throws WebdavException if something goes wrong on the store level
     */
    void createFolder( ITransaction transaction,
                       String folderUri );

    /**
     * Creates a content resource at the position specified by
     * <code>resourceUri</code>.
     *
     * @param transaction indicates that the method is within the scope of a WebDAV
     * transaction
     * @param resourceUri URI of the content resource
     * @throws WebdavException if something goes wrong on the store level
     */
    void createResource( ITransaction transaction,
                         String resourceUri );

    /**
     * Gets the content of the resource specified by <code>resourceUri</code>.
     *
     * @param transaction indicates that the method is within the scope of a WebDAV
     * transaction
     * @param resourceUri URI of the content resource
     * @return input stream you can read the content of the resource from
     * @throws WebdavException if something goes wrong on the store level
     */
    InputStream getResourceContent( ITransaction transaction,
                                    String resourceUri );

    /**
     * Sets / stores the content of the resource specified by
     * <code>resourceUri</code>.
     *
     * @param transaction indicates that the method is within the scope of a WebDAV
     * transaction
     * @param resourceUri URI of the resource where the content will be stored
     * @param content input stream from which the content will be read from
     * @param contentType content type of the resource or <code>null</code> if unknown
     * @param characterEncoding character encoding of the resource or <code>null</code> if unknown
     * or not applicable
     * @return lenght of resource
     * @throws WebdavException if something goes wrong on the store level
     */
    long setResourceContent( ITransaction transaction,
                             String resourceUri,
                             InputStream content,
                             String contentType,
                             String characterEncoding );

    /**
     * Gets the names of the children of the folder specified by
     * <code>folderUri</code>.
     *
     * @param transaction indicates that the method is within the scope of a WebDAV
     * transaction
     * @param folderUri URI of the folder
     * @return a (possibly empty) list of children, or <code>null</code> if the
     *         uri points to a file
     * @throws WebdavException if something goes wrong on the store level
     */
    String[] getChildrenNames( ITransaction transaction,
                               String folderUri );

    /**
     * Gets the length of the content resource specified by
     * <code>resourceUri</code>.
     *
     * @param transaction indicates that the method is within the scope of a WebDAV
     * transaction
     * @param resourceUri URI of the resource for which the length should be retrieved
     * @return length of the resource in bytes, <code>-1</code> declares this
     *         value as invalid and asks the adapter to try to set it from the
     *         properties if possible
     * @throws WebdavException if something goes wrong on the store level
     */
    long getResourceLength( ITransaction transaction,
                            String resourceUri );

    /**
     * Removes the object specified by <code>uri</code>.
     *
     * @param transaction indicates that the method is within the scope of a WebDAV
     * transaction
     * @param uri URI of the object, i.e. content resource or folder
     * @throws WebdavException if something goes wrong on the store level
     */
    void removeObject( ITransaction transaction,
                       String uri );

    /**
     * Gets the storedObject specified by <code>uri</code>
     *
     * @param transaction indicates that the method is within the scope of a WebDAV
     * transaction
     * @param uri URI
     * @return StoredObject
     */
    StoredObject getStoredObject( ITransaction transaction,
                                  String uri );

    /**
     * Updates the custom properties on the given resource. NOTE: Nested properties are <b>not</b> supported

     * @param transaction the {@link org.modeshape.webdav.ITransaction} within which the operation takes place; may not be null
     * @param resourceUri the URI of the object on which the properties should be updated; may not be null
     * @param propertiesToSet a map of (propertyName, propertyValue) pairs which should be set on the object; may not be null;
     * If the name of a property contains a namespace, it is expected to be in the [namespaceUri]:[localPropertyName] format.
     * @param propertiesToRemove a set of property name representing the properties which should be removed
     * @return a Map of (property name, error message) for the properties which could not changed (either set or removed). If
     * the operation was successful, this may be null.
     */
    Map<String, String> setCustomProperties( ITransaction transaction,
                                             String resourceUri,
                                             Map<String, Object> propertiesToSet,
                                             List<String> propertiesToRemove );

    /**
     * Returns the map of (propertyName, propertyValue) of custom properties of the given resource. NOTE: Nested properties are <b>not</b> supported
     *
     * @param transaction the {@link ITransaction} within which the operation takes place; may not be null
     * @param resourceUri the URI of the object on which the properties should be updated; may not be null
     * @return a Map of (property name, property value) pair; may not be null; if the property name is namespace-aware it is
     * expected to have the [namespaceUri]:[localPropertyName] format
     */
    Map<String, Object> getCustomProperties( ITransaction transaction,
                                             String resourceUri );


    /**
     * Returns a map of custom namespaces that are specific to the store.
     *
     * @param transaction the {@link ITransaction} within which the operation takes place; may not be null
     * @param resourceUri resourceUri the URI of the object on which the properties should be updated; may not be null
     * @return a Map of (namespaceUri, namespacePrefix) pairs;may not be null;
     */
    Map<String, String> getCustomNamespaces(ITransaction transaction,
                                            String resourceUri);

}
