/* 
 * JGimp - A Java extension for the GIMP
 * Copyright (C) 2002  Georgia Tech Research Corp.
 * Written by Michael Terry, mterry@cc.gatech.edu
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

package org.gimp.jgimp.utils;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.awt.image.BandedSampleModel;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.awt.image.DirectColorModel;
import java.awt.image.Raster;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;

import javax.swing.JPanel;

import org.gimp.jgimp.JGimpDrawable;
import org.gimp.jgimp.JGimpImage;

/**
 * Given a GIMP image or drawable, this class will copy the pixels in
 * either the active drawable of an image, or the pixels of a given drawable,
 * and display them in a panel.
 */
public class JGimpImagePanel extends JPanel {
    private BufferedImage m_BufferedImage = null;

    /**
     * Creates an empty image panel
     */
    public JGimpImagePanel() {
        this.setBackground(Color.white);
    }

    /**
     * Constructs an image panel displaying the active layer of the given image
     */
    public JGimpImagePanel(JGimpImage inImage) {
        this.setBackground(Color.white);
        this.copyImage(inImage);
    }

    /**
     * Constructs an image panel displaying the given drawable
     */
    public JGimpImagePanel(JGimpDrawable inDrawable) {
        this.setBackground(Color.white);
        this.copyDrawable(inDrawable);
    }

    /**
     * Clears the image in this image panel, so that nothing is displayed by this panel
     */
    public void clearImage() {
        m_BufferedImage = null;
        this.repaint();
    }

    /**
     * Returns the image displayed by this image panel
     */
    public Image getImage() {
        return m_BufferedImage;
    }

