/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.stanbol.enhancer.servicesapi;

import java.io.InputStream;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;

import org.apache.clerezza.rdf.core.MGraph;
import org.apache.clerezza.rdf.core.UriRef;

/**
 * A unit of content that Stanbol Enhancer can enhance.
 * <p>
 * Gives access to the binary content that
 * was registered, and the Graph that represents its metadata
 * (provided by client and/or generated).
 */
public interface ContentItem {

    /** The Uri of this ContentItem (either supplied by client or generated by Stanbol Enhancer) */
    UriRef getUri();

    /**
     * The binary content stream. Shortcut for
     * <code>{@link #getBlob()}{@link Blob#getStream() .getStream()}</code>
     * @return the InputStream
     */
    InputStream getStream();

    /**
     * The MimeType. Shortcut for
     * <code>{@link #getBlob()}{@link Blob#getMimeType() .getMimeType()}</code>.
     * @return the MimeType as string
     */
    String getMimeType();

    /**
     * Read/write lock used to synchronise access to the {@link #getMetadata()
     * metadata} and the content parts of this content item.<p>
     * The lock needs to be used for reading and writing information from/to
     * the ContentItem. In case the {@link MGraph} retured by {@link #getMetadata()}
     * is an instanceof used by the {@link org.apache.clerezza.rdf.core.access.LockableMGraph}
     * the {@link Lock} returned by this mehtod is the same as used by the
     * metadata.This is to avoid deadlocks when using a lock while iterating over 
     * the {@link #getMetadata() metadata} and simultaneously accessing the content 
     * parts.
     *  
     * @return the lock used for the content parts and the {@link LockableMGraph}
     * containing the metadata of this content item.
     */
    ReadWriteLock getLock();
    
    /** Optional metadata */
    MGraph getMetadata();
    
    /**
     * The main content of this content item
     * 
     * @return the blob at index 0
     */
    Blob getBlob();
    
    /**
     * A content item may consists of multiple parts, while the part with index 0 should always be a blob,
     * higher position may be used by Enhancer to story arbitrary objects, such objects can be used for 
     * accessing the precomputations of EnhancementEngines previous in the chain.
     * @throws NoSuchPartException if no part with the parsed index exists
     * @throws ClassCastException if the class of the part is not compatiple with
     * the requested class
     * @throws IllegalArgumentException if <code>null</code> is parsed as
     * clazz.
     */
    <T> T getPart(int index, Class<T> clazz) throws NoSuchPartException;
    
    /**
     * Each part of the content item has a URI. EnhancementEngines typically access parts by their Uri as the
     * position may vary depending on the chain.
     * @throws NoSuchPartException if no part with the parsed uri exists
     * @throws ClassCastException if the class of the part is not compatiple with
     * the requested class
     * @throws IllegalArgumentException if <code>null</code> is parsed as
     * uri or clazz.
     */
    <T> T getPart(UriRef uri, Class<T> clazz) throws NoSuchPartException;
    
    /**
     * Get the uri of the part at the specified index
     * @throws NoSuchPartException if no part with the parsed index exists
     */
    UriRef getPartUri(int index) throws NoSuchPartException;

    /**
     * Add a new part to this ContentItem
     * 
     * @param uriRef the URI of the part
     * @param object the part
     * @return the part replaced by the parsed object or <code>null</code> if
     * no part with the parsed URI was present
     * @throws IllegalArgumentException if <code>null</code> is parsed as
     * uriRef or object.
     */
    Object addPart(UriRef uriRef, Object object);
    
    /**
     * Removes a part - other than the main content part - from this ContentItem
     * @param index the index of the part to remove. NOTE that index '0' 
     * - the main content part - can NOT be removed!
     * @throws NoSuchPartException if no ContentPart with the parsed id exists
     * @throws IllegalArgumentException it the parsed index &lt; 0
     * @throws IllegalStateException if '0' is parsed as index. The index '0' 
     * - the main content part - can NOT be removed!
     */
    void removePart(int index);
    
    /**
     * Removes a part - other than the main content part - from this ContentItem
     * @param uriRef the uri of the part to remove. NOTE that the part with the
     * uri <code>{@link #getPartUri(int) getPartUri(0)}</code> - the main 
     * content part - can NOT be removed!
     * @throws NoSuchPartException if no ContentPart with the parsed uri exists
     * @throws IllegalArgumentException it the parsed uri is <code>null</code>
     * @throws IllegalStateException if the parsed uri is equals to
     * <code>{@link #getPartUri(int) getPartUri(0)}</code>. This uri refers to
     * the main content part. This part can NOT be removed by this method
     */
    void removePart(UriRef uriRef);
    
}
