/**
* Copyright (C) 2012 Red Hat, Inc. (jdcasey@commonjava.org)
*
* 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 org.commonjava.cartographer.graph.traverse.print;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import org.commonjava.maven.atlas.graph.rel.DependencyRelationship;
import org.commonjava.maven.atlas.graph.rel.ProjectRelationship;
import org.commonjava.maven.atlas.graph.rel.SimpleDependencyRelationship;
import org.commonjava.cartographer.graph.util.RelationshipUtils;
import org.commonjava.maven.atlas.ident.ref.ProjectRef;
import org.commonjava.maven.atlas.ident.ref.ProjectVersionRef;
public class TreePrinter
{
// private final Logger logger = LoggerFactory.getLogger( getClass() );
private final StructureRelationshipPrinter relationshipPrinter;
// private final boolean collapseTransitives;
// private final Set<ProjectRef> seen = new HashSet<ProjectRef>();
private final Map<ProjectRef, ProjectVersionRef> selected = new HashMap<ProjectRef, ProjectVersionRef>();
public TreePrinter()
{
this.relationshipPrinter = new TargetRefPrinter();
// this.collapseTransitives = true;
}
public TreePrinter( final StructureRelationshipPrinter relationshipPrinter )
{
this.relationshipPrinter = relationshipPrinter;
}
// TODO: Reinstate transitive collapse IF we can find a way to make output consistent.
// public TreePrinter( final StructureRelationshipPrinter relationshipPrinter, final boolean collapseTransitives )
// {
// this.relationshipPrinter = relationshipPrinter;
// this.collapseTransitives = collapseTransitives;
// }
public void printStructure( final ProjectVersionRef from,
final Map<ProjectVersionRef, List<ProjectRelationship<?, ?>>> links,
final Map<String, Set<ProjectVersionRef>> labels, final PrintWriter writer )
{
printStructure( from, links, null, null, " ", labels, writer );
}
public void printStructure( final ProjectVersionRef from,
final Map<ProjectVersionRef, List<ProjectRelationship<?, ?>>> links,
final String indent,
final Map<String, Set<ProjectVersionRef>> labels, final PrintWriter writer )
{
printStructure( from, links, null, null, indent, labels, writer );
}
public void printStructure( final ProjectVersionRef from,
final Map<ProjectVersionRef, List<ProjectRelationship<?, ?>>> links,
final String header, final String footer, final String indent,
final Map<String, Set<ProjectVersionRef>> labels, final PrintWriter writer )
{
if ( header != null )
{
writer.print( header );
}
writer.print( "\n" );
relationshipPrinter.printProjectVersionRef( from, writer, null, labels, null );
// writer.print( from );
printLinks( from, writer, indent, 1, links, labels, new HashSet<ProjectRef>(), new Stack<ProjectVersionRef>() );
writer.print( "\n" );
if ( footer != null )
{
writer.print( footer );
}
}
private void printLinks( final ProjectVersionRef from, final PrintWriter writer, final String indent,
final int depth, final Map<ProjectVersionRef, List<ProjectRelationship<?, ?>>> links,
final Map<String, Set<ProjectVersionRef>> labels, final Set<ProjectRef> excluded,
final Stack<ProjectVersionRef> inPath )
{
inPath.push( from );
selected.put( from.asProjectRef(), from );
final List<ProjectRelationship<?, ?>> outbound = links.get( from );
if ( outbound != null )
{
for ( final ProjectRelationship<?, ?> out : outbound )
{
final ProjectVersionRef outRef = out.getTarget()
.asProjectVersionRef();
if ( inPath.contains( outRef ) )
{
continue;
}
if ( excluded.contains( out.getTarget()
.asProjectVersionRef() ) )
{
continue;
}
// TODO: Reinstate transitive collapse IF we can find a way to make output consistent.
// else if ( collapseTransitives && !seen.add( out.getTarget()
// .asProjectRef() ) )
// {
// return;
// }
writer.append( "\n" );
final ProjectVersionRef selection = selected.get( out.getTarget()
.asProjectRef() );
if ( selection == null )
{
selected.put( out.getTarget()
.asProjectRef(), selection );
}
relationshipPrinter.print( out, selection, writer, labels, depth, indent );
if ( ( selection == null || selection.equals( out.getTarget()
.asProjectVersionRef() ) )
&& !from.equals( out.getTarget()
.asProjectVersionRef() ) )
{
Set<ProjectRef> newExcluded = null;
if ( out instanceof SimpleDependencyRelationship )
{
final Set<ProjectRef> excludes = ( (DependencyRelationship) out ).getExcludes();
if ( excludes != null && !excludes.isEmpty() )
{
newExcluded = new HashSet<ProjectRef>();
for ( final ProjectRef ref : excludes )
{
if ( !RelationshipUtils.isExcluded( ref, excluded ) )
{
newExcluded.add( ref );
excluded.add( ref );
}
}
}
}
printLinks( out.getTarget()
.asProjectVersionRef(), writer, indent, depth + 1, links, labels, excluded, inPath );
if ( newExcluded != null && !newExcluded.isEmpty() )
{
excluded.removeAll( newExcluded );
}
}
}
}
inPath.pop();
}
}