package kr.gui;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.WindowConstants;

import kr.gui.metrodome.MetrodomeGraphController;
import kr.util.audio.MixerAudioClip;
import kr.util.audio.TestBeatAudioClip;

public class KRCalibrationWindowController implements ActionListener, WindowListener
{

	private KRCalibrateWindow window;
	private Timer timer;
	private State state;
	private GuiModel guiModel;
	private long playStart;
	private long calibration, lastCalibration;
	private boolean blinkerState;
	private TestBeatAudioClip ac;
	private long startMicros;
	private double lastPlaybackRate;
	
	private enum State { PLAYING, STOPPED};

	public void init(final KRCalibrateWindow window, final GuiModel guiModel) {
		this.window = window;
		this.guiModel = guiModel;
		
		lastPlaybackRate = guiModel.getPlaybackRate();
		
		guiModel.setPlaybackRate(.5);

		lastCalibration = calibration = guiModel.getCalibrationMicros();
		guiModel.setCalibrationMicros(0);
		window.graph.setCalibration(calibration);

		updateCalibrationLabel();
		
		window.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
		window.addWindowListener(this);
		
		ac = new TestBeatAudioClip(guiModel.getAudioOut().getRate(),(byte)70, 1000000/2, 1000000/4 );
		
		window.graph.getAudioChannelModel().setClip(ac);
		
		//we use the real sample player as our timekeeper, so that we can move the graph without playing
		//the normal track
		window.graph.setTimeKeeper(guiModel.getTimeKeeper());
		
		guiModel.playAudioClip(ac);
		
		startMicros = guiModel.getTimeKeeper().getCurrMicros();
		
		window.finish.addActionListener(this);
		
		state = State.STOPPED;

		JComponent comp = ((JComponent) window.getContentPane());
		
		timer = new Timer(20, this);
		timer.start();
		
		comp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(
                KeyEvent.VK_B, 0),"beat");
		comp.getActionMap().put("beat", new AbstractAction()
				{
			public void actionPerformed(java.awt.event.ActionEvent e) 
			{
				long currMicros = guiModel.getTimeKeeper().getCurrMicros() - startMicros;
				long newCalibration1 = currMicros - ac.getMicrosFromIndex(ac.getLastBeatStart(ac.getIndexFromMicros(currMicros)));
				long newCalibration2 = currMicros - ac.getMicrosFromIndex(ac.getNextBeatStart(ac.getIndexFromMicros(currMicros)));
				
				long newCalibration;
				if(- newCalibration2 < newCalibration1 ) //if we are closer to the next note then we are to the previous
					//we assume that the user hit early
				{
					System.out.println("heard the note before it played? "+newCalibration2);
					newCalibration = 0;
				}
				else
					newCalibration = newCalibration1;
				
				if(calibration == 0)
					calibration = newCalibration;
				else
					calibration = Math.round(newCalibration * .5 + calibration *.5);
						
				window.graph.setCalibration(calibration);
				window.graph.repaintScrollingData();
				
				updateCalibrationLabel();
				
				System.out.println("calibration is "+calibration);
			}


				});

	}

	private void updateCalibrationLabel() {
		window.calibration.setText(String.format("%.5f secs", calibration / 1000000.));
	}
	
	public void actionPerformed(ActionEvent e) {
		if(e.getSource() == timer)
		{
			window.graph.repaint();
		}
		else if(e.getSource() == window.finish)
		{
			cleanup();
			guiModel.setCalibrationMicros(calibration);
		}
	}
	
	private void cleanup()
	{
		timer.stop();
		guiModel.stopPlayingAudioClip();
		guiModel.setPlaybackRate(lastPlaybackRate);
		guiModel.setCalibrationMicros(lastCalibration);
        this.window.setVisible(false);
	}

	public void windowOpened(WindowEvent e) {
		// TODO Auto-generated method stub
		
	}

	public void windowClosing(WindowEvent e) {
		cleanup();
	}

	public void windowClosed(WindowEvent e) {
		// TODO Auto-generated method stub
		
	}

	public void windowIconified(WindowEvent e) {
		// TODO Auto-generated method stub
		
	}

	public void windowDeiconified(WindowEvent e) {
		// TODO Auto-generated method stub
		
	}

	public void windowActivated(WindowEvent e) {
		// TODO Auto-generated method stub
		
	}

	public void windowDeactivated(WindowEvent e) {
		// TODO Auto-generated method stub
		
	}

}
