package edu.isi.karma.controller.command.alignment;
import java.util.Set;
import org.jgrapht.graph.DirectedWeightedMultigraph;
import org.json.JSONException;
import org.json.JSONObject;
import edu.isi.karma.controller.command.CommandException;
import edu.isi.karma.controller.command.CommandType;
import edu.isi.karma.controller.command.WorksheetCommand;
import edu.isi.karma.controller.update.TrivialErrorUpdate;
import edu.isi.karma.controller.update.UpdateContainer;
import edu.isi.karma.modeling.alignment.Alignment;
import edu.isi.karma.modeling.alignment.AlignmentManager;
import edu.isi.karma.modeling.alignment.LinkIdFactory;
import edu.isi.karma.modeling.ontology.OntologyManager;
import edu.isi.karma.rep.Workspace;
import edu.isi.karma.rep.alignment.DefaultLink;
import edu.isi.karma.rep.alignment.InternalNode;
import edu.isi.karma.rep.alignment.Label;
import edu.isi.karma.rep.alignment.LabeledLink;
import edu.isi.karma.rep.alignment.LinkStatus;
import edu.isi.karma.rep.alignment.LiteralNode;
import edu.isi.karma.rep.alignment.Node;
import edu.isi.karma.rep.alignment.NodeType;
import edu.isi.karma.controller.command.alignment.ChangeInternalNodeLinksCommand.LinkJsonKeys;
public class AddLinkCommand extends WorksheetCommand {
private String displayLabel;
private String alignmentId;
private JSONObject edge;
// Required for undo
private Alignment oldAlignment;
private DirectedWeightedMultigraph<Node, DefaultLink> oldGraph;
private boolean hasProvenaceType;
protected AddLinkCommand(String id, String model, String worksheetId, String alignmentId, JSONObject edge) {
super(id, model, worksheetId);
this.alignmentId = alignmentId;
this.edge = edge;
addTag(CommandTag.Modeling);
}
@Override
public String getCommandName() {
return AddLinkCommand.class.getSimpleName();
}
@Override
public String getTitle() {
return "Add Link";
}
@Override
public String getDescription() {
return this.displayLabel;
}
@Override
public CommandType getCommandType() {
return CommandType.undoable;
}
@SuppressWarnings("unchecked")
@Override
public UpdateContainer doIt(Workspace workspace) throws CommandException {
Alignment alignment = AlignmentManager.Instance().getAlignment(
alignmentId);
OntologyManager ontMgr = workspace.getOntologyManager();
// Save the original alignment for undo
oldAlignment = alignment.getAlignmentClone();
oldGraph = (DirectedWeightedMultigraph<Node, DefaultLink>) alignment
.getGraph().clone();
UpdateContainer uc = this.addNewLink(alignment, ontMgr, edge);
if(!this.isExecutedInBatch())
alignment.align();
uc.append(this.computeAlignmentAndSemanticTypesAndCreateUpdates(workspace));
return uc;
}
@Override
public UpdateContainer undoIt(Workspace workspace) {
// Revert to the old alignment
AlignmentManager.Instance()
.addAlignmentToMap(alignmentId, oldAlignment);
oldAlignment.setGraph(oldGraph);
return this.computeAlignmentAndSemanticTypesAndCreateUpdates(workspace);
}
private void addProvenaceLinks(Alignment alignment, Label linkLabel, LiteralNode targetNode) {
String targetId = targetNode.getId();
Set<Node> internalNodes = alignment.getNodesByType(NodeType.InternalNode);
String edgeUri = linkLabel.getUri();
for(Node internalNode : internalNodes) {
String nodeId = internalNode.getId();
Set<LabeledLink> inLinks = alignment.getIncomingLinksInTree(nodeId);
Set<LabeledLink> outLinks = alignment.getOutgoingLinksInTree(nodeId);
if((inLinks != null && inLinks.size() > 0)
|| (outLinks != null && outLinks.size() > 0)) {
String linkId = LinkIdFactory.getLinkId(edgeUri, nodeId, targetId);
LabeledLink link = alignment.getLinkById(linkId);
if(link == null) {
link = alignment.addObjectPropertyLink(internalNode,
targetNode, linkLabel);
alignment.changeLinkStatus(linkId, LinkStatus.ForcedByUser);
link.setProvenance(true, false);
}
}
}
}
private UpdateContainer addNewLink(Alignment alignment, OntologyManager ontMgr, JSONObject newEdge)
throws JSONException {
UpdateContainer uc = new UpdateContainer();
String edgeUri = newEdge.getString(LinkJsonKeys.edgeId.name());
if(edgeUri == null) {
displayLabel = "Edge " + edgeUri + " not found";
return uc;
}
Label edge = ontMgr.getUriLabel(edgeUri);
String sourceUri = newEdge.has(LinkJsonKeys.edgeSourceUri.name()) ? newEdge.getString(LinkJsonKeys.edgeSourceUri.name()) : null;
String sourceId = newEdge.has(LinkJsonKeys.edgeSourceId.name()) ? newEdge.getString(LinkJsonKeys.edgeSourceId.name()) : null;
String targetId = newEdge.has(LinkJsonKeys.edgeTargetId.name()) ? newEdge.getString(LinkJsonKeys.edgeTargetId.name()) : null;
String targetUri = newEdge.has(LinkJsonKeys.edgeTargetUri.name()) ? newEdge.getString(LinkJsonKeys.edgeTargetUri.name()) : null;
boolean isProvenance = newEdge.has(LinkJsonKeys.isProvenance.name()) ? newEdge.getBoolean(LinkJsonKeys.isProvenance.name()) : false;
LiteralNode provenanceNode = null;
if(isProvenance) {
Node node = alignment.getNodeById(targetId);
if(node != null && node instanceof LiteralNode) {
provenanceNode = (LiteralNode)node;
} else {
isProvenance = false;
}
}
this.hasProvenaceType = isProvenance;
if(edgeUri != null && sourceId != null && targetId != null) {
String linkId = LinkIdFactory.getLinkId(edgeUri, sourceId, targetId);
LabeledLink link = alignment.getLinkById(linkId);
if (link != null) {
//Link already exists
alignment.changeLinkStatus(linkId, LinkStatus.ForcedByUser);
link.setProvenance(isProvenance, true);
if(isProvenance)
addProvenaceLinks(alignment, edge, provenanceNode);
this.displayLabel = link.getLabel().getDisplayName();
return uc;
}
}
Node sourceNode = null;
Label sourceLabel = null;
if(sourceUri != null)
sourceLabel = ontMgr.getUriLabel(sourceUri);
if(sourceId != null) {
if(sourceId.endsWith(" (add)"))
sourceId = sourceId.substring(0, sourceId.length()-5).trim();
sourceNode = alignment.getNodeById(sourceId);
if(sourceNode == null) {
sourceNode = alignment.addInternalNode(new InternalNode(sourceId, sourceLabel));
}
} else if(sourceUri != null){
sourceNode = alignment.addInternalNode(sourceLabel);
sourceId = sourceNode.getId();
}
Label targetLabel = null;
if(targetUri != null)
targetLabel = ontMgr.getUriLabel(targetUri);
Node targetNode = null;
if(targetId != null) {
if(targetId.endsWith(" (add)"))
targetId = targetId.substring(0, targetId.length()-5).trim();
targetNode = alignment.getNodeById(targetId);
if(targetNode == null) {
targetNode = alignment.addInternalNode(new InternalNode(targetId, targetLabel));
}
} else if(targetUri != null) {
targetNode = alignment.addInternalNode(targetLabel);
targetId = targetNode.getId();
}
if(sourceNode == null) {
uc.add(new TrivialErrorUpdate("Could not add links from " + sourceId));
this.displayLabel = "Source " + sourceId + " not found";
return uc;
}
if(targetNode == null) {
uc.add(new TrivialErrorUpdate("Could not add links to " + targetId));
this.displayLabel = "Target " + targetId + " not found";
return uc;
}
String linkId = LinkIdFactory.getLinkId(edgeUri, sourceId, targetId);
LabeledLink newLink = alignment.getLinkById(linkId);
if (newLink != null) {
alignment.changeLinkStatus(linkId, LinkStatus.ForcedByUser);
} else {
newLink = alignment.addObjectPropertyLink(sourceNode,
targetNode, edge);
linkId = newLink.getId();
}
newLink.setProvenance(isProvenance, true);
alignment.changeLinkStatus(linkId, LinkStatus.ForcedByUser);
if(isProvenance)
addProvenaceLinks(alignment, edge, provenanceNode);
this.displayLabel = newLink.getLabel().getDisplayName();
return uc;
}
public boolean hasProvenanceType() {
return this.hasProvenaceType;
}
}