package com.xenoage.zong.core.util;
import static com.xenoage.utils.math.Fraction._0;
import static com.xenoage.zong.core.position.MP.mp;
import static com.xenoage.zong.core.position.MP.mp0;
import static com.xenoage.zong.core.position.MP.unknownMp;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import lombok.Getter;
import com.xenoage.zong.core.Score;
import com.xenoage.zong.core.music.VoiceElement;
import com.xenoage.zong.core.position.MP;
/**
* An iterator over all {@link VoiceElement}s in a score.
*
* Iterates over the staves, measures, voices and its voice elements.
*
* @author Andreas Wenger
*/
public class VoiceElementIterator
implements Iterator<VoiceElement>, Iterable<VoiceElement> {
private final Score score;
@Getter private MP mp = unknownMp;
private List<VoiceElement> elements;
private MP nextMp = mp0;
public VoiceElementIterator(Score score) {
this.score = score;
elements = score.getVoice(nextMp).getElements();
findNext();
}
@Override public boolean hasNext() {
return nextMp != null;
}
@Override public VoiceElement next() {
if (!hasNext())
throw new NoSuchElementException();
mp = nextMp;
VoiceElement element = elements.get(nextMp.element);
nextMp = nextMp.withElement(nextMp.element + 1);
nextMp = nextMp.withBeat(nextMp.beat.add(element.getDuration()));
findNext();
return element;
}
private void findNext() {
while (true) {
if (nextMp.element < elements.size()) {
//next element within voice exists
break;
}
else {
if (nextMp.voice + 1 < score.getMeasure(nextMp).getVoices().size()) {
//next measure within staff
nextMp = mp(nextMp.staff, nextMp.measure, nextMp.voice + 1, _0, 0);
}
else if (nextMp.measure + 1 < score.getMeasuresCount()) {
//next measure within staff
nextMp = mp(nextMp.staff, nextMp.measure + 1, 0, _0, 0);
}
else if (nextMp.staff + 1 < score.getStavesCount()) {
//next staff
nextMp = mp(nextMp.staff + 1, 0, 0, _0, 0);
}
else {
//finished
nextMp = null;
break;
}
elements = score.getVoice(nextMp).getElements();
}
}
}
@Override public Iterator<VoiceElement> iterator() {
return this;
}
@Override public void remove() {
throw new UnsupportedOperationException();
}
}