package com.xenoage.zong.commands.core.music;
import com.xenoage.utils.annotations.MaybeNull;
import com.xenoage.utils.annotations.Untested;
import com.xenoage.utils.document.command.Command;
import com.xenoage.utils.document.command.Undoability;
import com.xenoage.zong.core.Score;
import com.xenoage.zong.core.music.Part;
import com.xenoage.zong.core.music.Staff;
import com.xenoage.zong.core.music.StavesList;
import com.xenoage.zong.core.music.group.BarlineGroup;
import com.xenoage.zong.core.music.group.BracketGroup;
import java.util.ArrayList;
import java.util.List;
import static com.xenoage.utils.kernel.Range.range;
import static com.xenoage.utils.kernel.Range.rangeReverse;
import static com.xenoage.zong.core.music.Staff.staff;
/**
* Adds a given part to a score.
*
* The staves for the part are either given (the number of measures must
* match the number of measures in the score) or they are created with
* default settings and filled with empty measures, according to the number of measures in the score.
*
* @author Andreas Wenger
*/
@Untested public class PartAdd
implements Command {
//data
private Score score;
private Part part;
private int partIndex;
@MaybeNull List<Staff> staves;
//backup data
private int staffStartIndex;
public PartAdd(Score score, Part part, int partIndex, List<Staff> staves) {
if (staves != null && staves.size() != part.getStavesCount())
throw new IllegalArgumentException("number of staves is not equal");
this.score = score;
this.part = part;
this.partIndex = partIndex;
this.staves = staves;
}
@Override public void execute() {
//prepare staves
int measuresCount = score.getMeasuresCount();
if (staves == null) {
//staves are not given. create them with default settings
staves = new ArrayList<>(part.getStavesCount());
for (int i = 0; i < part.getStavesCount(); i++) {
Staff staff = staff(5, null);
staff.setParent(score.getStavesList());
staff.addEmptyMeasures(measuresCount); //fill with empty measures
this.staves.add(staff);
}
}
else {
//check staves and measures
for (int i : range(staves)) {
if (staves.get(i).getMeasures().size() != measuresCount)
throw new IllegalStateException("number of measures in score and staff " + i + " is not equal");
}
}
//add part
StavesList stavesList = score.getStavesList();
stavesList.getParts().add(partIndex, part);
//add staves
staffStartIndex = 0;
for (int iPart = 0; iPart < partIndex; iPart++)
staffStartIndex += stavesList.getParts().get(iPart).getStavesCount();
stavesList.getStaves().addAll(staffStartIndex, staves);
//shift the staff indexes of the groups
//beginning at the start index by the given number of staves
for (BracketGroup group : stavesList.getBracketGroups())
group.getStaves().insert(staffStartIndex, part.getStavesCount());
for (BarlineGroup group : stavesList.getBarlineGroups())
group.getStaves().insert(staffStartIndex, part.getStavesCount());
}
@Override public Undoability getUndoability() {
return Undoability.Undoable;
}
@Override public void undo() {
//remove part
StavesList stavesList = score.getStavesList();
stavesList.getParts().remove(partIndex);
//remove staves
for (int i : rangeReverse(staffStartIndex + part.getStavesCount(), staffStartIndex))
stavesList.getStaves().remove(i);
//shift staff indexes of the groups. we ignore the boolean return value of .remove
//because the staves we remove can not cross group borders in this context
for (BracketGroup group : stavesList.getBracketGroups())
group.getStaves().remove(staffStartIndex, part.getStavesCount());
for (BarlineGroup group : stavesList.getBarlineGroups())
group.getStaves().remove(staffStartIndex, part.getStavesCount());
}
}