package ij.plugin; 
import java.awt.*;
import java.awt.event.*;
import java.awt.datatransfer.*;
import java.awt.image.*;
import java.io.*;
import ij.*;
import ij.process.*;
import ij.gui.*;
import ij.plugin.frame.Editor;
import ij.plugin.frame.Recorder;
import ij.text.TextWindow;
import ij.util.Tools;
    
/** Copies/pastes images to/from the system clipboard. */
public class Clipboard implements PlugIn, Transferable {
    static java.awt.datatransfer.Clipboard clipboard;
    private ImagePlus gImp;
    
    public void run(String arg) {
        if (IJ.altKeyDown()) {
            if (arg.equals("copy"))
                arg = "scopy";
            else if (arg.equals("paste"))
                arg = "spaste";
        }
        if (arg.equals("copy"))
            copy(false);
        else if (arg.equals("paste"))
            paste();
        else if (arg.equals("cut"))
            copy(true);
        else if (arg.equals("scopy"))
            copyToSystem();
        else if (arg.equals("showsys"))
            showSystemClipboard();
        else if (arg.equals("show"))
            showInternalClipboard();
    }
    
    /** Copies the contents of the specified image, or selection, to the system clicpboard. */
    public static void copyToSystem(ImagePlus imp) {
        Clipboard cplugin = new Clipboard();
        cplugin.gImp = imp;
        cplugin.setup();
        try {
            cplugin.clipboard.setContents(cplugin, null);
        } catch (Throwable t) {}
    }
    
    void copy(boolean cut) {
        ImagePlus imp = WindowManager.getCurrentImage();
        if (imp!=null) {
            imp.copy(cut);
            if (cut)
                imp.changes = true;
        } else
            IJ.noImage();
        if (Recorder.scriptMode()) {
            if (cut)
                Recorder.recordCall("imp.cut();");
            else
                Recorder.recordCall("imp.copy();");
        }
    }
    
    private ImagePlus flatten(ImagePlus imp) {
        if (imp.getOverlay()!=null && !imp.getHideOverlay() && !imp.isHyperStack()) {
            ImagePlus imp2 = imp;
            Roi roi = imp.getRoi();
            if (imp.getStackSize()>1) {
                imp.deleteRoi();
                int slice = imp.getCurrentSlice();
                imp = new Duplicator().run(imp, slice, slice);
            }
            imp = imp.flatten();
            imp.setRoi(roi);
            imp2.setRoi(roi);
        }
        return imp;
    }
    
    void paste() {
        if (ImagePlus.getClipboard()==null)
            showSystemClipboard();
        else {
            ImagePlus imp = WindowManager.getCurrentImage();
            if (imp!=null) {
                imp.paste();
                if (Recorder.scriptMode())
                    Recorder.recordCall("imp.paste();");
            } else
                showInternalClipboard   ();
        }
    }

    void setup() {
        if (clipboard==null)
            clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
    }
    
    void copyToSystem() {
        this.gImp = WindowManager.getCurrentImage();
        setup();
        try {
            clipboard.setContents(this, null);
        } catch (Throwable t) {}
        if (Recorder.scriptMode())
            Recorder.recordCall("imp.copyToSystem();");
    }
    
    void showSystemClipboard() {
        setup();
        IJ.showStatus("Opening system clipboard...");
        try {
            Transferable transferable = clipboard.getContents(null);
            boolean imageSupported = transferable.isDataFlavorSupported(DataFlavor.imageFlavor);
            boolean textSupported = transferable.isDataFlavorSupported(DataFlavor.stringFlavor);
            if (imageSupported) {
                Image img = (Image)transferable.getTransferData(DataFlavor.imageFlavor);
                if (img==null) {
                    IJ.error("Unable to convert image on system clipboard");
                    IJ.showStatus("");
                    return;
                }
                int width = img.getWidth(null);
                int height = img.getHeight(null);
                BufferedImage   bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
                Graphics g = bi.createGraphics();
                g.drawImage(img, 0, 0, null);
                g.dispose();
                WindowManager.checkForDuplicateName = true;
                new ImagePlus("Clipboard", bi).show();
            } else if (textSupported) {
                String text = (String)transferable.getTransferData(DataFlavor.stringFlavor);
                if (IJ.isMacintosh())
                    text = Tools.fixNewLines(text);
                Editor ed = new Editor();
                ed.setSize(600, 300);
                ed.create("Clipboard", text);
                IJ.showStatus("");
            } else
                IJ.error("Unable to find an image on the system clipboard");
        } catch (Throwable e) {
            IJ.handleException(e);
        }
    }
    
    public DataFlavor[] getTransferDataFlavors() {
        return new DataFlavor[] { DataFlavor.imageFlavor };
    }

    public boolean isDataFlavorSupported(DataFlavor flavor) {
        return DataFlavor.imageFlavor.equals(flavor);
    }

    public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException {
        if (!isDataFlavorSupported(flavor))
            throw new UnsupportedFlavorException(flavor);
        ImagePlus imp = gImp!=null?gImp:WindowManager.getCurrentImage();
        if (imp==null)
            return null;
        Roi roi = imp.getRoi();
        if (roi!=null && !roi.isLine()) {
            Rectangle bounds = roi.getBounds();
            if (!(bounds.x==0&&bounds.y==0&&bounds.width==imp.getWidth()&&bounds.height==imp.getHeight()))
                imp = imp.crop();
        }
        boolean overlay = imp.getOverlay()!=null && !imp.getHideOverlay();
        if (overlay && !imp.tempOverlay())
            imp = imp.flatten(); 
        return imp.getImage();
    }
    
    void showInternalClipboard() {
        ImagePlus clipboard = ImagePlus.getClipboard();
        if (clipboard!=null) {
            ImageProcessor ip = clipboard.getProcessor();
            ImagePlus imp2 = new ImagePlus("Clipboard", ip.duplicate());
            Roi roi = clipboard.getRoi();
            imp2.deleteRoi();
            if (roi!=null && roi.isArea() && roi.getType()!=Roi.RECTANGLE) {
                roi = (Roi)roi.clone();
                roi.setLocation(0, 0);
                imp2.setRoi(roi);
                IJ.run(imp2, "Clear Outside", null);
                imp2.deleteRoi();
            }
            WindowManager.checkForDuplicateName = true;          
            imp2.show();
        } else
            IJ.error("The internal clipboard is empty.");
    }

}