/**
 * Copyright (C) 2004-2011 Jive Software. All rights reserved.
 *
 * Licensed 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.
 */
package org.jivesoftware.spark.component;

import org.jivesoftware.spark.util.log.Log;

import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragSource;
import java.awt.dnd.DragSourceDragEvent;
import java.awt.dnd.DragSourceDropEvent;
import java.awt.dnd.DragSourceEvent;
import java.awt.dnd.DragSourceListener;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.io.File;
import java.io.StringReader;
import java.util.Vector;

import javax.swing.JFrame;
import javax.swing.JLabel;

/**
 * Allows for dragging of a file from the label to the desktop.
 */
public class FileDragLabel extends JLabel implements DropTargetListener, DragSourceListener, DragGestureListener {
    private File file;

    public FileDragLabel() {
        DragSource dragSource = DragSource.getDefaultDragSource();
        dragSource.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY, this);
    }

    public void setFile(File file) {
        this.file = file;
    }

    @Override
	public void dragDropEnd(DragSourceDropEvent DragSourceDropEvent) {
    }

    @Override
	public void dragEnter(DragSourceDragEvent DragSourceDragEvent) {
    }

    @Override
	public void dragExit(DragSourceEvent DragSourceEvent) {
    }

    @Override
	public void dragOver(DragSourceDragEvent DragSourceDragEvent) {
    }

    @Override
	public void dropActionChanged(DragSourceDragEvent DragSourceDragEvent) {
    }

    @Override
	public void dragEnter(DropTargetDragEvent dropTargetDragEvent) {
        dropTargetDragEvent.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
    }

    @Override
	public void dragExit(DropTargetEvent dropTargetEvent) {
    }

    @Override
	public void dragOver(DropTargetDragEvent dropTargetDragEvent) {
    }

    @Override
	public void dropActionChanged(DropTargetDragEvent dropTargetDragEvent) {
    }

    @Override
	public synchronized void drop(DropTargetDropEvent dropTargetDropEvent) {
        try {
            final Transferable transferable = dropTargetDropEvent.getTransferable();
            if (transferable.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
                dropTargetDropEvent.acceptDrop(DnDConstants.ACTION_COPY);
                dropTargetDropEvent.getDropTargetContext().dropComplete(true);
            }
            else {
                dropTargetDropEvent.rejectDrop();
            }
        }
        catch (Exception ex) {
            Log.error(ex);
            dropTargetDropEvent.rejectDrop();
        }
    }

    @Override
	public void dragGestureRecognized(DragGestureEvent dragGestureEvent) {
        if (file == null) {
            // Nothing selected, nothing to drag
            getToolkit().beep();
        }
        else {
            FileSelection transferable = new FileSelection(file);
            dragGestureEvent.startDrag(DragSource.DefaultCopyDrop, transferable, this);
        }
    }

    private class FileSelection extends Vector<File> implements Transferable {
		private final static int FILE = 0;
		private final static int STRING = 1;
		private final static int PLAIN = 2;
        private final DataFlavor[] flavors = {
            DataFlavor.javaFileListFlavor,
            DataFlavor.stringFlavor,
            DataFlavor.getTextPlainUnicodeFlavor()};

        public FileSelection(File file) {
            addElement(file);
        }


        @Override
		public synchronized DataFlavor[] getTransferDataFlavors() {
            return flavors;
        }


        @Override
		public boolean isDataFlavorSupported(DataFlavor flavor) {
            boolean b = false;
            b = b | flavor.equals(flavors[FILE]);
            b |= flavor.equals(flavors[STRING]);
            b |= flavor.equals(flavors[PLAIN]);
            return (b);
        }


        @Override
		public synchronized Object getTransferData(DataFlavor flavor)
            throws UnsupportedFlavorException {
            if (flavor.equals(flavors[FILE])) {
                return this;
            }
            else if (flavor.equals(flavors[PLAIN])) {
                return new StringReader(file.getAbsolutePath());
            }
            else if (flavor.equals(flavors[STRING])) {
                return (file.getAbsolutePath());
            }
            else {
                throw new UnsupportedFlavorException(flavor);
            }
        }
    }

    public static void main(String[] args) {
        JFrame f = new JFrame();
        FileDragLabel p = new FileDragLabel();
        f.add(p);
        f.setVisible(true);
    }

}