    /**
     * Sets the image displayed in this image panel to the one in
     * the given drawable. The image panel automatically
     * resizes itself to match the proportions of the GIMP image.
     */
    public void copyDrawable(JGimpDrawable inDrawable) {
        if (inDrawable == null) {
            clearImage();
            return;
        }
        try {
            Dimension size = inDrawable.getSize();
            int bytesPerPixel = inDrawable.getBytesPerPixel();

            /* Stub: optimize JGimpImagePanel code when reusing an image panel (don't reallocate memory blocks)*/

            if (inDrawable.isRGB()) {
                if (bytesPerPixel == 4) {
                    int[] thePixels = inDrawable.readPixelRegionInNativeIntFormat(0, 0, size.width, size.height);
                    DataBufferInt dataBuffer = new DataBufferInt(thePixels, thePixels.length);
                    int[] bitMasks = { 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 };
                    WritableRaster writableRaster = Raster.createPackedRaster(dataBuffer, size.width, size.height, size.width, bitMasks, new Point());
                    ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);
                    ColorModel colorModel =
                        new DirectColorModel(colorSpace, 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000, false, dataBuffer.getDataType());
                    m_BufferedImage = new BufferedImage(colorModel, writableRaster, false, null);
                } else if (bytesPerPixel == 3) {
                    int[] thePixels = inDrawable.readPixelRegionInJavaIntFormat(0, 0, size.width, size.height);
                    m_BufferedImage = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_ARGB);
                    m_BufferedImage.setRGB(0, 0, size.width, size.height, thePixels, 0, size.width);
                } else {
                    System.out.println("Stub for RGB images with byte counts other than 3 or 4. Byte count: " + bytesPerPixel);
                }
            } else if (inDrawable.isGrayscale()) {
                if (bytesPerPixel == 1) {
                    byte[] thePixels = inDrawable.readPixelRegionInNativeByteFormat(0, 0, size.width, size.height);
                    DataBufferByte dataBuffer = new DataBufferByte(thePixels, thePixels.length);
                    ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_GRAY);
                    ColorModel colorModel = new ComponentColorModel(colorSpace, false, false, Transparency.TRANSLUCENT, dataBuffer.getDataType());
                    SampleModel sampleModel = new BandedSampleModel(dataBuffer.getDataType(), size.width, size.height, 1);
                    WritableRaster writableRaster = new sun.awt.image.ByteInterleavedRaster(sampleModel, dataBuffer, new Point());
                    m_BufferedImage = new BufferedImage(colorModel, writableRaster, false, null);
                } else {
                    /*
                    byte[] thePixels = inProxy.readPixelRegionAsBytes(inDrawable, 0, 0, size.width, size.height);
                    DataBufferByte dataBuffer = new DataBufferByte(thePixels, thePixels.length);
                    ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_GRAY);
                    ColorModel colorModel = new ComponentColorModel(colorSpace, true, false, Transparency.TRANSLUCENT, dataBuffer.getDataType());
                    int[] bandOffsets = { 0 };
                    SampleModel sampleModel = new PixelInterleavedSampleModel(dataBuffer.getDataType(), size.width, size.height, 1, size.width * 2, bandOffsets);
                    WritableRaster writableRaster = new sun.awt.image.ByteInterleavedRaster(sampleModel, dataBuffer, new Point());
                    m_BufferedImage = new BufferedImage(colorModel, writableRaster, false, null);
                    */
                    System.out.println("Stub for Gray images with Alpha channel");
                }
            } else {
                System.out.println("Stub for indexed images byte count: " + bytesPerPixel);
            }

            boolean sizeDiff = false;
            if (!this.getPreferredSize().equals(size)) {
                sizeDiff = true;
            }
            if ((!sizeDiff) && (!this.getMinimumSize().equals(size))) {
                sizeDiff = true;
            }
            if ((!sizeDiff) && (!this.getMaximumSize().equals(size))) {
                sizeDiff = true;
            }
            if (sizeDiff) {
                this.setPreferredSize(size);
                this.setMinimumSize(size);
                this.setMaximumSize(size);
                if (this.getParent() != null) {
                    this.getParent().validate();
                }
            }
            this.repaint();

        } catch (Exception e) {
            System.err.println("Caught error trying to refresh image in JGimpImagePanel: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * Sets the image displayed in this image panel to the one in
     * the active layer of the given image. The image panel automatically
     * resizes itself to match the proportions of the GIMP image.
     */
    public void copyImage(JGimpImage inImage) {
        if (inImage == null) {
            clearImage();
            return;
        }
        if (inImage.canRenderEntireImage()) {
            try {
                Dimension size = inImage.getSize();

                /* Stub: optimize JGimpImagePanel code when reusing an image panel (don't reallocate memory blocks)*/

                int[] thePixels = inImage.renderImageInJavaIntFormat(0, 0, size.width, size.height);
                DataBufferInt dataBuffer = new DataBufferInt(thePixels, thePixels.length);
                int[] bitMasks = { 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 };
                WritableRaster writableRaster = Raster.createPackedRaster(dataBuffer, size.width, size.height, size.width, bitMasks, new Point());
                ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);
                ColorModel colorModel = new DirectColorModel(colorSpace, 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000, false, dataBuffer.getDataType());
                m_BufferedImage = new BufferedImage(colorModel, writableRaster, false, null);

                boolean sizeDiff = false;
                if (!this.getPreferredSize().equals(size)) {
                    sizeDiff = true;
                }
                if ((!sizeDiff) && (!this.getMinimumSize().equals(size))) {
                    sizeDiff = true;
                }
                if ((!sizeDiff) && (!this.getMaximumSize().equals(size))) {
                    sizeDiff = true;
                }
                if (sizeDiff) {
                    this.setPreferredSize(size);
                    this.setMinimumSize(size);
                    this.setMaximumSize(size);
                    if (this.getParent() != null) {
                        this.getParent().validate();
                    }
                }
                this.repaint();
            } catch (Exception e) {
                System.err.println("Caught error trying to refresh image in JGimpImagePanel: " + e.getMessage());
                e.printStackTrace();
            }
        } else {
            try {
                System.out.println("Requesting repaint on image");
                JGimpDrawable activeDrawable = inImage.getActiveDrawable();
                copyDrawable(activeDrawable);
            } catch (Exception e) {
                System.err.println("Caught error trying to refresh image in JGimpImagePanel: " + e.getMessage());
                e.printStackTrace();
            }
        }
    }

    public void paint(Graphics g) {
        super.paint(g);
        if (m_BufferedImage != null) {
            g.drawImage(m_BufferedImage, 0, 0, null);
        }
    }
}
