
class PixelPanel {
  private int width, height;
  private boolean yIsDown;

  native public PixelPanel( int width, int height );

  public int getWidth() {
    return width;
  }

  public int getHeight() {
    return height;
  }

  native public void setTitle( String title );

  native public void flipY();

  native public void clear( Color color );

  native public void drawPixel( int x, int y, Color color );

  native public void drawLine( int x0, int y0, int x1, int y1, Color color );

  native public void drawRectangle( int x, int y, int width, int height, Color color );

  native public void drawImage( int x, int y, PixelImage image );

  native public void fillRectangle( int x, int y, int width, int height, Color color );

  public void update() {
    animate();

    renderSprites();

    updatePixels();
  }

  private native void updatePixels();

  /*
   * key listeners
   */
  private ArrayList keyListeners = new ArrayList();

  public void addKeyListener( KeyListener listener ) {
    if ( !keyListeners.contains( listener ) )
      keyListeners.add( listener );
  }

  public void removeKeyListener( KeyListener listener ) {
    keyListeners.remove( listener );
  }

  // called from native
  private void fireKeyDown( char c ) {
    for ( int i=0; i<keyListeners.size(); i++  )
      ((KeyListener) keyListeners.get( i )).handleKeyDown( this, c );
  }

  // called from native
  private void fireKeyUp( char c ) {
    for ( int i=0; i<keyListeners.size(); i++  )
      ((KeyListener) keyListeners.get( i )).handleKeyUp( this, c );
  }

  /*
   * mouse listeners
   */
  private ArrayList mouseListeners = new ArrayList();

  public void addMouseListener( MouseListener listener ) {
    if ( !mouseListeners.contains( listener ) )
      mouseListeners.add( listener );
  }

  public void removeKeyListener( MouseListener listener ) {
    mouseListeners.remove( listener );
  }

  // called from native
  private void fireMouseClicked( int pixelX, int pixelY ) {
    for ( int i=0; i<mouseListeners.size(); i++  )
      ((MouseListener) mouseListeners.get( i )).handleMouseClicked( this, pixelX, pixelY );
  }

  /*
   * animations
   */
  private AnimationList animations = new AnimationList();

  public void addAnimation( Animation animation ) {
    animation.reset();

    animations.add( animation );
  }

  public boolean removeAnimation( Animation animation ) {
    return animations.remove( animation );
  }

  private long lastAnimateMillis = 0;

  private void animate() {
    long nowMillis = currentTimeMillis();
    double delta;

    if ( lastAnimateMillis != 0 )
      delta = ( nowMillis - lastAnimateMillis ) / 1000.0;
    else
      delta = 0.0;

    lastAnimateMillis = nowMillis;

    animations.animate( delta );
  }

  /*
   * sprites
   */
  private PixelSpriteList sprites = new PixelSpriteList();

  public void addSprite( PixelSprite sprite ) {
    addSprite( sprite, 0 );
  }

  public void addSprite( PixelSprite sprite, int layer ) {
    sprites.add( sprite, layer );
  }

  public boolean removeSprite( PixelSprite sprite ) {
    return sprites.remove( sprite );
  }

  private void renderSprites() {
    sprites.render( this, 0.0, 0.0 );
  }
}
