package com.xenoage.zong.layout.frames;
import static com.xenoage.utils.collections.CollectionUtils.alist;
import java.util.ArrayList;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import com.xenoage.utils.annotations.NonNull;
import com.xenoage.zong.core.Score;
import com.xenoage.zong.musiclayout.ScoreFrameLayout;
import com.xenoage.zong.musiclayout.ScoreLayout;
/**
* A list of connected {@link ScoreFrame}s.
*
* This class is also used for unconnected, single score frames.
*
* @author Andreas Wenger
*/
@RequiredArgsConstructor public class ScoreFrameChain {
/** The list of frames */
@Getter private ArrayList<ScoreFrame> frames = alist();
/** The score. */
@Getter @NonNull private Score score;
/** The score layouts in the frames. */
@Getter @Setter private ScoreLayout scoreLayout = null;
/**
* Adds the given frame to the end of the chain, if it is not already part
* of the chain.
* If the frame was already part of another chain, it is unregistered there.
* It is registered for this chain.
*/
public void add(ScoreFrame frame) {
if (frames.contains(frame)) {
throw new IllegalArgumentException("Score frame is already part of the chain!");
}
registerFrame(frame);
frames.add(frame);
}
/**
* Adds the given frame in the middle of the chain, after the given frame.
* If the frame is already part of the chain, it is moved to the new
* position.
* If the frame was already part of another chain, it is unregistered there.
* It is registered for this chain.
*/
public void add(ScoreFrame atFrame, ScoreFrame newFrame) {
if (!frames.contains(atFrame)) {
throw new IllegalArgumentException("Anchor frame does not exist!");
}
int pos = frames.indexOf(atFrame);
add(newFrame, pos + 1);
}
/**
* Adds the givenframe at the given position.
* If the frame is already part of the chain, it is moved to the new
* position.
* If the frame was already part of another chain, it is unregistered there.
* It is registered for this chain.
*/
public void add(ScoreFrame newFrame, int position) {
registerFrame(newFrame);
frames.remove(newFrame);
frames.add(position, newFrame);
}
/**
* Removes the given frame from this chain and unregisters the chain from the frame.
*/
public void remove(ScoreFrame frame) {
frames.remove(frame);
frame.setScoreFrameChain(null);
}
/**
* If the frame was already part of another chain, it is unregistered there.
* It is registered for this chain.
*/
private void registerFrame(ScoreFrame frame) {
if (frame.getScoreFrameChain() != null)
frame.getScoreFrameChain().remove(frame);
frame.setScoreFrameChain(this);
}
/**
* Returns true, if the given {@link ScoreFrame} is the first one in this
* score frame chain.
*/
public boolean isLeadingScoreFrame(ScoreFrame scoreFrame) {
return frames.get(0) == scoreFrame;
}
/**
* Gets the {@link ScoreFrameLayout} of the given {@link ScoreFrame}, or
* null if unknown.
*/
public ScoreFrameLayout getScoreFrameLayout(ScoreFrame frame) {
int frameIndex = frames.indexOf(frame);
if (frameIndex == -1)
return null;
return scoreLayout.frames.get(frameIndex);
}
}