
com.nedap.archie.base.Interval Maven / Gradle / Ivy
package com.nedap.archie.base;
import javax.annotation.Nullable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
import java.time.Duration;
import java.time.temporal.TemporalAmount;
import java.util.Objects;
/**
* Created by pieter.bos on 15/10/15.
*/
@XmlType(name="INTERVAL")
@XmlAccessorType(XmlAccessType.FIELD)
public class Interval extends OpenEHRBase {
@Nullable
private T lower;
@Nullable
private T upper;
@XmlAttribute(name="lower_unbounded")
private boolean lowerUnbounded = false;
@XmlAttribute(name="upper_unbounded")
private boolean upperUnbounded = false;
@XmlAttribute(name="lower_included")
private boolean lowerIncluded = true;
@XmlAttribute(name="upper_included")
private boolean upperIncluded = true;
public Interval() {
}
public Interval(T value) {
this.lower = value;
this.upper = value;
}
public Interval(T lower, T upper) {
this.lower = lower;
this.upper = upper;
}
public Interval(T lower, T upper, boolean lowerIncluded, boolean upperIncluded) {
this.lower = lower;
this.upper = upper;
this.lowerIncluded = lowerIncluded;
this.upperIncluded = upperIncluded;
}
public static Interval lowerUnbounded(T upper, boolean upperIncluded) {
Interval result = new Interval<>(null, upper, true, upperIncluded);
result.setLowerUnbounded(true);
return result;
}
public static Interval upperUnbounded(T lower, boolean lowerIncluded) {
Interval result = new Interval<>(lower, null, lowerIncluded, true);
result.setUpperUnbounded(true);
return result;
}
public T getLower() {
return lower;
}
public void setLower(T lower) {
this.lower = lower;
}
public T getUpper() {
return upper;
}
public void setUpper(T upper) {
this.upper = upper;
}
public boolean isLowerUnbounded() {
return lowerUnbounded;
}
public void setLowerUnbounded(boolean lowerUnbounded) {
this.lowerUnbounded = lowerUnbounded;
}
public boolean isUpperUnbounded() {
return upperUnbounded;
}
public void setUpperUnbounded(boolean upperUnbounded) {
this.upperUnbounded = upperUnbounded;
}
public boolean isLowerIncluded() {
return lowerIncluded;
}
public void setLowerIncluded(boolean lowerIncluded) {
this.lowerIncluded = lowerIncluded;
}
public boolean isUpperIncluded() {
return upperIncluded;
}
public void setUpperIncluded(boolean upperIncluded) {
this.upperIncluded = upperIncluded;
}
public boolean has(T value) {
if(lowerUnbounded && upperUnbounded) {
return true;
}
//since TemporalAmount does not implement Comparable we have to do some magic here
Comparable comparableValue;
Comparable comparableLower;
Comparable comparableUpper;
if(value instanceof TemporalAmount && !(value instanceof Comparable) && isNonComparableTemporalAmount(lower) && isNonComparableTemporalAmount(upper)) {
//TemporalAmount is not comparable, but can always be converted to a duration that is comparable.
comparableValue = value == null ? null : Duration.from((TemporalAmount) value);
comparableLower = lower == null ? null : Duration.from((TemporalAmount) lower);
comparableUpper = upper == null ? null : Duration.from((TemporalAmount) upper);
}
else if(!(isComparable(lower) && isComparable(upper) && isComparable(value))) {
throw new UnsupportedOperationException("subclasses of interval not implementing comparable should implement their own has method");
} else {
comparableValue = (Comparable) value;
comparableLower = (Comparable) lower;
comparableUpper = (Comparable) upper;
}
if(value == null) {
//interval values are not concerned with cardinality, so return true if not set
return true;
}
if(!lowerUnbounded) {
int comparedWithLower = comparableValue.compareTo(comparableLower);
if (comparedWithLower < 0 || (!lowerIncluded && comparedWithLower == 0)) {
return false;
}
}
if(!upperUnbounded) {
int comparedWithUpper = comparableValue.compareTo(comparableUpper);
if (comparedWithUpper > 0 || (!upperIncluded && comparedWithUpper == 0)) {
return false;
}
}
return true;
}
private boolean isNonComparableTemporalAmount(T value) {
return value == null || (!(value instanceof Comparable) && value instanceof TemporalAmount);
}
private boolean isComparable(T upper) {
return upper == null || upper instanceof Comparable;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Interval> interval = (Interval>) o;
return (lowerUnbounded == interval.lowerUnbounded) &&
(upperUnbounded == interval.upperUnbounded) &&
(lowerIncluded == interval.lowerIncluded) &&
(upperIncluded == interval.upperIncluded) &&
Objects.equals(lower, interval.lower) &&
Objects.equals(upper, interval.upper);
}
@Override
public int hashCode() {
return Objects.hash(lower,
upper,
lowerUnbounded,
upperUnbounded,
lowerIncluded,
upperIncluded);
}
@Override
public String toString() {
if(lowerUnbounded) {
return "|" + (upperIncluded ? "<=" : "<") + upper + "|";
}
if(upperUnbounded) {
return "|" + (lowerIncluded ? ">=" : ">") + lower + "|";
}
if(lower != null && upper != null && lower == upper) {
return lower.toString();
}
StringBuilder result = new StringBuilder();
result.append("|");
if(!lowerIncluded) {
result.append(">");
}
result.append(lower);
result.append("..");
if(!upperIncluded) {
result.append("<");
}
result.append(upper);
result.append("|");
return result.toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy