/* Copyright (C) 2000, 2003, 2004  Free Software Foundation

   This file is part of libgcj.

This software is copyrighted work licensed under the terms of the
Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
details.  */

package gnu.awt.xlib;

import java.awt.*;
import java.awt.image.WritableRaster;
import java.awt.image.Raster;
import java.awt.image.DataBuffer;
import java.awt.image.ColorModel;
import java.awt.image.ImageObserver;
import java.awt.image.BufferedImage;
import gnu.gcj.xlib.GC;
import gnu.gcj.xlib.XImage;
import gnu.gcj.xlib.Drawable;
import gnu.gcj.xlib.Window;
import gnu.gcj.xlib.Drawable;
import gnu.gcj.xlib.Pixmap;
import gnu.gcj.xlib.Visual;
import gnu.awt.j2d.DirectRasterGraphics;
import gnu.awt.j2d.MappedRaster;

public class XGraphics implements Cloneable, DirectRasterGraphics
{
  static class XRaster extends MappedRaster
  {
    XImage ximage;
    
    public XRaster(WritableRaster raster, XImage ximage, ColorModel cm)
    {
      super(raster, cm);
      this.ximage = ximage;
    }
  }
  
  GC context;
  XGraphicsConfiguration config;
  Rectangle clipBounds;
    
  XFontMetrics metrics;


  public Object clone()
  {
    try
      {
	XGraphics gfxCopy = (XGraphics) super.clone();
	gfxCopy.context = context.create();
	
	return gfxCopy;
      }
    catch (CloneNotSupportedException ex)
      {
	// This should never happen.
	throw new InternalError ();
      }
  }

  public void dispose()
  {
    GC lContext = context;
    context = null;
    config = null;
    clipBounds = null;
    metrics = null;
    
    if (lContext != null)
    {
      lContext.dispose();
    }	    
  }

  public XGraphics(Drawable drawable, XGraphicsConfiguration config)
  {
    context = GC.create(drawable);
    this.config = config;
  }  
  
  public void setColor(Color color)
  {
    context.setForeground(config.getPixel(color));
  }

  public void setPaintMode()
  {
    throw new UnsupportedOperationException("not implemented");
  }

  public void setXORMode(Color c1)
  {
    throw new UnsupportedOperationException("not implemented");
  }
    
  public void setFont(Font font)
  {
    if (font == null)
      return;
    if ((metrics != null) && font.equals(metrics.getFont()))
      return;
    metrics = config.getXFontMetrics(font);
    if (metrics != null)
      context.setFont(metrics.xfont);
  }
    
  public FontMetrics getFontMetrics(Font font)
  {
    if ((metrics != null) && font.equals(metrics.getFont()))
      return metrics;
    
    return config.getXFontMetrics(font);
  }
    
  public void setClip(int x, int y, int width, int height)
  {
    Rectangle[] rects = { new Rectangle(x, y, width, height) };
    context.setClipRectangles(rects);
  }
    
  public void setClip(Shape clip)
  {
    /* TODO: create a special RectangleUnion shape that can be
       used to draw advantage of the GCs ability to set multiple
       rectangles. 
    */

    /* FIXME: creating all these objects is wasteful and can be
       costly in the long run, since this code is run at every
       expose. */
    Rectangle newClipBounds = clip.getBounds();
    
    /* FIXME: decide whether this test code is worth anything
     * (as of 2004-01-29, it prints frequently)
    if ((clipBounds != null) && !clipBounds.contains(newClipBounds))
      {
	System.err.println("warning: old clip ("+ clipBounds +") does " +
			   "not fully contain new clip (" +
			   newClipBounds + ")");
      }
     */
    clipBounds = newClipBounds;
    Rectangle[] rects = { clipBounds };
    context.setClipRectangles(rects);
  }
    
  public void copyArea(int x, int y, int width, int height, int
		       dx, int dy)
  {
    throw new UnsupportedOperationException("not implemented");
  }
    
  public void drawLine(int x1, int y1, int x2, int y2)
  {
    context.drawLine(x1, y1, x2, y2);
  }
    
  public void drawRect(int x, int y, int width, int height)
  {
    throw new UnsupportedOperationException("not implemented yet");
  }
    
