package tudelft.healthpsychology.traumaontologies.answerstate; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.util.StdConverter; import tudelft.healthpsychology.traumaontologies.questiontypes.TypedQuestion; import tudelft.utilities.tree.Tree; /** * Handles the process in filling in the properties of an {@link OntologyNode}. * The most accurate available {@link OntologyNode} was determined already. The * process here is to get answers to all the questions relevant for such a node. * Properties are picked up from the comment fields behind the given * OntologyNode and its parents.
* immutable. * */ public class PropertiesAnswerState implements AnswerState { private final String nodelabel; @JsonSerialize(converter = PropMapSerializer.class) private final Map answers; /** * * @param object the ontologynode class for which all properties need to be * collected and answered. * @param answers the already collected answers to the properties */ @JsonCreator public PropertiesAnswerState(@JsonProperty("nodelabel") String objectlabel, @JsonProperty("answers") @JsonDeserialize(converter = PropMapDeserializer.class) Map answers) { this.nodelabel = objectlabel; this.answers = answers; } /** * Convenience constructor for initial state * * @param nodelabel the label of initial node */ @SuppressWarnings("unchecked") public PropertiesAnswerState(String nodelabel) { this(nodelabel, Collections.EMPTY_MAP); } @Override public PropertiesAnswerState with(String answer, Tree, OntologyNode> tree) { Property property = getProperty(tree); if (property == null) return this; if (!property.getQuestionType().fits(answer)) { throw new IllegalArgumentException("The answer string must fit an " + property.getQuestionType()); } Map newanswers = new HashMap( answers); newanswers.put(property, answer); return new PropertiesAnswerState(nodelabel, newanswers); } /** * * @return the main node label for this object. Mainly for testing */ public String getNode() { return nodelabel; } @Override public TypedQuestion getOptions( Tree, OntologyNode> tree) { Property prop = getProperty(tree); if (prop == null) return null; return prop.getQuestionType(); } /** * * @return the answers given so far. */ public Map getAnswers() { return answers; } /** * * @return the property to be answered, or null if no such property (all * have been answered) */ private Property getProperty( Tree, OntologyNode> tree) { Set remaining = new HashSet<>( tree.get(nodelabel).getAttribute()); remaining.removeAll(answers.keySet()); if (remaining.isEmpty()) { return null; } return remaining.iterator().next(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((answers == null) ? 0 : answers.hashCode()); result = prime * result + ((nodelabel == null) ? 0 : nodelabel.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; PropertiesAnswerState other = (PropertiesAnswerState) obj; if (answers == null) { if (other.answers != null) return false; } else if (!answers.equals(other.answers)) return false; if (nodelabel == null) { if (other.nodelabel != null) return false; } else if (!nodelabel.equals(other.nodelabel)) return false; return true; } } /****** serialization of key-value pair of Map **********/ class PropString { @JsonProperty private final Property prop; @JsonProperty private final String answer; @JsonCreator public PropString(@JsonProperty("prop") Property prop, @JsonProperty("answer") String answer) { this.prop = prop; this.answer = answer; } public Property getProp() { return prop; } public String getAnswer() { return answer; } } /** * Custom serializer to map the Map into a List * */ class PropMapSerializer extends StdConverter, List> { private final ObjectMapper mapper = new ObjectMapper(); @Override public List convert(Map propstringmap) { List list = new LinkedList(); for (Map.Entry pair : propstringmap.entrySet()) { list.add(new PropString(pair.getKey(), pair.getValue())); } return list; } } /** * Custom deserializer to map the List back to a Map * */ class PropMapDeserializer extends StdConverter, Map> { private final ObjectMapper mapper = new ObjectMapper(); @Override public Map convert(List valuelist) { Map propsmap = new HashMap<>(); for (PropString prop : valuelist) { propsmap.put(prop.getProp(), prop.getAnswer()); } return propsmap; } }