package com.xenoage.zong.core.music.group;
import static com.xenoage.utils.kernel.Range.range;
import lombok.Data;
import com.xenoage.utils.kernel.Range;
/**
* Range of adjacent staves.
*
* @author Andreas Wenger
*/
@Data
public final class StavesRange {
/** The index of the first staff of the range. */
private int start;
/** The index of the last staff of the range. */
private int stop;
/**
* Creates a new {@link StavesRange} with at least 1 staff.
*/
public StavesRange(int start, int stop) {
if (stop - start < 0)
throw new IllegalArgumentException("must contain at least 1 staff");
this.start = start;
this.stop = stop;
}
/**
* Gets the number of staves.
*/
public int getCount() {
return stop - start + 1;
}
/**
* Returns true, if the group contains the whole given group.
*/
public boolean contains(StavesRange staves) {
return (staves.start >= start && staves.stop <= stop);
}
/**
* Returns true, if the group intersects with the given group.
*/
public boolean intersects(StavesRange staves) {
return staves.start <= stop && staves.stop >= start;
}
/**
* Returns true, if the group contains the staff
* with the given index.
*/
public boolean contains(int index) {
return (index >= start && index <= stop);
}
/**
* Adds the given staves to this range.
*/
public StavesRange merge(StavesRange staves) {
int mergedStart = Math.min(staves.start, start);
int mergedStop = Math.max(staves.stop, stop);
return new StavesRange(mergedStart, mergedStop);
}
/**
* Gets this range as a {@link Range}.
*/
public Range getRange() {
return range(start, stop);
}
/**
* Shifts the indices by the given amount.
*/
public void shift(int amount) {
start += amount;
stop += amount;
}
/**
* Shifts the end index by the given amount.
*/
public void shiftEnd(int amount) {
stop += amount;
}
/**
* Inserts the given number of staves at the given position.
* If the position is before the start, the whole range is shifted.
* If the position is at or after the start, but at or before the end, only the end is shifted
* (i.e. the range is enlarged).
* If the position is after the end, nothing happens.
*/
public void insert(int index, int stavesCount) {
if (index < start)
shift(stavesCount); //shift start and end
else if (index <= stop)
shiftEnd(stavesCount); //shift only the end
}
/**
* Removes the given number of staves starting at the given position.
* If true is returned, the whole range was removed. If false is returned,
* this range is still alive and the start and stop values were modified.
*/
public boolean remove(int index, int stavesCount) {
int lastIndex = index + stavesCount - 1;
if (index <= start && lastIndex >= stop) {
//whole range is removed
return true;
}
else if (index >= start && lastIndex <= stop) {
//all removed staves are within this range
stop -= stavesCount;
}
else if (lastIndex < start) {
//removed range before this range. shift start and end
shift(-stavesCount);
}
else if (index > stop) {
//removed range after this range. nothing to do.
}
else if (index < start && lastIndex >= start) {
//a upper part of the range was removed
start = index;
stop = stop - lastIndex;
}
else if (index <= stop) {
//a lower part of the range was removed
stop = index - 1;
}
return false;
}
}