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

import java.util.Iterator;
import java.util.Set;

import org.apache.jena.util.CollectionFactory ;

/**
     GraphExtract offers a very simple recursive extraction of a subgraph with a
     specified root in some supergraph. The recursion is terminated by triples
     that satisfy some supplied boundary condition.
 */
public class GraphExtract
    {
    protected final TripleBoundary b;
    
    public GraphExtract( TripleBoundary b )
        { this.b = b; }
    
    /**
         Answer a new graph which is the reachable subgraph from <code>node</code>
         in <code>graph</code> with the terminating condition given by the
         TripleBoundary passed to the constructor.
    */
    public Graph extract( Node node, Graph graph )
        { return extractInto( Factory.createGraphMem(), node, graph ); }
    
    /**
         Answer the graph <code>toUpdate</code> augmented with the sub-graph of
         <code>extractFrom</code> reachable from <code>root</code> bounded
         by this instance's TripleBoundary.
    */
    public Graph extractInto( Graph toUpdate, Node root, Graph extractFrom )
        { new Extraction( b, toUpdate, extractFrom ).extractInto( root );
        return toUpdate; }
    
    /**
         This is the class that does all the work, in the established context of the
         source and destination graphs, the TripleBoundary that determines the
         limits of the extraction, and a local set <code>active</code> of nodes 
         already seen and hence not to be re-processed.
        */
    protected static class Extraction
        {
        protected Graph toUpdate;
        protected Graph extractFrom;
        protected Set<Node> active;
        protected TripleBoundary b;
        
        Extraction( TripleBoundary b, Graph toUpdate, Graph extractFrom )
            {
            this.toUpdate = toUpdate;
            this.extractFrom = extractFrom;
            this.active = CollectionFactory.createHashedSet();
            this.b = b;
            }
        
        public void extractInto( Node root  )
            {
            active.add( root );
            Iterator<Triple> it = extractFrom.find( root, Node.ANY, Node.ANY );
            while (it.hasNext())
                {
                Triple t = it.next();
                Node subRoot = t.getObject();
                toUpdate.add( t );
                if (! (active.contains( subRoot ) || b.stopAt( t ))) extractInto( subRoot );
                }
            }
        }
    

    }
