package com.xenoage.zong.io.musicxml.in.readers;
import static com.xenoage.utils.iterators.It.it;
import lombok.RequiredArgsConstructor;
import com.xenoage.utils.annotations.MaybeNull;
import com.xenoage.zong.core.format.Break;
import com.xenoage.zong.core.format.StaffLayout;
import com.xenoage.zong.core.format.SystemLayout;
import com.xenoage.zong.core.header.ScoreHeader;
import com.xenoage.zong.core.music.layout.PageBreak;
import com.xenoage.zong.core.music.layout.SystemBreak;
import com.xenoage.zong.musicxml.types.MxlPrint;
import com.xenoage.zong.musicxml.types.MxlStaffLayout;
import com.xenoage.zong.musicxml.types.MxlSystemLayout;
import com.xenoage.zong.musicxml.types.attributes.MxlPrintAttributes;
import com.xenoage.zong.musicxml.types.enums.MxlYesNo;
import com.xenoage.zong.musicxml.types.groups.MxlLayout;
/**
* Reads a {@link MxlPrint} to the {@link Context}.
*
* @author Andreas Wenger
*/
@RequiredArgsConstructor
public class PrintReader {
private final MxlPrint mxlPrint;
public void readToContext(Context context) {
ScoreHeader header = context.getScore().getHeader();
int measure = context.getMp().measure;
//system and page break
Break break_ = readBreak();
if (break_ != null) {
//MusicXML print is in the first broken measure, but we
//store the break in the last measure before the break (thus -1)
int breakMeasure = measure - 1;
if (breakMeasure >= 0) //ignore, when in the first measure
context.writeColumnElement(break_, breakMeasure);
}
//we assume that custom system layout information is just used in combination with
//forced system/page breaks. so we ignore system-layout elements which are not combined
//with system/page breaks.
//the first measure of a score is also ok.
if (measure == 0 || break_ != null) {
//first page or new page?
boolean isPageBreak = break_ != null && break_.getPageBreak() == PageBreak.NewPage;
boolean isPageStarted = (measure == 0 || isPageBreak);
if (isPageBreak) {
//increment page index
context.incPageIndex();
}
//first system or new system?
boolean isSystemBreak = isPageBreak ||
(break_ != null && break_.getSystemBreak() == SystemBreak.NewSystem);
if (isSystemBreak) {
//increment system index
context.incSystemIndex();
}
//read system layout, if there
SystemLayout systemLayout = readSystemLayout(isPageStarted, context.getTenthMm());
if (systemLayout != null)
header.setSystemLayout(context.getSystemIndex(), systemLayout);
//staff layouts
MxlLayout mxlLayout = mxlPrint.getLayout();
if (mxlLayout != null) {
for (MxlStaffLayout mxlStaffLayout : it(mxlLayout.getStaffLayouts())) {
int staffIndex = mxlStaffLayout.getNumberNotNull() - 1;
//get system layout. if it does not exist yet, create it
systemLayout = header.getSystemLayout(context.getSystemIndex());
if (systemLayout == null) {
systemLayout = new SystemLayout();
header.setSystemLayout(context.getSystemIndex(), systemLayout);
}
StaffLayout staffLayout = new StaffLayoutReader(mxlStaffLayout, context.getTenthMm()).read();
systemLayout.setStaffLayout(
context.getPartStaffIndices().getStart() + staffIndex, staffLayout);
}
}
}
}
private Break readBreak() {
MxlPrintAttributes mxlPA = mxlPrint.getPrintAttributes();
SystemBreak systemBreak = readSystemBreak(mxlPA.getNewSystem());
PageBreak pageBreak = readPageBreak(mxlPA.getNewPage());
if (systemBreak != null || pageBreak != null)
return new Break(pageBreak, systemBreak);
return null;
}
@MaybeNull private SystemBreak readSystemBreak(MxlYesNo mxlSystemBreak) {
if (mxlSystemBreak == MxlYesNo.Yes)
return SystemBreak.NewSystem;
else if (mxlSystemBreak == MxlYesNo.No)
return SystemBreak.NoNewSystem;
else
return null;
}
@MaybeNull private PageBreak readPageBreak(MxlYesNo mxlPageBreak) {
if (mxlPageBreak == MxlYesNo.Yes)
return PageBreak.NewPage;
else if (mxlPageBreak == MxlYesNo.No)
return PageBreak.NoNewPage;
else
return null;
}
private SystemLayout readSystemLayout(boolean isPageStarted, float tenthMm) {
MxlLayout mxlLayout = mxlPrint.getLayout();
if (mxlLayout != null) {
MxlSystemLayout mxlSystemLayout = mxlLayout.getSystemLayout();
if (mxlSystemLayout != null) {
SystemLayoutReader systemLayoutReader = new SystemLayoutReader(mxlSystemLayout, tenthMm);
SystemLayout systemLayout = systemLayoutReader.read();
Float topSystemDistance = systemLayoutReader.getTopSystemDistance();
//for first systems on a page, use top-system-distance
if (isPageStarted && topSystemDistance != null)
systemLayout.setDistance(topSystemDistance);
return systemLayout;
}
}
return null;
}
}