/* BlinkenLightsInteractiveMovieProgram
 * version 0.2 date 2004-11-10
 * Copyright (C) 2004: Stefan Schuermans <1stein@schuermans.info>
 * Copyleft: GNU public license - http://www.gnu.org/copyleft/gpl.html
 * a blinkenarea.org project
 * powered by eventphone.de
 */

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;

public class BlinkenFrameDisplay extends JLabel
                                 implements Scrollable, MouseListener, MouseMotionListener
{
  BlinkenFrame frame = null;
  int height = 0, width = 0, channels = 1, maxval = 1;
  int zoom = 8;
  Dimension dimension = new Dimension( 0, 0 );
  ImageIcon icon = null;
  Image image = null;
  Graphics graphics = null;
  BlinkenFrameDisplayListener displayListener = null;
  BlinkenFrameDisplayInterceptor displayInterceptor = null;

  public BlinkenFrameDisplay( )
  {
    addMouseListener( this );
    addMouseMotionListener( this );
  }

  public Dimension getPreferredScrollableViewportSize( )
  {
    return new Dimension( 200, 200 );
  }

  public int getScrollableBlockIncrement( Rectangle visibleRect, int orientation, int direction )
  {
    if( orientation == SwingConstants.HORIZONTAL )
      return visibleRect.width * 2 / 3 + 1;
    else
      return visibleRect.height * 2 / 3 + 1;
  }

  public boolean getScrollableTracksViewportHeight( )
  {
    return false;
  }

  public boolean getScrollableTracksViewportWidth( )
  {
    return false;
  }

  public int getScrollableUnitIncrement( Rectangle visibleRect, int orientation, int direction )
  {
    if( orientation == SwingConstants.HORIZONTAL )
      return visibleRect.width / 30 + 1;
    else
      return visibleRect.height / 30 + 1;
  }

  public void mouseClicked( MouseEvent e )
  {
    if( displayListener != null )
      displayListener.blinkenFrameDisplayClicked( e.getY( ) / zoom, e.getX( ) / zoom, height, width );
  }

  public void mouseEntered( MouseEvent e )
  {
    if( displayListener != null )
      displayListener.blinkenFrameDisplayEntered( e.getY( ) / zoom, e.getX( ) / zoom, height, width );
  }

  public void mouseExited( MouseEvent e )
  {
    if( displayListener != null )
      displayListener.blinkenFrameDisplayExited( e.getY( ) / zoom, e.getX( ) / zoom, height, width );
  }

  public void mousePressed( MouseEvent e )
  {
    if( displayListener != null )
      displayListener.blinkenFrameDisplayPressed( e.getY( ) / zoom, e.getX( ) / zoom, height, width );
  }

  public void mouseReleased( MouseEvent e )
  {
    if( displayListener != null )
      displayListener.blinkenFrameDisplayReleased( e.getY( ) / zoom, e.getX( ) / zoom, height, width );
  }

  public void mouseDragged( MouseEvent e )
  {
    if( displayListener != null )
      displayListener.blinkenFrameDisplayDragged( e.getY( ) / zoom, e.getX( ) / zoom, height, width );
  }

  public void mouseMoved( MouseEvent e )
  {
    if( displayListener != null )
      displayListener.blinkenFrameDisplayMoved( e.getY( ) / zoom, e.getX( ) / zoom, height, width );
  }

  public void setFrame( BlinkenFrame newFrame )
  {
    //remember frame
    frame = newFrame;

    //no frame
    if( frame == null )
    {
      //reset dimensions
      height = 0;
      width = 0;
      channels = 1;
      maxval = 1;
    }
    //frame available
    else
    {
      //get dimensions of frame
      height = frame.getHeight( );
      width = frame.getWidth( );
      channels = frame.getChannels( );
      maxval = frame.getMaxval( );
    }

    updateDisplay( );
  }

  public void setZoom( int zoomExp )
  {
    //get new zoom factor
    if( zoomExp < 0 )
      zoomExp = 0;
    if( zoomExp > 6 )
      zoomExp = 6;
    zoom = 1 << zoomExp;

    updateDisplay( );
  }

  public void updateDisplay( )
  {
    int h, w, y, yy, x, xx;
    boolean sizeChanged, newIcon;

    //calculate pixel dimensions
    h = height * zoom;
    w = width * zoom;
    sizeChanged = dimension.height != h || dimension.width != w;

    //update size
    if( sizeChanged )
    {
      dimension.height = h;
      dimension.width = w;
      setPreferredSize( dimension );
      revalidate( ); //propagate update
    }

    //no frame
    if( frame == null )
    {
      //remove image
      setIcon( null );
      image = null;
      graphics = null;
    }

    //frame available
    else
    {
      //create new image and icon
      newIcon = sizeChanged || icon == null || image == null || graphics == null;
      if( newIcon )
      {
        image = new BufferedImage( dimension.width, dimension.height, BufferedImage.TYPE_INT_RGB );
	icon = new ImageIcon( image );
	image = icon.getImage( );
        graphics = image.getGraphics( );
      }

      //create image from frame
      for( y = 0, yy = 0; y < height; y++, yy += zoom )
      {
        for( x = 0, xx = 0; x < width; x++, xx += zoom )
        {
          graphics.setColor( frame.getColor( y, x ) );
          graphics.fillRect( xx, yy, zoom, zoom );
        }
      }

      //call interceptor
      if( displayInterceptor != null )
        displayInterceptor.blinkenFrameDisplayNewImage( height, width, zoom, graphics );

      //update image
      if( newIcon )
	setIcon( icon );
      repaint( );
    }
  }

  public void setDisplayListener( BlinkenFrameDisplayListener newDisplayListener )
  {
    displayListener = newDisplayListener;
  }

  public void setDisplayInterceptor( BlinkenFrameDisplayInterceptor newDisplayInterceptor )
  {
    displayInterceptor = newDisplayInterceptor;
  }
}
