package kr.gui;

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

import javax.swing.JComponent;
import javax.swing.JViewport;

public abstract class XScrollingPane extends JComponent {
	//TODO: LOW: find a way to prevent flashing when drawing the "now" line
	
	int absX = 0;
	
	// Double buffer (for flipping images)
	private Graphics2D offscreenGraphics; // A graphics object for the buffer

	private Image offscreenImage = null; // The off screen image for double

	private boolean offScreenValid;
											// buffering

	public XScrollingPane() { 
		setDoubleBuffered(false);
	}
	
	protected void paintComponent(Graphics g1d)
	{
		//DebugTimer.start(this.toString());
		Graphics2D g = (Graphics2D)g1d;

		int w = getWidth();
		int h = getHeight();
		
		if (offscreenImage != null && (offscreenImage.getWidth(null) != w
				|| offscreenImage.getHeight(null) != h)) {
			offscreenImage = null;
		}

		if (offscreenImage == null) {
			//System.out.println("Creating double buffering");
			// set up double buffer
			offscreenImage = createImage(w, h);
			offscreenGraphics = (Graphics2D)offscreenImage.getGraphics();
			offScreenValid = false;
		}
		
		int newAbsX = getScrollAbs();
		
		if(Math.abs(newAbsX-absX) >=w)
			offScreenValid = false;
		
		if(offScreenValid)
		{
			scrollOffscreen(newAbsX);
			if(newAbsX < absX)
				doScrollingPaint(offscreenGraphics, 0, absX - newAbsX);
			else if(newAbsX != absX)
				doScrollingPaint(offscreenGraphics, w - (newAbsX - absX), w);
		}
		else
			doScrollingPaint(offscreenGraphics, 0, w);
		
		offScreenValid = true;
		absX = newAbsX;

		g.drawImage(offscreenImage, 0, 0, w, h, null);
		doOverlapPaint(g);
		
		//DebugTimer.end(this.toString());
	}
	
	public void repaintScrollingData()
	{
		offScreenValid = false;
		repaint();
	}
	
	/**
	 * Draw overlapping graphics, if any
	 */
	protected void doOverlapPaint(Graphics2D g) {
	}

	/**
	 * Paints the scrolling graphics to the screen. 
	 * @param startX the starting value of the area to be repainted
	 * @param endX the ending value of the area to be repainted
	 */
	protected abstract void doScrollingPaint(Graphics2D g, int startX, int endX);

	protected void scrollOffscreen(int newAbsX)
	{
		if(newAbsX > absX)
		{
			int startX = newAbsX - absX;
			
			offscreenGraphics.copyArea(startX, 0, getWidth() - startX, getHeight(), -startX,0);
		}
		else if(newAbsX < absX)
		{
			int endX = getWidth() - (absX - newAbsX);
			
			offscreenGraphics.copyArea(0, 0, endX, getHeight(), getWidth() - endX, 0);
		}
	}
	

	protected abstract int getScrollAbs();

	/*
	 * protected void paintComponent(Graphics g1d) { Graphics2D g =
	 * (Graphics2D)g1d;
	 * 
	 * //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
	 * 
	 * Rectangle clip = g.getClipBounds(); int w = getWidth(); int h =
	 * getHeight();
	 * 
	 * g.setColor(getBackground());
	 * g.fillRect(clip.x,clip.y,clip.width,clip.height);
	 * 
	 * int nowX = guiModel.calcNowX(w);
	 * 
	 * long nowMicros = guiModel.getNowMicros(); // // Draw notes // long
	 * startMicros = guiModel.getStartMicros(w); long endMicros =
	 * guiModel.getEndMicros(w);
	 * 
	 * //get all notes that are within the screen MidiTextModel.NoteEvent []
	 * notes = model.getNoteEvents(startMicros, endMicros);
	 * 
	 * for(int i = 0; i < notes.length; i++) { MidiTextModel.NoteEvent n =
	 * notes[i]; if(i != 0 && n.isContinuation()) { drawNoteLine(g, nowMicros,
	 * notes[i-1].getEndMicros(), notes[i-1].getNote(), n.getMicros(),
	 * n.getNote()); }
	 * 
	 * drawNoteLine(g, nowMicros, n.getMicros(), n.getNote(), n.getEndMicros(),
	 * n.getNote()); drawText(n.getMicros(), n.getText()); }
	 * 
	 * //draw line representing now g.setColor(Color.GRAY); g.drawLine(nowX, 0,
	 * nowX, h); }
	 */

}
