package com.xenoage.zong.core.music.util;
import static com.xenoage.zong.core.music.util.Interval.Result.FalseHigh;
import static com.xenoage.zong.core.music.util.Interval.Result.FalseLow;
import static com.xenoage.zong.core.music.util.Interval.Result.True;
import com.xenoage.utils.math.Fraction;
import com.xenoage.zong.core.position.MP;
/**
* This enumeration is used when searching elements
* relative to a given position.
*
* <ul>
* <li>Before: ]-∞, position[</li>
* <li>BeforeOrAt: ]-∞, position]</li>
* <li>At: [position, position]</li>
* <li>AtOrAfter: [position, +∞[</li>
* <li>After: ]position, +∞[</li>
* </ul>
*
* Meaning: "]...[" is exclusive, "[...]" is inclusive.
*
* @author Andreas Wenger
*/
public enum Interval {
/** Before a position. */
Before,
/** Before or exactly at a position. */
BeforeOrAt,
/** Exactly at a position. */
At,
/** After or exactly at a position. */
AtOrAfter,
/** After a position. */
After;
public enum Result {
/** Not in the range, but before. */
FalseLow,
/** Within the range. */
True,
/** Not in the range, but afterwars. */
FalseHigh;
}
/**
* Returns true, if the index is in the given interval
* relative to the given reference index, or if it is too low or too high.
*/
public Result isInInterval(int index, int referenceIndex) {
int compare = (index > referenceIndex ? 1 : (index < referenceIndex ? -1 : 0));
return isInInterval(compare);
}
/**
* Returns true, if the beat is in the given interval
* relative to the given reference beat, or if it is too low or too high.
*/
public Result isInInterval(Fraction beat, Fraction referenceBeat) {
int compare = beat.compareTo(referenceBeat);
return isInInterval(compare);
}
/**
* Returns, if the given {@link MP} is in the given interval
* relative to the given reference {@link MP}, or if it is too low or too high.
*/
public Result isInInterval(MP bmp, MP referenceMP) {
int compare = bmp.compareTo(referenceMP);
return isInInterval(compare);
}
private Result isInInterval(int compare) {
switch (this) {
case Before:
return (compare < 0 ? True : FalseHigh);
case BeforeOrAt:
return (compare <= 0 ? True : FalseHigh);
case At:
return (compare == 0 ? True : (compare < 0 ? FalseLow : FalseHigh));
case AtOrAfter:
return (compare >= 0 ? True : FalseLow);
case After:
return (compare > 0 ? True : FalseLow);
}
throw new IllegalArgumentException("Unknown interval type: " + this);
}
/**
* Returns true, if this interval is {@link #Before}, {@link #BeforeOrAt} or {@link #At}.
*/
public boolean isPrecedingOrAt() {
return this == Before || this == BeforeOrAt || this == At;
}
}