/*******************************************************************************
 * Copyright (c) 2010 Oak Ridge National Laboratory.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 ******************************************************************************/
package org.csstudio.ui.util.widgets;

import java.io.FileInputStream;
import java.io.InputStream;

import org.csstudio.ui.util.dialogs.ExceptionDetailsErrorDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;

/** Widget that displays an image.
 *
 *  <p>Similar to a Label with image, but image is resized to fit the widget.
 *
 *  <p>Image can be provided as {@link InputStream}.
 *
 *  <p>As a shortcut, the widget can also read a file.
 *
 *  <p>Setting the {@link Image} directly is not supported
 *  to avoid issues with ownership and disposal of such an image.
 *
 *  @author Kay Kasemir
 */
public class ImagePreview extends Canvas implements DisposeListener,
        PaintListener
{
    /** Image or <code>null</code> */
    private Image image = null;

    /** Additional short message or <code>null</code> */
    private String message = null;

    /** Initialize empty
     *  @param parent Parent widget
     */
    public ImagePreview(final Composite parent)
    {
        super(parent, 0);
        addDisposeListener(this);
        addPaintListener(this);
    }

    /** Set image to display
     *  @param image_filename Full path to image file or <code>null</code> for no image
     */
    public void setImage(final String image_filename)
    {
        if (image_filename == null)
            setImage((InputStream) null);
        else
        {
            try
            {
                setImage(new FileInputStream(image_filename));
            }
            catch (Exception ex)
            {
                ExceptionDetailsErrorDialog.openError(getShell(), "Error", ex);
            }
        }
    }

    /** Set image to display
     *  @param image_stream Image stream
     */
    public void setImage(final InputStream image_stream)
    {
        // Remove previous image, if there was one
        if (image != null)
        {
            image.dispose();
            image = null;
            setToolTipText("");
        }
        if (image_stream == null)
            return;
        image = new Image(getDisplay(), image_stream);
        redraw();
    }

    /** Set a message that is displayed on top of the image
     *  @param message Message to display or <code>null</code>
     */
    public void setMessage(final String message)
    {
        this.message = message;
        redraw();
    }

    // Note that this is supported by Canvas
    // public void setToolTipText(final String tooltip);

    /** @see Control */
    @Override
    public Point computeSize(final int wHint, final int hHint)
    {
        if (image == null)
            return new Point(1, 1);
        return new Point(200, 200);
    }

    /** @see PaintListener */
    @Override
    public void paintControl(final PaintEvent e)
    {
        final Rectangle bounds = getBounds();
        final GC gc = e.gc;
        if (image != null)
        {   // Draw image to fit widget bounds, maintaining
            // aspect ratio
            final Rectangle img = image.getBounds();
            // Start with original size
            int width = img.width;
            int height = img.height;
            int destX = 0;
            int destY = 0;
            if (width > bounds.width)
            {   // Too wide?
                width = bounds.width;
                height = width * img.height / img.width;
            }
            if (height > bounds.height)
            {   // Too high?
                height = bounds.height;
                width = height * img.width / img.height;
            }
            destX = (bounds.width - width) / 2;
            destY = (bounds.height - height) / 2;
            gc.drawImage(image, 0, 0, img.width, img.height, destX, destY,
                    width, height);
        }
        if (message != null)
        {   // Show message
            final Point extend = gc.textExtent(message, SWT.DRAW_DELIMITER);
            final int x = (bounds.width - extend.x) / 2;
            final int y = (bounds.height - extend.y) / 2;
            gc.drawText(message, x, y, SWT.DRAW_DELIMITER
                    | SWT.DRAW_TRANSPARENT);
            return;
        }
    }

    /** @see DisposeListener */
    @Override
    public void widgetDisposed(final DisposeEvent e)
    {
        if (image != null)
            image.dispose();
    }
}
