/*
 * Copyright Amherst College
 *
 * 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 edu.amherst.acdc.trellis.spi;

import java.io.InputStream;
import java.util.List;
import java.util.Optional;

import edu.amherst.acdc.trellis.api.Datastream;
import org.apache.commons.rdf.api.IRI;

/**
 * The DatastreamService provides methods for retrieving, modifying and checking
 * the validity of binary content.
 *
 * @author acoburn
 */
public interface DatastreamService {

    /**
     * A datastream resolver, used by the DatastreamService
     */
    interface Resolver {
        /**
         * @return the uri schemes supported by this resolver
         */
        List<String> getUriSchemes();

        /**
         * Get the content of the datastream
         * @param identifier the identifier
         * @return the content of the datastream
         */
        Optional<InputStream> getContent(IRI identifier);

        /**
         * Check whether the datastream exists
         * @param identifier the identifier
         * @return whether the datastream exists
         */
        Boolean exists(IRI identifier);

        /**
         * Set the content of the datastream
         * @param identifier the identifier
         * @param stream the content
         * @param contentType the datastream contentType
         */
        void setContent(IRI identifier, InputStream stream, String contentType);
    }

    /**
     * Get the content of the datastream
     * @param identifier an identifier used for locating the datastream
     * @return the content
     */
    Optional<InputStream> getContent(IRI identifier);

    /**
     * Test whether a datastream exists at the given URI
     * @param identifier the datastream identifier
     * @return whether the datastream exists
     */
    Boolean exists(IRI identifier);

    /**
     * Set the content for a datastream
     * @param identifier the datastream identifier
     * @param stream the content
     * @param contentType the contentType
     */
    void setContent(IRI identifier, InputStream stream, String contentType);

    /**
     * Calculate the digest for a datastream
     * @param identifier the identifier
     * @param algorithm the algorithm
     * @return the digest
     */
    Optional<String> calculateDigest(IRI identifier, String algorithm);

    /**
     * Generate an identifier for a new datastream resource
     * @param identifier the resource identifier
     * @return an identifier for the datastream
     */
    default IRI generateIdentifier(IRI identifier) {
        return generateIdentifier(identifier, null);
    }

    /**
     * Generate an identifier for a new datastream resource using a particular
     * partition hint.
     * @param identifier the resource identifier
     * @param partition the partition to use
     * @return the new identifier for the datastream
     */
    IRI generateIdentifier(IRI identifier, Datastream.StoragePartition partition);
}

@@ -2076,32 +2076,40 @@
 ent%0A     */%0A    
+default 
 Optional%3CInputSt
@@ -2132,33 +2132,133 @@
 (IRI identifier)
-;
+ %7B%0A        return getResolver(identifier).flatMap(resolver -%3E resolver.getContent(identifier));%0A    %7D
 %0A%0A    /**%0A     *
@@ -2412,24 +2412,32 @@
      */%0A    
+default 
 Boolean exis
@@ -2450,25 +2450,131 @@
  identifier)
-;
+ %7B%0A        return getResolver(identifier).map(resolver -%3E resolver.exists(identifier)).orElse(false);%0A    %7D
 %0A%0A    /**%0A  
@@ -2745,24 +2745,32 @@
      */%0A    
+default 
 void setCont
@@ -2828,17 +2828,133 @@
 entType)
-;
+ %7B%0A        getResolver(identifier).ifPresent(resolver -%3E resolver.setContent(identifier, stream, contentType));%0A    %7D
 %0A%0A    /*
@@ -3112,24 +3112,32 @@
      */%0A    
+default 
 Optional%3CStr
@@ -3190,17 +3190,111 @@
 gorithm)
-;
+ %7B%0A        return getContent(identifier).flatMap(stream -%3E hexDigest(algorithm, stream));%0A    %7D
 %0A%0A    /*
@@ -3920,11 +3920,444 @@
 tition);
+%0A%0A    /**%0A     * Get the resolver for the given identifier%0A     * @param identifier the identifier%0A     * @return a datastream resolver%0A     */%0A    Optional%3CResolver%3E getResolver(IRI identifier);%0A%0A    /**%0A     * Get the digest for an input stream%0A     * @param algorithm the algorithm to use%0A     * @param stream the input stream%0A     * @return the digest%0A     */%0A    Optional%3CString%3E hexDigest(String algorithm, InputStream stream);
 %0A%7D%0A

move code into default methods