package kr.gui;

import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.FocusAdapter;
import java.io.File;
import java.io.IOException;

import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.Sequence;
import javax.sound.midi.Track;
import javax.swing.BoxLayout;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

import kr.util.Util;

import kr.AudioModel;
import kr.gui.midigraph.MidiGraph;
import kr.gui.midigraph.MidiTuneGraphController;
import kr.gui.midigraph.MidiTextGraphController;
import kr.miditunemodel.Event;
import kr.miditunemodel.MidiTuneModel;
import kr.miditunemodel.NoteEvent;
import kr.util.Listener;
import kr.util.ListenerManager;

public class MidiTextGraph extends MidiGraph
{

	private MidiTuneModel model;

	private static final Font TEXT_FONT = new Font("Arial", Font.PLAIN, 18);

	private FontMetrics fm;

	private JTextField textEdit;

	public MidiTextGraph(GuiModel guiModel, MidiTuneModel midiModel,
			MidiTextGraphController midiController) {
		super(guiModel);
		
		setOpaque(true);
		this.model = midiModel;

		setFont(TEXT_FONT);

		//
		// find minimum size
		//
		fm = this.getFontMetrics(TEXT_FONT);
		Dimension size = new Dimension(20, fm.getHeight());
		setMinimumSize(size);
		setPreferredSize(size);
		
		textEdit = new JTextField();
		this.add(textEdit);
		textEdit.setVisible(false);
		
		midiController.init(guiModel, midiModel, this, guiModel.getNoteEventGuiModel());
	}

	private static final long serialVersionUID = 1L;

	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.setClip(startX, 0, endX-startX, h);
		g.setColor(Color.WHITE);
		g.fillRect(startX, 0, endX-startX, h);

		int nowX = guiModel.calcNowX(w);

		long nowMicros = guiModel.getNowMicros();

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

        //get all notes that are within the screen
        //PERF specify a starting point
        NoteEvent n = model.getNoteEventGroup().getAtOrBeforeMicros(null, 0, startMicros);
        if(n == null) n = model.getNoteEventGroup().getEvents().getFirst(); 
        
        while(n != null && n.getMicros() < endMicros)
        {
			drawText(g, nowMicros, n.getMicros(), n.getEndMicros(), n.getText(),
					guiModel.getNoteEventGuiModel().getSelectedEventsSize() == 1 ? 
					guiModel.getNoteEventGuiModel().isSelectedEvent(n) : false);
        	n = (NoteEvent)n.getNext();
		}
		g.setClip(0, 0, w, h);
	}

	private void drawText(Graphics2D g, long nowMicros, long micros, long endMicros, String text, boolean selected) {
		if(text == null) return;

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

		int x = guiModel.microsToPixels(w, nowMicros, micros);
		int y = fm.getAscent();

		g.setColor(Color.BLUE);
		g.setFont(TEXT_FONT);

		g.drawString(text, x, y);
		
		if(selected)
		{
			g.setColor(Color.BLACK);
			int endX = guiModel.microsToPixels(w, nowMicros, endMicros);
			
			drawBud(g, x-2,1);
			drawBud(g, x-2,h-2);
			drawBud(g, endX+2,1);
			drawBud(g, endX+2,h-2);
		}
	}

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

	public JTextField getEditTextField() {
		return textEdit;
	}

	public void editEvent(NoteEvent edittedEvent) {
		int pixels = microsToPixels(edittedEvent.getMicros());
		int endPixels = microsToPixels(edittedEvent.getEndMicros());
		textEdit.setBounds(pixels, 0, endPixels - pixels, getHeight());
		textEdit.setText(edittedEvent.getText());
		textEdit.selectAll();
		textEdit.setVisible(true);
		textEdit.requestFocus();
	}

	public void stopEdittingEvent() {
		textEdit.setVisible(false);
	}

	@Override
	public Event getEvent(int x, int y) {
		long micros = pixelsToMicros(x);

		//PERF: specify a starting point
		NoteEvent closestNote = model.getNoteEventGroup().getClosestEvent(null, micros);
		
		if(closestNote != null && closestNote.getMicros() <= micros && closestNote.getEndMicros() > micros)
			return closestNote;
		
		return null;
	}

}

class MidiGraphTextTest {
	public static void main(String[] args) throws Exception {
		Sequence sequence = null;
		File file = new File(args[0]);

		sequence = MidiSystem.getSequence(file);

		Track[] tracks = sequence.getTracks();

		MidiTuneModel m = new MidiTuneModel();

		m.readTune(sequence, tracks[1], tracks[1], false);

		JFrame f = new JFrame();

		Container content = f.getContentPane();
		content.setBackground(Color.white);
		content.setLayout(new BoxLayout(content, BoxLayout.PAGE_AXIS));

		content.add(new MidiTextGraph(new GuiModel(new AudioModel(), m), m,
				new MidiTextGraphController()));

		f.pack();
		f.setSize(600, 300);
		f.setVisible(true);
	}
}
