package com.cyc.tool.kbtaxonomy.viewer;
/*
* #%L
* KBTaxonomyViewer2015
* %%
* 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.tool.kbtaxonomy.builder.NonCycConcept;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* <p>
* A modifiable set of features that describes some thing (possibly depicted).
*
*/
public class FeatureSet {
final private Set<Feature> features = new HashSet<>();
private int lastFeatureNum = 1;
final private Map<String, Feature> map = new HashMap<>();
private String setName = null;
private String setSource = null;
/**
* FeatureSet constructor
*
* @param xmlFromFile
*/
public FeatureSet(File xmlFromFile) {
map.clear();
features.clear();
try {
setSource = xmlFromFile.getCanonicalPath();
DocumentBuilderFactory dbFactoryOld = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilderOld = dbFactoryOld.newDocumentBuilder();
Document docOld = dBuilderOld.parse(xmlFromFile);
docOld.getDocumentElement().normalize();
setName = docOld.getDocumentElement().getAttribute("eventID");
NamedNodeMap nodeAttribs = docOld.getDocumentElement().
getElementsByTagName("node")
.item(0)
.getAttributes();
String weightMap = nodeAttribs.getNamedItem("eq")
.getNodeValue().replaceFirst("\\s*combine\\s+", "");
NodeList nListOld = docOld.getElementsByTagName("tag");
for (int i = 0; i < nListOld.getLength(); i++) {
Node nNode = nListOld.item(i);
Element eElement = (Element) nNode;
features.add(new Feature(eElement.getAttribute("name"), eElement.getAttribute("id")));
}
String weightMatcher = "^(CC\\.\\d+)=(.+)$";
Arrays.asList(weightMap.split(",")).forEach(s -> {
if (s.matches(weightMatcher)) {
String sID = s.replaceFirst(weightMatcher, "$1");
String sWe = s.replaceFirst(weightMatcher, "$2");
map.get(sID).weight = Float.parseFloat(sWe);
}
});
/* Export Weights */
map.values().forEach(feat -> {
feat.getConcept().setWeight(feat.getWeight());
});
} catch (ParserConfigurationException | SAXException | IOException ex) {
Logger.getLogger(FeatureSet.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* Construct FeatureSet from a set of NonCyc concepts
*
* @param concepts
* @param setN
*/
public FeatureSet(Collection<NonCycConcept> concepts, String setN) {
map.clear();
features.clear();
setName = setN;
concepts.forEach(con -> {
for (Integer id : con.getNonCycTeamNumericID()) {
features.add(new Feature(con, id));
}
});
}
/**
*
* @return setName
*/
public String getFeatureSetName() {
return setName;
}
/**
*
* @return a Set of NonCycConcepts in the FeatureSet
*/
public Set<NonCycConcept> getSet() {
return features.stream()
.map(Feature::getConcept)
// .sorted()
.collect(Collectors.toSet());
}
/**
* Save out a FeatureSet to a file
*
* @param file
*/
public void save(File file) {
try (PrintWriter out = new PrintWriter(file)) {
out.print(toXML());
} catch (FileNotFoundException ex) {
System.out.println("Failed to write XML in " + file.getAbsolutePath());
Logger.getLogger(FeatureSet.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Override
public String toString() {
return ("Features for event kit " + setName)
+ (" From file: " + setSource)
+ (" Number of features: " + features.size())
+ (" Features: ["
+ features.stream().map(Feature::toString).sorted().collect(Collectors.joining(", "))
+ "]");
}
/**
* Get String representation of the feature set without weights
*
* @return a String
*/
public String toStringNoWeight() {
return ("Features for event kit " + setName)
+ (" From file: " + setSource)
+ (" Number of features: " + features.size())
+ (" Features: ["
+ features.stream().map(Feature::toStringNoWeight).sorted().collect(Collectors.joining(", "))
+ "]");
}
/**
* Get XML representation of the feature set
*
* @return a String
*/
public String toXML() {
return "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
+ "<query eventID=\"" + setName + "\">\n"
+ nodeXML(" ")
+ "</query>";
}
private String combineXML() {
return "combine "
+ features.stream().sorted()
.map(Feature::toWeightXML)
.collect(Collectors.joining(","));
}
private String nodeXML(String indent) {
return indent + "<node eq=\"" + combineXML() + "\" id=\"CC\" name=\"concepts/cycorp\">\n"
+ tagsXML(indent + " ") + "\n"
+ indent + "</node>\n";
}
private String tagsXML(String indent) {
return features.stream().sorted().map(f -> f.toTagXML(indent + " ")).collect(Collectors.joining("\n"));
}
synchronized int nextFeatureNum() {
lastFeatureNum++;
return lastFeatureNum;
}
private class Feature implements Comparable<Feature> {
String name;
String tagID;
Integer nonCycTeamIDNumber;
String conceptUri;
Float weight;
static final String matcher = "^([^/]*)/(\\d+)$";
public Feature(String fromSingle, String tagId) {
if (fromSingle.matches(matcher)) {
name = fromSingle.replaceFirst(matcher, "$1");
String num = fromSingle.replaceFirst(matcher, "$2");
nonCycTeamIDNumber = Integer.parseInt(num);
conceptUri = "";
tagID = tagId;
map.put(tagID, this);
}
}
public Feature(NonCycConcept c, Integer id) {
name = c.getName();
nonCycTeamIDNumber = id;
conceptUri = "";
tagID = String.format("CC.%d", nextFeatureNum());
weight = c.getWeight();
map.put(tagID, this);
}
public Float getWeight() {
return weight;
}
public String getName() {
return name;
}
public NonCycConcept getConcept() {
return NonCycConcept.getFromIDNameOpt(nonCycTeamIDNumber, name, conceptUri);
}
String toWeightXML() {
return tagID + "=" + weight;
}
String toNameWithTeamID() {
return name + ":" + nonCycTeamIDNumber;
}
String toTagXML(String indent) {
return indent + "<tag id=\"" + tagID + "\" name=\"" + toNameWithTeamID() + "\"/>";
}
@Override
public String toString() {
return toStringNoWeight() + "/W:" + toWeightXML();
}
public String toStringNoWeight() {
return toNameWithTeamID();
}
@Override
public int compareTo(Feature o) {
return o.getWeight().compareTo(this.getWeight());
}
}
}