package com.cyc.tool.kbtaxonomy.builder;
/*
* #%L
* KBTaxonomyGeneral
* %%
* Copyright (C) 2015 Cycorp, Inc
* %%
* 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.
* #L%
*/
import com.cyc.library.json.D3JSONizable;
import com.cyc.library.json.JSONizable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* KBConcept is an abstract class for representing concepts that are used in KB Taxonomies.
*
*/
public abstract class KBConcept implements JSONizable, D3JSONizable, Comparable<KBConcept> {
/**
* Used to number entries in the JSON sent to be graphed.
*/
public static long printNumber = 0L;
/**
* A Map from Integers to KBConcepts to keep track of all concepts that have been created.
*/
static protected final Map<Integer, KBConcept> allConceptTable = new HashMap<>();
private static final Map<String, KBConcept> allConcepts = new HashMap<>();
private static final int graphMaxDepth = 8;
private static int lastConceptIndex = 0;
private int conceptIndex;
private boolean expanded = false;
private final Set<KBLink> generalLinks;
private boolean selected = false;
final Set<KBLink> childSpecLinks;
final Set<KBConcept> children;
final String conceptCycL;
final String conceptUri;
Set<String> nlNames = new HashSet<>();
final Set<NonTaxonomicLink> nonTaxonomicLinks;
final Set<TaxonomicLink> parentLinks;
final Set<KBConcept> parents;
/**
* KBConcept constructor
*
* @param conceptCycL
* @param conceptUri
*/
protected KBConcept(String conceptCycL, String conceptUri) {
this.conceptIndex = nextIndex();
this.childSpecLinks = new HashSet<>();
this.nonTaxonomicLinks = new HashSet<>();
this.parentLinks = new HashSet<>();
this.generalLinks = new HashSet<>();
this.children = new HashSet<>();
this.parents = new HashSet<>();
this.conceptCycL = conceptCycL;
this.conceptUri = conceptUri;
}
/**
* Returns all concepts
*
* @return Set of KBConcepts
*/
public static Set<KBConcept> getAllConcepts() {
return new HashSet(allConcepts.values());
}
/**
* @param id
* @return a KBConcept
*/
public static KBConcept getConcept(String id) {
return allConcepts.get(id);
}
/**
* @param id
* @return a KBConcept
*/
public static KBConcept getExpandedConcept(String id) {
allConcepts.get(id).maybeExpand();
return allConcepts.get(id);
}
/**
*
* @param id
* @return true if the concept with id is known
*/
static public boolean haveConcept(String id) {
return allConcepts.containsKey(id);
}
static void addToLists(KBConcept created) {
// System.out.println("CREATE:"+created.conceptCycL+"--"+created.conceptIndex);
allConcepts.put(created.getConceptCycL(), created);
if (created instanceof OpenCycConcept) {
allConcepts.put(((OpenCycConcept) created).shortenedName(), created);
}
allConceptTable.put(created.conceptIndex, created);
}
/**
*
* @param jsonData the value of jsonData
* @param graphConceptID the value of n
* @param depthInConcepts the value of depthInConcepts
* @param widthInConcepts the value of widthInConcepts
*/
static String writeGraphStarter(String comment, Integer graphConceptId, String graphConceptName, int depthInConcepts, int widthInConcepts) {
// return "alert(\"clicked\");";
return "collapsibleLinearGraph('" + String.format("%06d", graphConceptId) + "','" + graphConceptName + "'," + depthInConcepts + "," + widthInConcepts + "," + graphMaxDepth + ");";
}
/**
*
* @return Set of Strings containing all term names
*/
public Set<String> allTerms() {
Set<String> toReturn = new HashSet<>(getNlNames());
toReturn.add(getConceptCycL());
return toReturn;
}
@Override
public int compareTo(KBConcept o) {
return this.getName().toLowerCase().compareTo(o.getName().toLowerCase());
}
/**
* @return the conceptCycL
*/
public String getConceptCycL() {
return conceptCycL;
}
/**
*
* @return conceptUri
*/
public String getConceptUri() {
return conceptUri;
}
/**
*
* @return concept CycL
*/
public String getCycL() {
return getConceptCycL();
}
/**
*
* @return conceptIndex
*/
public int getIndex() {
return conceptIndex;
}
/**
*
* @return concept name
*/
public abstract String getName();
/**
*
* @return html to set concept to "unclickable"
*/
public String getNameUnclick() {
return "<span class='unclickable'>" + getName() + "</span>";
}
/**
* @return the nlNames
*/
public Set<String> getNlNames() {
return nlNames;
}
/**
* @param nlNames the nlNames to set
*/
public void setNlNames(Set<String> nlNames) {
this.nlNames = nlNames;
}
/**
*
* @return formatted String based on the concept index
*/
public String getRef() {
return String.format("concept%06d", getIndex());
}
/**
* Returns the maximum depth of a child node.
*
* @return in integer representing the maximum depth
*/
public int height() {
if (getChildSpecLinks().isEmpty() && getNonTaxonomicLinks().isEmpty()) {
return 0;
}
int max = 0;
for (KBLink c : getChildSpecLinks()) {
int h = c.getFrom().height();
if (h > max) {
max = h;
}
}
if (!getNonTaxonomicLinks().isEmpty()) {
if (1 > max) {
max = 1;
}
}
return max + 1;
}
/**
*
* @return true if concept is selected
*/
public boolean isSelected() {
return selected;
}
/**
*
* @param selected
*/
public void setSelected(boolean selected) {
this.selected = selected;
}
/**
* Returns the total leaf node count below this
*
* @return total leaf node count
*/
public int nLeaves() {
if (getChildSpecLinks().isEmpty()) {
return 1;
}
int leaves = 0;
for (KBLink c : getChildSpecLinks()) {
int l = c.getFrom().nLeaves();
leaves += l;
}
return leaves;
}
/**
* Returns the total leaf node count below this, assuming the tree has a max-depth of depth.
*
* @param depth
* @return total leaf node count
*/
public int nLeaves(int depth) {
if (getChildSpecLinks().isEmpty() || depth == 0) {
return 1;
}
int leaves = 0;
for (KBLink c : getChildSpecLinks()) {
int l = c.getFrom().nLeaves(depth - 1);
leaves += l;
}
return leaves;
}
/**
*
* @return incremented index
*/
public synchronized int nextIndex() {
lastConceptIndex++;
return lastConceptIndex;
}
/**
* Set selected flag to true.
*/
public void setSelected() {
this.selected = true;
}
/**
* Set selected flag to false.
*/
public void setUnselected() {
this.selected = false;
}
/**
*
* @param candidate
* @return true if the concept is subsumed in the the taxonomic links for candidate
*/
public boolean subsumedBy(KBConcept candidate) {
// System.out.println("SUBSUMED?:" + this + " by " + candidate);
for (KBLink childLink : candidate.getChildSpecLinks()) {
if (subsumedBy(childLink.getFrom())) {
return true;
}
}
return false;
}
/**
*
* @return HTML for Taxonomy Viewer
*/
public String toAnchor() {
String script = "";
int conceptNo = getIndex();
if (this instanceof OpenCycConcept) {
int depth = 2;
int width = this.nLeaves(depth);
script = writeGraphStarter("Cyc Concept #" + conceptNo + " " + this, conceptNo, this.getCycL(), depth, width);
} else if (this instanceof NonCycConcept) {
script = writeGraphStarter("NonCyc Team Concept #" + conceptNo + " " + this, conceptNo, this.getCycL(), 4, 5);
}
return "<a href='javascript:;' onclick=\"" + script + "\">" + getName() + "</a>";
// return "<a href='javascript:;' onclick=\"" + script + "\">" + getCycL()+ "</a>";
}
/**
*
* @return HTML for Taxonomy Viewer
*/
public String toCloseButton() {
//there is a argument for this method going in the jscript class
return "<button onclick='handleCloseConceptAnchor(\"" + getRef() + "\");'>☒</button>";
}
/**
*
* @param depth
* @return D3JSON output
*/
public abstract String toD3JSON(int depth);
/**
*
* @param depth
* @param dir
* @return D3JSON output
* @deprecated
*/
@Deprecated
abstract public String toD3JSON(int depth, GraphDirection dir);
/**
*
* @param depth
* @param depthLimit
* @param dir
* @return D3JSON output
*/
abstract public String toD3JSON(int depth, int depthLimit, GraphDirection dir);
/**
*
* @return D3JSON output
*/
@Override
public String toD3JSON() {
return toD3JSON(0, GraphDirection.down);
}
/**
*
* @param forLink
* @return D3JSON output
*/
abstract public String toD3JSONNoRecursion(NonTaxonomicLink forLink);
/**
*
* @param depth
* @return JSON output
*/
abstract public String toJSON(int depth);
/**
*
* @param depth
* @param dir
* @return JSON output
*/
abstract public String toJSON(int depth, GraphDirection dir);
/**
*
* @return JSON output
*/
@Override
public String toJSON() {
return toJSON(0, GraphDirection.down);
}
/**
*
* @return JSON output
*/
public abstract String toJSONNoRecursion();
/**
*
* @return HTML for Taxonomy Viewer
*/
public String toLabelledSpan() {
return "<span conceptID=\"" + getRef() + "\" onclick='handleClickedSelectedConceptSpan(\"" + getRef() + "\");'>" + getName() + "</span>";
}
/**
*
* @return HTML for Taxonomy Viewer
*/
public String toSelectedAnchor() {
// return "<a class=\"selectedTerm\" href='javascript:;' onclick='handleClickedConceptAnchor(\"" + getRef() + "\");'>" + getName() + "</a>";
return "<a class=\"selectedTerm\" href='javascript:;' onclick=\""
+ "collapsibleLinearGraph('" + String.format("%06d", getIndex()) + "','" + getConceptCycL()+ "'," + 4 + "," + 5 + "," + graphMaxDepth + ");\">"
+ getName()
+ "</a>";
}
@Override
public String toString() {
// return "KBTaxonomy:" + conceptCycL + " names:" + getName() + " N children:" + getChildSpecLinks().size();
return "KBTaxonomy:" + getConceptCycL() + " names:" + getName() + " N children:" + getNonTaxonomicLinks().size();
}
/**
*
* @return childSpecLinks
*/
protected abstract Set<KBLink> getChildSpecLinks();
/**
*
* @return children
*/
public abstract Set<KBConcept> getChildren();
/**
*
* @return generalLinks
*/
protected Set<KBLink> getGeneralLinks() {
return generalLinks;
}
/**
*
* @return NonTaxonomicLinks
*/
abstract protected Set<NonTaxonomicLink> getNonTaxonomicLinks();
/**
*
* @return parentLinks
*/
abstract protected Set<TaxonomicLink> getParentlinks();
/**
*
* @return parents
*/
abstract protected Set<KBConcept> getParents();
/**
*
* @return true if the concept has already been expanded
*/
protected boolean isExpanded() {
return expanded;
}
/**
* Expand the concept by setting the parents and children.
*/
protected final void maybeExpand() {
if (isExpanded()) {
return;
} else {
setParents();
// setParentLinks();
setChildren();
// setChildrenLinks();
setExpanded();
return;
}
}
/**
* Setter for children field.
*/
protected abstract void setChildren();
/**
* Setter for childrenLinks field.
*/
protected abstract void setChildrenLinks();
/**
* Set expanded flag to true.
*/
protected void setExpanded() {
this.expanded = true;
}
/**
* Setter for parentLinks field.
*/
protected abstract void setParentLinks();
/**
* Setter for parents field.
*/
protected abstract void setParents();
/**
* Enumeration of possible graph directions.
*/
public enum GraphDirection {
up, down
}
}