/*
 * 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.rosid;

import static com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS;
import static edu.amherst.acdc.trellis.rosid.Constants.RESOURCE_CACHE;
import static edu.amherst.acdc.trellis.rosid.Constants.RESOURCE_QUADS;
import static edu.amherst.acdc.trellis.rosid.FileUtils.stringToQuad;
import static java.nio.file.Files.lines;
import static java.util.Optional.ofNullable;
import static java.util.stream.Stream.empty;
import static org.slf4j.LoggerFactory.getLogger;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

import edu.amherst.acdc.trellis.api.Resource;

import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Stream;

import org.apache.commons.rdf.api.IRI;
import org.apache.commons.rdf.api.Quad;
import org.apache.commons.rdf.api.Triple;
import org.slf4j.Logger;

/**
 * An object that mediates access to the resource cache files.
 *
 * @author acoburn
 */
class CachedResource extends AbstractFileResource {

    private static final ObjectMapper MAPPER = new ObjectMapper();

    private static final Logger LOGGER = getLogger(CachedResource.class);

    static {
        MAPPER.configure(WRITE_DATES_AS_TIMESTAMPS, false);
        MAPPER.registerModule(new JavaTimeModule());
    }

    /**
     * Create a File-based resource reader
     * @param directory the data storage directory
     * @param identifier the resource to retrieve
     */
    protected CachedResource(final File directory, final IRI identifier, final ResourceData data) {
        super(directory, identifier, data);
    }

    /**
     * Retrieve a cached resource, if it exists
     * @param directory the directory
     * @param identifier the identifier
     * @return the resource
     */
    public static Optional<Resource> find(final File directory, final IRI identifier) {
        ResourceData data = null;
        try {
            data = MAPPER.readValue(new File(directory, RESOURCE_CACHE), ResourceData.class);
        } catch (final IOException ex) {
            LOGGER.warn("Error reading cached resource: {}", ex.getMessage());
        }
        return ofNullable(data).map(d -> new CachedResource(directory, identifier, d));
    }

    /**
     * Write the resource data into a file as JSON
     * @param directory the directory
     * @param json the resource data
     */
    public static void write(final File directory, final ResourceData json) {
        try {
            MAPPER.writeValue(new File(directory, RESOURCE_CACHE), json);
        } catch (final IOException ex) {
            throw new UncheckedIOException(ex);
        }
    }

    @Override
    public <T extends Resource.TripleCategory> Stream<Triple> stream(final Collection<T> category) {
        return Optional.of(new File(directory, RESOURCE_QUADS)).filter(File::exists).map(File::toPath)
            .map(uncheckedLines).orElse(empty()).map(line -> stringToQuad(rdf, line)).filter(Optional::isPresent)
            .map(Optional::get).filter(quad -> quad.getGraphName().isPresent() &&
                    category.contains(categorymap.get(quad.getGraphName().get()))).map(Quad::asTriple);
    }

    private Function<Path, Stream<String>> uncheckedLines = path -> {
        try {
            return lines(path);
        } catch (final IOException ex) {
            throw new UncheckedIOException(ex);
        }
    };
}

@@ -955,28 +955,329 @@
 ava.
-nio.file.Files.lines
+lang.String.join;%0Aimport static java.lang.System.lineSeparator;%0Aimport static java.nio.charset.StandardCharsets.UTF_8;%0Aimport static java.nio.file.Files.lines;%0Aimport static java.nio.file.Files.newBufferedWriter;%0Aimport static java.nio.file.StandardOpenOption.APPEND;%0Aimport static java.nio.file.StandardOpenOption.CREATE
 ;%0Aim
@@ -1574,16 +1574,99 @@
 source;%0A
+import edu.amherst.acdc.trellis.vocabulary.Trellis;%0A%0Aimport java.io.BufferedWriter;
 %0Aimport 
@@ -1796,24 +1796,51 @@
 Collection;%0A
+import java.util.Iterator;%0A
 import java.
@@ -3838,24 +3838,948 @@
    %7D%0A    %7D%0A%0A
+    /**%0A     * Write the resource data into a file as RDF quads%0A     * @param directory the directory%0A     * @param quads the quads%0A     */%0A    public static void write(final File directory, final Stream%3CQuad%3E quads) throws IOException %7B%0A        final File file = new File(directory, RESOURCE_QUADS);%0A        try (final BufferedWriter writer = newBufferedWriter(file.toPath(), UTF_8, CREATE, APPEND)) %7B%0A            final Iterator%3CString%3E lineIter = quads.map(quad -%3E join(%22 %22, quad.getSubject().ntriplesString(),%0A                        quad.getPredicate().ntriplesString(), quad.getObject().ntriplesString(),%0A                        quad.getGraphName().orElse(Trellis.PreferUserManaged).ntriplesString(), %22.%22)).iterator();%0A            while (lineIter.hasNext()) %7B%0A                writer.write(lineIter.next() + lineSeparator());%0A            %7D%0A        %7D catch (final IOException ex) %7B%0A            throw ex;%0A        %7D%0A    %7D%0A%0A
     @Overrid

Add write methods to cache