package kr.gui;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;

import javax.swing.JComponent;
import javax.swing.JPanel;

import kr.AudioChannelModel;
import kr.AudioModel;
import kr.TimeKeeper;
import kr.gui.midigraph.MidiGraph;
import kr.miditunemodel.Event;
import kr.util.Listener;
import kr.util.ListenerManager;
import kr.util.audio.AudioClip;

public class AudioGraph extends MidiGraph
{

	private AudioChannelModel audioChannelModel;
	private GuiModel guiModel;
	private TimeKeeper timeKeeper;

	public AudioGraph(GuiModel guiModel, AudioChannelModel audioChannelModel) {
		this(guiModel, audioChannelModel, guiModel);
		
	}
	public AudioGraph(GuiModel guiModel, AudioChannelModel audioChannelModel, TimeKeeper timeKeeper) {
		super(guiModel);
		this.guiModel = guiModel;
		this.audioChannelModel = audioChannelModel;
		this.timeKeeper = timeKeeper;
	}
	
	private byte [] data;
	private long calibration;
	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 = timeKeeper.getCurrMicros() - calibration;

        //
        // Draw graph
        //
        //get all notes that are within the screen
        AudioClip clip = audioChannelModel.getClip();
        if(clip == null) return;
        
        int channels = clip.getNumChannels(); //TODO: HACK always displaying left channel

        
        double ratio = 1./guiModel.getPixelsToMicrosRatio() / clip.getMicrosToFrameRatio();
        int addition = clip.getFrameFromMicros(nowMicros);
        
        int lastY = -1;
        
        /*
        //FOR TESTING AudioClip.copyTo 
        int dataStart = (int)Math.round((startX-nowX)*ratio) + addition;
        int dataEnd = (int)Math.round((endX-nowX)*ratio) + addition;
        if(dataStart < 0) dataStart = 0;
        if(dataEnd > clip.length()) dataEnd = clip.length();
        data = new byte[dataEnd - dataStart];
        clip.copyTo(dataStart, dataEnd - dataStart, data, 0);

        g.setColor(Color.RED);

        for(int i = startX-1; i < endX; i++)
        {
        	int index = (int)Math.round((i-nowX) * ratio) + addition - dataStart;
        	index = index - index % channels;
        	int val;
        	if(index < 0 || index >= data.length) val = 0;
        	else
        		val = data[index];
        	int y = (int)Math.round((val+128.)/256.*h);
        	
        	if(lastY != -1)
        		g.drawLine(i-1, lastY, i, y); //draw a point
        	lastY = y;
        }
        */
        
        g.setColor(Color.BLUE);
        
        int sizeInFrames = clip.sizeInFrames();

        for(int i = startX-1; i < endX; i++)
        {
        	int frame = (int)((i-nowX) * ratio+.5) + addition;
        	frame = frame - frame % channels;
        	float val;
        	if(frame < 0 || frame > sizeInFrames) val = .5f;
        	else
        		val = clip.frameFloatVal(frame,0);
        	int y = (int)(val*h+.5);
        	
        	if(lastY != -1)
        		g.drawLine(i-1, lastY, i, y); //draw a point
        	lastY = y;
        }
        
        drawSelectionMarker(g, microsToPixels(guiModel.getSelectionStart()), true, startX, endX);
        drawSelectionMarker(g, microsToPixels(guiModel.getSelectionEnd()), false, startX, endX);
	}

	private void drawSelectionMarker(Graphics2D g, int x, boolean isStartMarker, int startX, int endX) {
		if(x >= startX -5 && x < endX + 5)
		{
	        g.setColor(Color.BLACK);
	        g.drawLine(x, 0, x, getHeight());
	        g.drawLine(x, getHeight() / 3, x + (isStartMarker ? -5 : 5), getHeight()/3-5);
	        g.drawLine(x, getHeight() / 3, x + (isStartMarker ? -5 : 5), getHeight()/3+5);
	        g.drawLine(x, getHeight() * 2 / 3, x + (isStartMarker ? -5 : 5), getHeight() * 2/3-5);
	        g.drawLine(x, getHeight() * 2 / 3, x + (isStartMarker ? -5 : 5), getHeight() * 2/3+5);
		}
	}

	/**
	 * An audio graph has no events
	 */
	//TODO: possibly seperate this out in a branch of the midigraph hierarchy which doesn't contain events
	public Event getEvent(int x, int y) {
		return null;
	}

	public AudioChannelModel getAudioChannelModel() {
		return audioChannelModel;
	}
	public void setTimeKeeper(TimeKeeper timeKeeper) {
		this.timeKeeper = timeKeeper;
		super.setTimeKeeper(timeKeeper);
	}
	
	public void setCalibration(long calibration) {
		this.calibration = calibration;
		
	}

	

	

}
