/**
 * 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.jena.sparql.core;

import java.util.Iterator ;

import org.apache.jena.atlas.iterator.Iter ;
import org.apache.jena.atlas.lib.Sync ;
import org.apache.jena.graph.Node ;
import org.apache.jena.graph.Triple ;
import org.apache.jena.graph.impl.GraphBase ;
import org.apache.jena.riot.other.GLib ;
import org.apache.jena.shared.JenaException ;
import org.apache.jena.shared.PrefixMapping ;
import org.apache.jena.shared.impl.PrefixMappingImpl ;
import org.apache.jena.sparql.SystemARQ ;
import org.apache.jena.util.iterator.ExtendedIterator ;
import org.apache.jena.util.iterator.WrappedIterator ;

/** Implement a Graph as a view of the DatasetGraph.
 * 
 *  It maps graph operations to quad operations. 
 */ 

public class GraphView extends GraphBase implements Sync
{
    // Beware this implements union graph - implementations may wish
    // to do better so see protected method below.
    
    static class GraphViewException extends JenaException
    {
        public GraphViewException()                                  { super(); }
        public GraphViewException(String message)                    { super(message); }
        public GraphViewException(Throwable cause)                   { super(cause) ; }
        public GraphViewException(String message, Throwable cause)   { super(message, cause) ; }
    }
    
    private final DatasetGraph dsg ;
    private final Node gn ;                 // null for default graph.

    // Factory style.
    public static GraphView createDefaultGraph(DatasetGraph dsg)
    { return new GraphView(dsg, Quad.defaultGraphNodeGenerated) ; }
    
    public static GraphView createNamedGraph(DatasetGraph dsg, Node graphIRI)
    { return new GraphView(dsg, graphIRI) ; }
    
    public static GraphView createUnionGraph(DatasetGraph dsg)
    { return new GraphView(dsg, Quad.unionGraph) ; }

    // If inherited.
    protected GraphView(DatasetGraph dsg, Node gn) {
        this.dsg = dsg ;
        this.gn = gn ;
    }

    /**
     * Return the graph name for this graph in the dataset it is a view of.
     * Returns {@code null} for the default graph.
     */
    public Node getGraphName() {
        return (gn == Quad.defaultGraphNodeGenerated) ? null : gn ;
    }

    /** Return the DatasetGraph we are viewing. */
    public DatasetGraph getDataset() {
        return dsg ;
    }
    
    protected final boolean isDefaultGraph() { return isDefaultGraph(gn) ; }
    protected final boolean isUnionGraph()   { return isUnionGraph(gn) ; }

    protected static final boolean isDefaultGraph(Node gn) { return gn == null || Quad.isDefaultGraph(gn) ; }
    protected static final boolean isUnionGraph(Node gn)   { return Quad.isUnionGraph(gn) ; }
    
    // TODO Unsatisfactory - need PrefixMap support by DSGs 
    // and sort out PrefixMap/PrefixMapping.
    
    @Override
    protected PrefixMapping createPrefixMapping() {
        // Unwrap if possible, else put in an in-memroy placeholder. 
        if ( dsg instanceof DatasetGraphWrapper ) {
            DatasetGraph dsg2 = ((DatasetGraphWrapper)dsg).getBase() ;
            return dsg2.getDefaultGraph().getPrefixMapping() ;    
        }
        return new PrefixMappingImpl() ;
    }

    @Override
    protected ExtendedIterator<Triple> graphBaseFind(Triple m) {
        if ( m == null ) m = Triple.ANY ;
        Node s = m.getMatchSubject() ;
        Node p = m.getMatchPredicate() ;
        Node o = m.getMatchObject() ;
        return graphBaseFind(s, p, o) ;
    }
    
    @Override
    protected ExtendedIterator<Triple> graphBaseFind(Node s, Node p, Node o) {
        if ( Quad.isUnionGraph(gn) )
            return graphUnionFind(s, p, o) ;
        Node g = graphNode(gn) ;
        Iterator<Triple> iter = GLib.quads2triples(dsg.find(g, s, p, o)) ;
        return WrappedIterator.createNoRemove(iter) ;
    }

    private static Node graphNode(Node gn) {
        return ( gn == null ) ? Quad.defaultGraphNodeGenerated : gn ;
    }

    protected ExtendedIterator<Triple> graphUnionFind(Node s, Node p, Node o) {
        Node g = graphNode(gn) ;
        // Implementations may wish to do better so this is separated out.
        // For example, Iter.distinctAdjacent is a lot cheaper than Iter.distinct
        // but assumes thing come back in a particular order
        Iterator<Quad> iterQuads = getDataset().find(g, s, p, o) ;
        Iterator<Triple> iter = GLib.quads2triples(iterQuads) ;
        // Suppress duplicates after projecting to triples.
        iter = Iter.distinct(iter) ;
        return WrappedIterator.createNoRemove(iter) ;
    }
    
    @Override
    public void performAdd( Triple t ) { 
        Node g = graphNode(gn) ;
        if ( Quad.isUnionGraph(g) )
            throw new GraphViewException("Can't update the default union graph of a dataset") ; 
        Node s = t.getSubject() ;
        Node p = t.getPredicate() ;
        Node o = t.getObject() ;
        dsg.add(g, s, p, o) ;
    }

    @Override
    public void performDelete( Triple t ) {
        Node g = graphNode(gn) ;
        if ( Quad.isUnionGraph(g) )
            throw new GraphViewException("Can't update the default union graph of a dataset") ; 
        Node s = t.getSubject() ;
        Node p = t.getPredicate() ;
        Node o = t.getObject() ;
        dsg.delete(g, s, p, o) ;
    }

    @Override
    public void sync() {
        SystemARQ.sync(dsg);
    }
    
    // Need to call GraphBase.close() or sent the protected closed flag.
    //@Override public void close() { super.close() ; }
}

@@ -3695,24 +3695,26 @@
 Mapping() %7B%0A
+//
         // U
@@ -3753,18 +3753,18 @@
 n in-mem
-r
 o
+r
 y placeh
@@ -3771,16 +3771,98 @@
 older. %0A
+//        // Does not work so simply - TDB may have gone transactional.        %0A//
         
@@ -3901,24 +3901,26 @@
 Wrapper ) %7B%0A
+//
             
@@ -3974,24 +3974,26 @@
 getBase() ;%0A
+//
             
@@ -4043,24 +4043,26 @@
 ing() ;    %0A
+//
         %7D%0A  

Undo chnages from commit 880c410.