  public void fillRect(int x, int y, int width, int height)
  {
    context.fillRectangle(x, y, width, height);
  }
    
  public void drawArc(int x, int y, int width, int height, int
		      startAngle, int arcAngle)
  {
    context.drawArc (x, y, width, height, startAngle, arcAngle);
  }
    
  public void fillArc(int x, int y, int width, int height, int
		      startAngle, int arcAngle)
  {
    context.fillArc (x, y, width, height, startAngle, arcAngle);
  }
    
  public void drawPolyline(int[] xPoints, int[] yPoints, int
			   nPoints)
  {
    throw new UnsupportedOperationException("not implemented");
  }
    
  public void drawPolygon(int[] xPoints, int[] yPoints, int
			  nPoints)
  {
    throw new UnsupportedOperationException("not implemented");
  }
    
  public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints,
			  int translateX, int translateY)
  {
    context.fillPolygon(xPoints, yPoints, nPoints, translateX, translateY);
  }

  public void drawString(String str, int x, int y)
  {
    context.drawString(str, x, y);
  }

  public boolean drawImage(Image img, int x, int y,
			   ImageObserver observer)
  {
    if (img instanceof XOffScreenImage)
    {
      // FIXME: have to enforce clip, or is it OK as-is?
      XOffScreenImage offScreenImage = (XOffScreenImage) img;
      Pixmap pixmap = offScreenImage.getPixmap ();
      context.copyArea (pixmap, 0, 0, x, y,
        offScreenImage.getWidth (), offScreenImage.getHeight ());
      return true;
    }
    if (clipBounds == null)
      return false; // ***FIXME***

    if (!(img instanceof BufferedImage))
      {
	throw new AWTError("unknown image class");
      }
	
    BufferedImage bimg = (BufferedImage) img;

    XImage ximg = (XImage) bimg.getProperty("gnu.gcj.xlib.XImage");
    if (ximg == null)
      {
	System.err.println("FIXME: skipping null XImage, should " +
			   "really do on the spot conversion");
	return false;
      }

    /*
      +------------------
      |    clip
      |     +---------+
      | img |         |
      |  +--+-------+ |
      |  |  |       | | 
      |  |  |       | |
      |  |  +-------+-+
      |  |          |
      |  +----------+
    */

    int iLeft   = Math.max(x, clipBounds.x);
    int iTop    = Math.max(y, clipBounds.y);
    int iRight  = Math.min(x + bimg.getWidth(),
			   clipBounds.x + clipBounds.width);
    int iBottom = Math.min(y + bimg.getHeight(),
			   clipBounds.y + clipBounds.height);
    
    int srcX = iLeft - x;
    int srcY = iTop  - y;
    
    int width  = iRight  - iLeft;
    int height = iBottom - iTop;
    
    if ((width > 0) && (height > 0))
      context.putImage(ximg, srcX, srcY, iLeft, iTop, width, height);

    return true;
  }

  public MappedRaster mapRaster(Rectangle bounds)
  {
    Visual visual = config.getVisual();
    XImage ximage = new XImage(visual, bounds.width, bounds.height,
			       false // do not auto allocate memory
			       );

    WritableRaster raster =
      config.createRasterForXImage(ximage,
				   new Point(bounds.x, bounds.y));
    
    DataBuffer dataB = raster.getDataBuffer();
    XGraphicsConfiguration.attachData(ximage, dataB, 0);

    Drawable drawable = context.getDrawable();

    // TODO: restrict to clipping

    Rectangle mBounds = drawable.copyIntoXImage(ximage, bounds, 0, 0);
	
    return new XRaster(raster, ximage, config.imageCM);
  }
    
    
  public void unmapRaster(MappedRaster mappedRaster)
  {
    XRaster xraster = (XRaster) mappedRaster;
    XImage ximage = xraster.ximage;
    Raster raster = xraster.getRaster();
    int x = raster.getMinX();
    int y = raster.getMinY();
    int width = raster.getWidth();
    int height = raster.getHeight();
    
    context.putImage(ximage, 0, 0, x, y, width, height);
  }
}
