//Dstl (c) Crown Copyright 2017
package uk.gov.dstl.baleen.annotators.patterns.data;
import java.util.Collection;
import com.google.common.base.Strings;
import uk.gov.dstl.baleen.types.language.Interaction;
import uk.gov.dstl.baleen.types.language.WordToken;
import uk.gov.dstl.baleen.types.semantic.Entity;
import uk.gov.dstl.baleen.types.semantic.Relation;
/**
* A constraint which applies to a relation, constraining its type, source entity type, and target
* entity type.
*/
public class RelationConstraint {
private final String type;
private final String source;
private final String target;
private final String pos;
private final String subType;
private final char posChar;
/**
* Instantiates a new relation constraint.
*
* @param type
* the type
* @param source
* the source
* @param target
* the target
*/
public RelationConstraint(final String type, final String subType, final String pos, final String source,
final String target) {
this.type = type;
this.subType = subType;
this.pos = pos;
if (pos != null && pos.length() > 0) {
this.posChar = Character.toLowerCase(pos.charAt(0));
} else {
this.posChar = '?';
}
this.source = source;
this.target = target;
}
/**
* Gets the source.
*
* @return the source
*/
public String getSource() {
return source;
}
/**
* Gets the target.
*
* @return the target
*/
public String getTarget() {
return target;
}
/**
* Gets the POS.
*
* @return the part of speech
*/
public String getPos() {
return pos;
}
/**
* Gets the sub type.
*
* @return the sub type
*/
public String getSubType() {
return subType;
}
/**
* Gets the type.
*
* @return the type
*/
public String getType() {
return type;
}
/**
* Checks if this instance is valid.
*
* @return true, if is valid
*/
public boolean isValid() {
return !isNullOrEmpty(type, subType, pos, source, target);
}
/**
* Returns true if any of the strings in args are null or empty
*
* @param args
* @return
*/
private boolean isNullOrEmpty(String... args){
for(String a : args){
if(Strings.isNullOrEmpty(a))
return true;
}
return false;
}
/**
* Check is the relation provided matches this constraint.
*
* No inheritence and matches the full (not short) type name.
*
* @param relation
* the relation
* @param symmetric
* the symmetric (ie source and type can be swapped)
* @return true, if successful
*/
public boolean matches(final Relation relation, final boolean symmetric) {
final Entity sourceEntity = relation.getSource();
final Entity targetEntity = relation.getTarget();
final String sourceType = sourceEntity.getTypeName();
final String targetType = targetEntity.getTypeName();
final boolean relationType = type.equalsIgnoreCase(relation.getRelationshipType())
&& subType.equalsIgnoreCase(relation.getRelationSubType());
if (!symmetric) {
return relationType && typesEqual(sourceType, targetType);
} else {
return relationType && (typesEqual(sourceType, targetType) || typesEqual(targetType, sourceType));
}
}
private boolean typesEqual(String sourceType, String targetType){
return sourceType.equalsIgnoreCase(source) && targetType.equalsIgnoreCase(target);
}
/**
* Check if the interaction provided matches this constraint
*
* @return true, if successful
*/
public boolean matches(Interaction interaction, Collection<WordToken> words) {
String interactionType = interaction.getRelationshipType();
String interactionSubType = interaction.getRelationSubType();
boolean typeMatch = type.equalsIgnoreCase(interactionType) && subType.equalsIgnoreCase(interactionSubType);
if (words == null || words.isEmpty()) {
return typeMatch;
} else {
return typeMatch && words.stream()
.anyMatch(w -> posChar == Character.toLowerCase(w.getPartOfSpeech().charAt(0)));
}
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (source == null ? 0 : source.hashCode());
result = prime * result + (target == null ? 0 : target.hashCode());
result = prime * result + (type == null ? 0 : type.hashCode());
result = prime * result + (subType == null ? 0 : subType.hashCode());
result = prime * result + (pos == null ? 0 : pos.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;
}
final RelationConstraint other = (RelationConstraint) obj;
if (source == null) {
if (other.source != null) {
return false;
}
} else if (!source.equals(other.source)) {
return false;
}
if (target == null) {
if (other.target != null) {
return false;
}
} else if (!target.equals(other.target)) {
return false;
}
if (type == null) {
if (other.type != null) {
return false;
}
} else if (!type.equals(other.type)) {
return false;
}
if (subType == null) {
if (other.subType != null) {
return false;
}
} else if (!subType.equals(other.subType)) {
return false;
}
if (pos == null) {
if (other.pos != null) {
return false;
}
} else if (!pos.equals(other.pos)) {
return false;
}
return true;
}
@Override
public String toString() {
return this.source + "-" + this.type + "-" + this.target;
}
}