/*
 * Created on 04-ene-2006
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package org.herac.tuxguitar.graphics.control;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.herac.tuxguitar.graphics.TGPainter;
import org.herac.tuxguitar.graphics.TGRectangle;
import org.herac.tuxguitar.song.models.TGTrack;

/**
 * @author julian
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
public class TGLayoutVertical extends TGLayout{
	
	private int maximumWidth;
	private int marginLeft;
	private int marginRight;
	
	public TGLayoutVertical(TGController controller,int style){
		super(controller,style);
	}
	
	public int getMode(){
		return MODE_VERTICAL;
	}
	
	public void paintSong(TGPainter painter,TGRectangle clientArea,int fromX,int fromY) {
		this.marginLeft = getFirstMeasureSpacing();
		this.marginRight = 10;
		this.maximumWidth = (clientArea.getWidth() - (this.marginLeft + this.marginRight));
		this.setHeight(0);
		this.setWidth(0);
		this.clearTrackPositions();
		
		int style = getStyle();
		int number = getComponent().getTrackSelection();
		int posY = fromY + getFirstTrackSpacing();
		int height = getFirstTrackSpacing();
		int lineHeight = 0;
		
		int measureCount = getSongManager().getSong().countMeasureHeaders();
		int nextMeasureIndex = 0;
		while(measureCount > nextMeasureIndex){
			TempLine line = null;
			Iterator tracks = getSongManager().getSong().getTracks();
			while(tracks.hasNext()){
				TGTrackImpl track = (TGTrackImpl) tracks.next();
				if(number < 0 || track.getNumber() == number){
					
					TGTrackSpacing ts = new TGTrackSpacing(this) ;
					ts.setSize(TGTrackSpacing.POSITION_SCORE_MIDDLE_LINES, ((style & DISPLAY_SCORE) != 0 ?( (getScoreLineSpacing() * 5) ):0));
					
					if(nextMeasureIndex == 0){
						((TGLyricImpl)track.getLyrics()).start();
					}
					
					line = getTempLines(track,nextMeasureIndex,ts);
					if( (style & DISPLAY_SCORE) != 0 ){
						ts.setSize(TGTrackSpacing.POSITION_SCORE_UP_LINES, Math.abs(line.minY));
						if(line.maxY > track.getScoreHeight()){
							ts.setSize(TGTrackSpacing.POSITION_SCORE_DOWN_LINES, (line.maxY - track.getScoreHeight()) );
						}
					}
					if((style & DISPLAY_TABLATURE) != 0){
						ts.setSize(TGTrackSpacing.POSITION_TABLATURE_TOP_SEPARATOR, ((style & DISPLAY_SCORE) != 0 ? getMinScoreTabSpacing() : Math.max(Math.abs(line.minY), getStringSpacing()) ));
						ts.setSize(TGTrackSpacing.POSITION_TABLATURE, ((style & DISPLAY_SCORE) != 0 ?  track.getTabHeight() + getStringSpacing() + 1 : Math.max( line.maxY, track.getTabHeight() + getStringSpacing() + 1) ));
					}
					ts.setSize(TGTrackSpacing.POSITION_LYRIC,10);
					checkDefaultSpacing(ts);
					
					paintLine(track,line,painter,fromX,posY,ts,clientArea);
					
					lineHeight = ts.getSize();
					addTrackPosition(track.getNumber(),posY,lineHeight);
					
					int emptyX = (this.marginLeft + fromX + line.tempWith + 2);
					int emptyWith = ( this.maximumWidth - emptyX );
					if((emptyWith - 20) > 0 && (line.lastIndex + 1) >= measureCount){
						if(emptyX < (clientArea.getX() + clientArea.getWidth())){
							emptyX = (emptyX < clientArea.getX() ? clientArea.getX() :emptyX);
							emptyWith = ( emptyWith > clientArea.getWidth() ? clientArea.getWidth() : emptyWith );
							paintLines(track,ts,painter, emptyX ,posY, emptyWith);
						}
					}
					
					posY += lineHeight + getTrackSpacing();
					height += lineHeight + getTrackSpacing();
				}
			}
			if(line != null){
				nextMeasureIndex = line.lastIndex + 1;
			}
		}
		
		this.setHeight(height);
		this.setWidth( getWidth() + this.marginRight );
	}
	
	public void paintLine(TGTrackImpl track,TempLine line,TGPainter painter,int fromX, int fromY,TGTrackSpacing ts,TGRectangle clientArea) {
		int posX = (this.marginLeft + fromX);
		int posY = fromY;
		int width = this.marginLeft;
		
		//verifico si esta en el area de cliente
		boolean isAtY = (posY + ts.getSize() > clientArea.getY() && posY < clientArea.getY() + clientArea.getHeight() + 80);
		
		int measureSpacing = 0;
		if(line.fullLine){
			int diff = ( this.maximumWidth - line.tempWith);
			if(diff != 0 && line.measures.size() > 0){
				measureSpacing = diff / line.measures.size();
			}
		}
		
		for(int i = 0;i < line.measures.size();i ++){
			int index = ((Integer)line.measures.get(i)).intValue();
			TGMeasureImpl currMeasure = (TGMeasureImpl)track.getMeasure(index);
			
			//asigno la posicion dentro del compas
			currMeasure.setPosX(posX);
			currMeasure.setPosY(posY);
			currMeasure.setTs(ts);
			
			((TGLyricImpl)track.getLyrics()).setCurrentMeasure(currMeasure);
			
			currMeasure.setFirstOfLine(i == 0);
			
			int measureWidth = ( currMeasure.getWidth(this) + measureSpacing );
			boolean isAtX = ( posX + measureWidth > clientArea.getX() && posX < clientArea.getX() + clientArea.getWidth());
			if(isAtX && isAtY){
				paintMeasure(currMeasure,painter,measureSpacing);
				((TGLyricImpl)track.getLyrics()).paintCurrentNoteBeats(painter,this,currMeasure,posX, posY);
			}else{
				currMeasure.setOutOfBounds(true);
			}
			
			posX += measureWidth;
			width += measureWidth;
		}
		this.setWidth(Math.max(getWidth(),width));
	}
	
	public TempLine getTempLines(TGTrack track,int fromIndex,TGTrackSpacing ts) {
		int style = getStyle();
		
		TempLine line = new TempLine();
		line.maxY = 0;
		line.minY = 0;
		
		// Need to score extra-lines in edition mode
		if( (style & DISPLAY_TABLATURE) == 0 && (style & DISPLAY_SCORE) != 0 ){
			line.maxY = ((getScoreLineSpacing() * 4) + (getScoreLineSpacing() * 4));
			line.minY = -(getScoreLineSpacing() * 3);
		}
		
		int measureCount = track.countMeasures();
		for (int measureIdx = fromIndex; measureIdx < measureCount; measureIdx++) {
			TGMeasureImpl measure = (TGMeasureImpl)track.getMeasure(measureIdx);
			
			//verifico si tengo que bajar de linea
			if((line.tempWith + measure.getWidth(this)) >= this.maximumWidth && !line.measures.isEmpty()){
				line.fullLine = true;
				return line;
			}
			line.tempWith +=  measure.getWidth(this);
			line.maxY = (measure.getMaxY() > line.maxY)?measure.getMaxY():line.maxY;
			line.minY = (measure.getMinY() < line.minY)?measure.getMinY():line.minY;
			
			line.addMeasure(measureIdx);
			measure.registerSpacing(this,ts);
		}
		
		return line;
	}
	
	private class TempLine{
		protected int tempWith;
		protected int lastIndex;
		protected boolean fullLine;
		protected int maxY = 0;
		protected int minY = 0;
		protected List measures;
		
		public TempLine(){
			this.measures = new ArrayList();
		}
		
		protected void addMeasure(int index){
			this.measures.add(new Integer(index));
			this.lastIndex = index;
		}
	}
}
