/*******************************************************************************
* Copyright 2012 University of Southern California
*
* 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.
*
* This code was developed by the Information Integration Group as part
* of the Karma project at the Information Sciences Institute of the
* University of Southern California. For more information, publications,
* and related projects, please see: http://www.isi.edu/integration
******************************************************************************/
package edu.isi.karma.modeling.alignment;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.log4j.Logger;
import org.jgrapht.graph.DirectedWeightedMultigraph;
import org.jgrapht.graph.WeightedMultigraph;
import org.jgrapht.traverse.BreadthFirstIterator;
import edu.isi.karma.rep.alignment.Link;
import edu.isi.karma.rep.alignment.LinkPriorityComparator;
import edu.isi.karma.rep.alignment.Node;
import edu.isi.karma.rep.alignment.SimpleLink;
public class TreePostProcess {
static Logger logger = Logger.getLogger(TreePostProcess.class);
private GraphBuilder graphBuilder;
private DirectedWeightedMultigraph<Node, Link> tree;
private Node root = null;
private Node thingNode = null;
// private List<Node> dangledVertexList;
// Constructor
public TreePostProcess(
GraphBuilder graphBuilder,
WeightedMultigraph<Node, Link> tree,
List<Link> newLinks,
Node thingNode) {
this.graphBuilder = graphBuilder;
this.tree = (DirectedWeightedMultigraph<Node, Link>)GraphUtil.asDirectedGraph(tree);
this.thingNode = thingNode;
buildOutputTree();
addLinks(newLinks);
selectRoot(findPossibleRoots());
}
// Public Methods
public DirectedWeightedMultigraph<Node, Link> getTree() {
return this.tree;
}
public Node getRoot() {
return this.root;
}
// Private Methods
private List<Node> findPossibleRoots() {
List<Node> possibleRoots = new ArrayList<Node>();
// If tree contains the Thing, we return it as the root
for (Node v: this.tree.vertexSet())
if (v.equals(this.thingNode)) {
possibleRoots.add(v);
return possibleRoots;
}
int maxReachableNodes = -1;
int reachableNodes = -1;
List<Node> vertexList = new ArrayList<Node>();
List<Integer> reachableNodesList = new ArrayList<Integer>();
for (Node v: this.tree.vertexSet()) {
BreadthFirstIterator<Node, Link> i =
new BreadthFirstIterator<Node, Link>(this.tree, v);
reachableNodes = -1;
while (i.hasNext()) {
i.next();
reachableNodes ++;
}
vertexList.add(v);
reachableNodesList.add(reachableNodes);
if (reachableNodes > maxReachableNodes) {
maxReachableNodes = reachableNodes;
}
}
for (int i = 0; i < vertexList.size(); i++)
if (reachableNodesList.get(i).intValue() == maxReachableNodes)
possibleRoots.add(vertexList.get(i));
return possibleRoots;
}
private void selectRoot(List<Node> possibleRoots) {
if (possibleRoots == null || possibleRoots.size() == 0)
return;
Collections.sort(possibleRoots);
this.root = possibleRoots.get(0);
}
private DirectedWeightedMultigraph<Node, Link> buildOutputTree() {
String sourceId, targetId;
Link[] links = tree.edgeSet().toArray(new Link[0]);
String linkSourceId;//, linkTargetId;
List<Link> temp;
List<Link> possibleLinks = new ArrayList<Link>();
for (Link link : links) {
if (!(link instanceof SimpleLink)) continue;
// links from source to target
sourceId = link.getSource().getId();
targetId = link.getTarget().getId();
possibleLinks.clear();
temp = this.graphBuilder.getPossibleLinks(sourceId, targetId);
if (temp != null) possibleLinks.addAll(temp);
temp = this.graphBuilder.getPossibleLinks(targetId, sourceId);
if (temp != null) possibleLinks.addAll(temp);
Collections.sort(possibleLinks, new LinkPriorityComparator());
if (possibleLinks.size() > 0) {
// pick the first one
Link newLink = possibleLinks.get(0);
linkSourceId = LinkIdFactory.getLinkSourceId(newLink.getId());
//linkTargetId = LinkIdFactory.getLinkTargetId(newLink.getId());
if (linkSourceId.equals(sourceId)) {
tree.addEdge(link.getSource(), link.getTarget(), newLink);
this.graphBuilder.addLink(link.getSource(), link.getTarget(), newLink);
} else {
tree.addEdge(link.getTarget(), link.getSource(), newLink);
this.graphBuilder.addLink(link.getTarget(), link.getSource(), newLink);
}
tree.removeEdge(link);
this.graphBuilder.removeLink(link);
} else {
logger.error("Something is going wrong. " +
"There should be at least one possible object property between " +
link.getSource().getLabel().getUri() +
" and " + link.getTarget().getLabel().getUri());
return null;
}
}
return tree;
}
private void addLinks(List<Link> links) {
if (links == null)
return;
for (Link link : links) {
if (!this.tree.containsEdge(link) &&
this.tree.containsVertex(link.getSource()) &&
this.tree.containsVertex(link.getTarget())) {
this.tree.addEdge(link.getSource(), link.getTarget(), link);
}
}
}
// private void removeDanglingNodes() {
//
// boolean connectedToColumn = false;
// for (Node v: this.tree.vertexSet()) {
// BreadthFirstIterator<Node, Link> i =
// new BreadthFirstIterator<Node, Link>(this.tree, v);
//
// connectedToColumn = false;
//
// while (i.hasNext()) {
// Node temp = i.next();
// if (temp instanceof ColumnNode)
// connectedToColumn = true;
// }
//
// if (connectedToColumn == false)
// dangledVertexList.add(v);
// }
//
// for (Node v : dangledVertexList)
// this.tree.removeVertex(v);
//
// }
// public List<Node> getDangledVertexList() {
// return dangledVertexList;
// }
}