package kr.gui.metrodome;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;

import javax.swing.KeyStroke;

import kr.gui.GuiModel;
import kr.gui.midigraph.MidiGraph;
import kr.miditunemodel.Event;
import kr.miditunemodel.KREvent;
import kr.miditunemodel.MetrodomeEvent;
import kr.miditunemodel.MidiTuneModel;

public class MetrodomeGraph extends MidiGraph<MetrodomeEvent>
{
	private static final Color TICK_START_COLOR = Color.BLUE;
	private static final Color TICK_COLOR = Color.getHSBColor((float)(160/255.), (float)(80/255.), 1);
	private static final long serialVersionUID = 1L;
	private static final double QUARTER_NOTES_PER_MARK = .5;
	private static final Color TICK_SELECTED_COLOR = Color.BLACK;

	
	private MidiTuneModel model;

	public MetrodomeGraph(GuiModel guiModel, MidiTuneModel midiModel,
			MetrodomeGraphController cont) {
		super(guiModel);
		setFocusable(true);
		
		setOpaque(true);
		this.model = midiModel;

		Dimension size = new Dimension(100, 10);
		setPreferredSize(size);
		
		cont.init(guiModel, midiModel, this, guiModel.getMetrodomeGuiModel());
	}

	protected void doScrollingPaint(Graphics2D g, int startX, int endX) {
		// TODO: PERF, only redraw stuff that has been written over. If the
		// slider is moved,
		// slide over the bits and only redraw the new stuff

		int w = getWidth();
		int h = getHeight();

		g.setColor(Color.WHITE);
		g.fillRect(startX, 0, endX-startX, h);

		int nowX = guiModel.calcNowX(w);

		long nowMicros = guiModel.getNowMicros();

		// TODO: merge repeated code from MidiGraph and AudioGraph
		long startMicros = guiModel.pixelsToMicros(startX, w);
		long endMicros = guiModel.pixelsToMicros(endX, w);

        //
        // Draw beats
        //
        g.setColor(Color.RED);
        
        for( long beatMicros: guiModel.getMetrodomeGuiModel().getBeats(startMicros, endMicros))
        {
        	int x = microsToPixels(beatMicros);
        	g.drawLine(x, 0, x, h);
        }

        //
		// Draw ticks
		//

        //get all notes that are within the screen
        //PERF specify a starting point
        MetrodomeEvent n = model.getMetrodomeEventGroup().getAtOrBeforeMicros(null, 0, startMicros);
        if(n == null) n = model.getMetrodomeEventGroup().getEvents().getFirst(); 
        
        while(n != null && n.getMicros() < endMicros)
        {
			drawDivisions(g, startX, endX, n.getMicros(), n.getEndMicros(), n.getQuarterNoteMicros(), guiModel.getMetrodomeGuiModel().isSelectedEvent(n));
        	n = (MetrodomeEvent)n.getNext();
		}
        
	}

	private void drawDivisions(Graphics2D g, int startX, int endX, long micros, long endMicros, long quarterNoteMicros, boolean selected) {
		int x1 = microsToPixels(micros);
		startX = Math.max(x1, startX);
		
		int x2 = endMicros == -1 ?  getWidth(): Math.min(getWidth(), microsToPixels(endMicros));
		endX = Math.min(x2, endX);
		
		if(endX <= startX) return;

		int h = getHeight();
		double tickPixels = guiModel.getPixelsToMicrosRatio() * quarterNoteMicros;
		
		if(startX <= x1)
		{
			g.setColor(TICK_START_COLOR);
			g.drawLine(x1, 0, x1, h);
			
			if(selected)
			{
				g.setColor(TICK_SELECTED_COLOR);
				drawBud(g, x1, 1);
				drawBud(g, x1, h-2);
			}
		}
		
		g.setColor(TICK_COLOR);
		g.drawLine(startX+1, h/2, endX,h/2);
			
		int c = (int)Math.max(1,Math.floor((startX - x1) / tickPixels / QUARTER_NOTES_PER_MARK));
		while(true)
		{
			int x = (int) Math.round(tickPixels * QUARTER_NOTES_PER_MARK *  c++ + x1);
			if(x > endX)
				break;
			g.drawLine(x, 0, x, h);
		}
	}

	private void drawBud(Graphics2D g, int x, int y) {
		g.fillRect(x-1, y-1, 3, 3);		
	}

	public MetrodomeEvent getEvent(int x, int y) {
		long startMicros = guiModel.pixelsToMicros(x, getWidth());

		//PERF: starting point
		return model.getMetrodomeEventGroup().getPrevEvent(null, startMicros);
	}

	public long getDivisionLength(long quarterNoteMicros) {
		return (long) (QUARTER_NOTES_PER_MARK * quarterNoteMicros);
	}

}
