/*
 * @(#)BinaryView.java  1.2  2004-12-26
 *
 * Copyright (c) 1999-2004 Werner Randelshofer, Immensee, Switzerland.
 * All rights reserved.
 *
 * You may not use, copy or modify this file, except in compliance with the
 * license agreement you entered into with Werner Randelshofer.
 * For details see accompanying license terms.
 */
package ch.randelshofer.view;

import org.monte.media.binary.BinaryPanel;
import org.monte.media.binary.BinaryModel;

import ch.randelshofer.gui.*;
import org.monte.media.binary.ByteArrayBinaryModel;
import org.monte.media.binary.FileBasedBinaryModel;

import java.awt.*;
import java.awt.dnd.*;


import java.text.NumberFormat;


import java.io.IOException;
import java.io.InputStream;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.activation.URLDataSource;

import javax.swing.JScrollPane;
import javax.swing.JLabel;
import javax.swing.JMenu;

/**
 * Hex viewer for all types of files.
 *
 * @author  Werner Randelshofer, Hausmatt 10, CH-6405 Immensee, Switzerland
 * @version 1.2 2004-12-26 Close input stream immediately after creating the
 * binary model.
 * <br>1.1 2002-02-10 Support for DnD added.
 * <br> 1.0.1   2000-10-09 Use SwingWorker instead of a subclass of Thread to
 *                             load the input stream asynchronously.
 * <br> 1.0  1999-10-19
 */
public class BinaryView extends AbstractView {

    private BinaryPanel binaryPanel;
    private JScrollPane scrollPane;

    public BinaryView() {
        setLayout(new BorderLayout());
        binaryPanel = new BinaryPanel();
        scrollPane = new JScrollPane(binaryPanel, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
        scrollPane.setBorder(null);
        scrollPane.setViewportView(binaryPanel);
        scrollPane.getVerticalScrollBar().setUnitIncrement(12);
        scrollPane.getHorizontalScrollBar().setUnitIncrement(6);
        add(scrollPane);
        setPreferredSize(new Dimension(400, 400));
    }

    /** Sets the command context for the bean. The receiver loads
     * the image data provided by the data handler and displays it.
     */
    @Override
    public void setCommandContext(String verb, final DataHandler dh)
            throws IOException {
        setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
        SwingWorker worker = new SwingWorker() {

            @Override
            public Object construct() {
                Object result = null;
                try {
                    DataSource source = dh.getDataSource();
                    if (source instanceof FileDataSource) {
                        FileDataSource fds=(FileDataSource)source;
                            result = new FileBasedBinaryModel(fds.getFile());
                    } else {

                        InputStream in = dh.getInputStream();
                        try {

                            result = new ByteArrayBinaryModel(in);
                        } catch (Throwable t) {
                            result = t;
                        } finally {
                            in.close();
                        }
                    }
                } catch (IOException e) {
                    result = e;
                }

                return result;
            }

            public void finished() {
                Object result = get();
                if (result instanceof BinaryModel) {
                    binaryPanel.setModel((BinaryModel) result);
                } else {
                    add(new JLabel(result.toString()), BorderLayout.NORTH);
                }
                setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
            }
        };

        worker.start();
    }

    /**
     * Adds menu items to the "View" menu.
     *
     * When the viewer is added to a container with a
     * JMenuBar. Then the container asks the viewer to
     * add his menu items to the "View" menu of the container.
     */
    public void mergeViewMenuItems(JMenu m) {
    }

    /**
     * Adds menu items to the "Settings" menu.
     *
     * When the viewer is added to a container with a
     * JMenuBar. Then the container asks the viewer to
     * add his menu items to the "Settings" menu of the container.
     */
    public void mergeSettingsMenuItems(JMenu m) {
    }

    protected void updateViewProperties() {
        getViewProperties().put("title", " as Binary");
    }

    protected void updateApplicationProperties() {
    }

    /**
     * Frees all resources allocated by this viewer.
     */
    @Override
    public void dispose() {
        if (binaryPanel!=null) {
            binaryPanel.getModel().close();
            binaryPanel=null;
        }
    }

    /**
     * Returns true if this viewer has a scrollpane of its own.
     * The container that contains this viewers uses this method to
     * determine if it should wrap a scrollpane around the viewer
     * or not.
     *
     * @return  true if this viewer has a scrollpane of its own.
     */
    public boolean hasScrollPane() {
        return true;
    }

    /**
     * This method adds the given drop target listener to
     * all components of the viewer.
     */
    public void addDropTargetListener(DropTargetListener listener) {
        new DropTarget(this, listener);
        new DropTarget(scrollPane, listener);
        new DropTarget(binaryPanel, listener);
    }

    public String toString() {
        return "Binary View\n\nSize: " + NumberFormat.getInstance().format(binaryPanel.getModel().getLength()) + " bytes";
    }
}
