package jpianotrain.gui;
import static jpianotrain.util.ResourceKeys.LABEL_NOTE;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
import javax.swing.table.DefaultTableModel;
import jpianotrain.staff.Chord;
import jpianotrain.staff.Duration;
import jpianotrain.staff.Note;
import jpianotrain.staff.NoteName;
import jpianotrain.staff.Scale;
import jpianotrain.staff.ScaleName;
import jpianotrain.util.ResourceFactory;
import org.apache.log4j.Logger;
/**
* Table model to render a set of chords spread across
* all twelve notes and filtering chords, not represented
* by notes of a given scale.
*
* @author onkobu
* @since 0.0.3
*/
public class ChordTableModel extends DefaultTableModel {
private static final Logger log=Logger.getLogger(ChordTableModel.class);
private static final Vector<Chord.ChordName> columnNames = new Vector<Chord.ChordName>(
Arrays.asList(Chord.ChordName.values()));
public ChordTableModel(ScaleName sn) {
super(columnNames, sn.getMapping().length * NoteName.values().length);
scaleName=sn;
scaleBuffer=new HashMap<Integer, Scale>();
chordBuffer=new HashMap<Integer, Map<Integer, Chord>>();
}
@Override
public Class<?> getColumnClass(int col) {
return col==0?Note.class:Chord.class;
}
@Override
public int getColumnCount() {
return columnNames.size() + 1;
}
@Override
public String getColumnName(int idx) {
if (idx == 0) {
return ResourceFactory.getString(LABEL_NOTE);
}
return columnNames.get(idx - 1).toString();
}
@Override
public int getRowCount() {
if (scaleName==null) {
return 0;
} else {
int notesPerScale = scaleName.getMapping().length;
int notesPerScaleTotal = notesPerScale + 1;
int notesPerBlock=notesPerScaleTotal+1;
int rootNotes = Scale.MAJOR_SCALES_CLASSIC.length;
return (notesPerBlock * rootNotes);
}
}
@Override
public Object getValueAt(int row, int col) {
//log.debug("getValueAt("+row+", "+col+")");
if (scaleName==null) {
return null;
}
int notesPerScale=scaleName.getMapping().length;
int notesPerScaleTotal=notesPerScale+1;
int notesPerBlock=notesPerScaleTotal+1;
int offset=row/notesPerBlock;
//log.debug("offset.......: "+offset+" ("+notesPerBlock+")");
// there's a delimiting empty row
// after each scale's cycle
if (row>notesPerScale && (row%notesPerBlock)==notesPerScaleTotal) {
//log.debug("is an empty row");
return null;
}
int rowWithoutEmpty=row-offset;
//log.debug("effective Row: "+rowWithoutEmpty);
int nameIdx=rowWithoutEmpty/notesPerScaleTotal;
Scale s=scaleBuffer.get(nameIdx);
if (s==null) {
//log.debug("nameIdx......: "+nameIdx);
if (scaleName.isMajor()) {
NoteName nn=Scale.MAJOR_SCALES_CLASSIC[nameIdx];
s=new Scale(nn, scaleName);
} else {
NoteName nn=Scale.MINOR_SCALES_CLASSIC[nameIdx];
s=new Scale(nn, scaleName);
}
scaleBuffer.put(nameIdx, s);
}
int noteIdx=rowWithoutEmpty%notesPerScaleTotal;
//log.debug("note index: "+noteIdx);
if (col==0) {
return s.getNote(noteIdx);
}
Map<Integer, Chord> cMap=chordBuffer.get(rowWithoutEmpty);
if (cMap==null) {
cMap=new HashMap<Integer, Chord>();
chordBuffer.put(rowWithoutEmpty, cMap);
}
Chord c=cMap.get(col-1);
if (c==null) {
c=Chord.create(s.getNote(noteIdx), columnNames.get(col-1));
if (s.contains(c, true)) {
cMap.put(col-1, c);
} else {
cMap.put(col-1, FAIL_CHORD);
c=null;
}
}
return c;
}
@Override
public boolean isCellEditable(int row, int col) {
return false;
}
private static final Chord FAIL_CHORD=new Chord(Duration.WHOLE);
private Map<Integer, Map<Integer, Chord>> chordBuffer;
private Map<Integer, Scale> scaleBuffer;
private ScaleName scaleName;
}