package org.herac.tuxguitar.gui.editors.tab;
import java.util.ArrayList;
import java.util.List;
import org.herac.tuxguitar.gui.editors.tab.layout.ViewLayout;
import org.herac.tuxguitar.song.models.TGVoice;
public class TGBeatGroup {
private static final int SCORE_MIDDLE_KEYS[] = new int[]{55,40,40,50};
private static final int SCORE_SHARP_POSITIONS[] = new int[]{7,7,6,6,5,4,4,3,3,2,2,1};
private static final int SCORE_FLAT_POSITIONS[] = new int[]{7,6,6,5,5,4,3,3,2,2,1,1};
public static final int DIRECTION_NOT_SETTED = 0;
public static final int DIRECTION_UP = 1;
public static final int DIRECTION_DOWN = 2;
private static final int UP_OFFSET = 28;
private static final int DOWN_OFFSET = 35;
private int voice;
private int direction;
private List voices;
private TGNoteImpl firstMinNote;
private TGNoteImpl firstMaxNote;
private TGNoteImpl lastMinNote;
private TGNoteImpl lastMaxNote;
private TGNoteImpl maxNote;
private TGNoteImpl minNote;
public TGBeatGroup(int voice){
this.voice = voice;
this.voices = new ArrayList();
this.direction = DIRECTION_NOT_SETTED;
this.firstMinNote = null;
this.firstMaxNote = null;
this.lastMinNote = null;
this.lastMaxNote = null;
this.maxNote = null;
this.minNote = null;
}
public void check(TGVoiceImpl voice){
this.check(voice.getMaxNote());
this.check(voice.getMinNote());
this.voices.add( voice );
if( voice.getDirection() != TGVoice.DIRECTION_NONE ){
if( voice.getDirection() == TGVoice.DIRECTION_UP ){
this.direction = DIRECTION_UP;
}
else if( voice.getDirection() == TGVoice.DIRECTION_DOWN ){
this.direction = DIRECTION_DOWN;
}
}
}
private void check(TGNoteImpl note){
int value = note.getRealValue();
//FIRST MIN NOTE
if(this.firstMinNote == null || note.getVoice().getBeat().getStart() < this.firstMinNote.getVoice().getBeat().getStart()){
this.firstMinNote = note;
}else if(note.getVoice().getBeat().getStart() == this.firstMinNote.getVoice().getBeat().getStart()){
if(note.getRealValue() < this.firstMinNote.getRealValue()){
this.firstMinNote = note;
}
}
//FIRST MAX NOTE
if(this.firstMaxNote == null || note.getVoice().getBeat().getStart() < this.firstMaxNote.getVoice().getBeat().getStart()){
this.firstMaxNote = note;
}else if(note.getVoice().getBeat().getStart() == this.firstMaxNote.getVoice().getBeat().getStart()){
if(note.getRealValue() > this.firstMaxNote.getRealValue()){
this.firstMaxNote = note;
}
}
//LAST MIN NOTE
if(this.lastMinNote == null || note.getVoice().getBeat().getStart() > this.lastMinNote.getVoice().getBeat().getStart()){
this.lastMinNote = note;
}else if(note.getVoice().getBeat().getStart() == this.lastMinNote.getVoice().getBeat().getStart()){
if(note.getRealValue() < this.lastMinNote.getRealValue()){
this.lastMinNote = note;
}
}
//LAST MIN NOTE
if(this.lastMaxNote == null || note.getVoice().getBeat().getStart() > this.lastMaxNote.getVoice().getBeat().getStart()){
this.lastMaxNote = note;
}else if(note.getVoice().getBeat().getStart() == this.lastMaxNote.getVoice().getBeat().getStart()){
if(note.getRealValue() > this.lastMaxNote.getRealValue()){
this.lastMaxNote = note;
}
}
if(this.maxNote == null || value > this.maxNote.getRealValue()){
this.maxNote = note;
}
if(this.minNote == null || value < this.minNote.getRealValue()){
this.minNote = note;
}
}
public void finish(ViewLayout layout, TGMeasureImpl measure){
if( this.direction == DIRECTION_NOT_SETTED ){
if (measure.getNotEmptyVoices() > 1 ){
this.direction = this.voice == 0 ? DIRECTION_UP : DIRECTION_DOWN;
}else if ( (layout.getStyle() & ViewLayout.DISPLAY_SCORE) == 0 ){
this.direction = DIRECTION_DOWN;
}else{
int max = Math.abs(this.minNote.getRealValue() - (SCORE_MIDDLE_KEYS[measure.getClef() - 1] + 100));
int min = Math.abs(this.maxNote.getRealValue() - (SCORE_MIDDLE_KEYS[measure.getClef() - 1] - 100));
if(max > min){
this.direction = DIRECTION_UP;
}else{
this.direction = DIRECTION_DOWN;
}
}
}
}
public List getVoices(){
return this.voices;
}
public int getY1(ViewLayout layout,TGNoteImpl note,int key,int clef){
double scale = (layout.getScoreLineSpacing() / 2.00);
int noteValue = note.getRealValue();
int scoreLineY = 0;
if(key <= 7){
scoreLineY = (int)((SCORE_SHARP_POSITIONS[noteValue % 12]) * scale - (7 * (noteValue / 12)) * scale);
}else{
scoreLineY = (int)((SCORE_FLAT_POSITIONS[noteValue % 12]) * scale - (7 * (noteValue / 12)) * scale);
}
scoreLineY += TGMeasureImpl.SCORE_KEY_OFFSETS[clef - 1] * scale;
return scoreLineY;
}
public int getY2(ViewLayout layout,int x,int key,int clef){
int maxDistance = 10;
float upOffset = TGBeatGroup.getUpOffset(layout);
float downOffset = TGBeatGroup.getDownOffset(layout);
if(this.direction == DIRECTION_DOWN){
if(this.minNote != this.firstMinNote && this.minNote != this.lastMinNote){
return (int) (getY1(layout,this.minNote,key,clef) + downOffset);
}
int y = 0;
int x1 = this.firstMinNote.getPosX() + this.firstMinNote.getBeatImpl().getSpacing();
int x2 = this.lastMinNote.getPosX() + this.lastMinNote.getBeatImpl().getSpacing();
int y1 = (int) (getY1(layout,this.firstMinNote,key,clef) + downOffset);
int y2 = (int) (getY1(layout,this.lastMinNote,key,clef) + downOffset);
if(y1 > y2 && (y1 - y2) > maxDistance) y2 = (y1 - maxDistance);
if(y2 > y1 && (y2 - y1) > maxDistance) y1 = (y2 - maxDistance);
//int y = (int)((((double)y1 -(double)y2) / ((double)x1 - (double)x2)) * ((double)x1 - (double)x));
if( (y1 - y2) != 0 && (x1 - x2) != 0 && (x1 - x) != 0){
y = (int)((((double)y1 -(double)y2) / ((double)x1 - (double)x2)) * ((double)x1 - (double)x));
}
return y1 - y;
}else if(this.maxNote != this.firstMaxNote && this.maxNote != this.lastMaxNote){
return (int)(getY1(layout,this.maxNote,key,clef) - upOffset);
}else{
int y = 0;
int x1 = this.firstMaxNote.getPosX() + this.firstMaxNote.getBeatImpl().getSpacing();
int x2 = this.lastMaxNote.getPosX() + this.lastMaxNote.getBeatImpl().getSpacing();
int y1 = (int)(getY1(layout,this.firstMaxNote,key,clef) - upOffset);
int y2 = (int)(getY1(layout,this.lastMaxNote,key,clef) - upOffset);
if(y1 < y2 && (y2 - y1) > maxDistance) y2 = (y1 + maxDistance);
if(y2 < y1 && (y1 - y2) > maxDistance) y1 = (y2 + maxDistance);
if( (y1 - y2) != 0 && (x1 - x2) != 0 && (x1 - x) != 0){
y = (int)((((double)y1 -(double)y2) / ((double)x1 - (double)x2)) * ((double)x1 - (double)x));
}
return y1 - y;
}
}
public int getDirection() {
return this.direction;
}
public TGNoteImpl getMinNote(){
return this.minNote;
}
public TGNoteImpl getMaxNote(){
return this.maxNote;
}
public static float getUpOffset(ViewLayout layout){
float scale = (layout.getScoreLineSpacing() / 8.0f);
return (UP_OFFSET * scale);
}
public static float getDownOffset(ViewLayout layout){
float scale = (layout.getScoreLineSpacing() / 8.0f);
return (DOWN_OFFSET * scale);
}
}