/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* $Id$ */

package org.apache.fop.render.awt.viewer;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.image.BufferedImage;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;

import javax.swing.JPanel;

import org.apache.fop.apps.FOPException;
import org.apache.fop.render.awt.AWTRenderer;

/**
 * Panel used to display a single page of a document.
 * This is basically a lazy-load display panel which
 * gets the size of the image for layout purposes but
 * doesn't get the actual image data until needed.
 * The image data is then accessed via a soft reference,
 * so it will be garbage collected when moving through
 * large documents.
 */
public class ImageProxyPanel extends JPanel {

    /** The reference to the BufferedImage storing the page data */
    private transient Reference imageRef;

    /** The maximum and preferred size of the panel */
    private Dimension size;

    /** The renderer. Shared with PreviewPanel and PreviewDialog. */
    private AWTRenderer renderer;

    /** The page to be rendered. */
    private int page;

    /**
     * Panel constructor. Doesn't allocate anything until needed.
     * @param renderer the AWTRenderer instance to use for painting
     * @param page initial page number to show
     */
    public ImageProxyPanel(AWTRenderer renderer, int page) {
        this.renderer = renderer;
        this.page = page;
        try {
            Dimension size = renderer.getPageImageSize(page);
            Insets insets = getInsets();
            size.width += insets.left + insets.right;
            size.height += insets.top + insets.bottom;
            this.size = size;
        } catch (Exception e) {
            this.size = new Dimension(10, 10);
        }
        // Allows single panel to appear behind page display.
        // Important for textured L&Fs.
        setOpaque(false);
    }

    /**
     * @return the size of the page plus the border.
     */
    public Dimension getMinimumSize() {
        return getPreferredSize();
    }

    /**
     * @return the size of the page plus the border.
     */
    public Dimension getPreferredSize() {
        return size;
    }

    /**
     * Sets the number of the page to be displayed and refreshes the display.
     * @param pg the page number
     */
    public synchronized void setPage(int pg) {
        if (page != pg) {
            page = pg;
            imageRef = null;
            repaint();
        }
    }

    /**
     * Gets the image data and paints it on screen. Will make
     * calls to getPageImage as required.
     * @param graphics a graphics context
     * @see javax.swing.JComponent#paintComponent(Graphics)
     * @see org.apache.fop.render.java2d.Java2DRenderer#getPageImage(int)
     */
    public synchronized void paintComponent(Graphics graphics) {
        try {
            if (isOpaque()) { //paint background
                graphics.setColor(getBackground());
                graphics.fillRect(0, 0, getWidth(), getHeight());
            }

            super.paintComponent(graphics);

            BufferedImage image = null;
            if (imageRef == null || imageRef.get() == null) {
                image = renderer.getPageImage(page);
                imageRef = new SoftReference(image);
            } else {
                image = (BufferedImage)imageRef.get();
            }

            if (image != null) {
                int x = (getWidth() - image.getWidth()) / 2;
                int y = (getHeight() - image.getHeight()) / 2;
                graphics.drawImage(image, x, y, image.getWidth(), image.getHeight(), null);
            }
        } catch (FOPException fopEx) {
            fopEx.printStackTrace();
        }
    }
}
