/*
 * JHDDropTargetListener.java
 *
 * Created on January 28, 2003, 4:23 PM
 */

package org.jhotdraw.contrib.dnd;

import org.jhotdraw.framework.*;
import org.jhotdraw.standard.DeleteFromDrawingVisitor;
import java.io.File;
import org.jhotdraw.util.Undoable;
import java.awt.Point;
import java.awt.datatransfer.DataFlavor;
import java.awt.dnd.*;


/**
 *
 * @author  Administrator
 */
public class JHDDropTargetListener implements java.awt.dnd.DropTargetListener {
	private int     fLastX=0, fLastY=0;      // previous mouse position
	private Undoable targetUndoable;
	private DrawingView dv;
	private DrawingEditor editor;
	/** Creates a new instance of JHDDropTargetListener */
	public JHDDropTargetListener(DrawingEditor drawingEditor, DrawingView drawingView) {
		dv = drawingView;
		editor = drawingEditor;
	}
	protected DrawingView view(){
		return dv;
	}
	protected DrawingEditor editor(){
		return editor;
	}
	
	
	
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
	
	/**
	 * Called when a drag operation has encountered the DropTarget.
	 */
	public void dragEnter(DropTargetDragEvent dtde) {
		log("DropTargetDragEvent-dragEnter");
		supportDropTargetDragEvent(dtde);
		if (fLastX == 0) {
			fLastX = dtde.getLocation().x;
		}
		if (fLastY == 0) {
			fLastY = dtde.getLocation().y;
		}
	}

	/**
	 * The drag operation has departed the DropTarget without dropping.
	 */
	public void dragExit(java.awt.dnd.DropTargetEvent dte) {
		log("DropTargetEvent-dragExit");
	}

	/**
	 * Called when a drag operation is ongoing on the DropTarget.
	 */
	 public void dragOver(DropTargetDragEvent dtde) {
		//log("DropTargetDragEvent-dragOver");
		if (supportDropTargetDragEvent(dtde)==true) {
			int x=dtde.getLocation().x;
			int y=dtde.getLocation().y;
			if ((Math.abs(x - fLastX) > 0) || (Math.abs(y - fLastY) > 0) ) {
				//FigureEnumeration fe = view().selectionElements();
				//while (fe.hasNextFigure()) {
				//	fe.nextFigure().moveBy(x - fLastX, y - fLastY);
				//	System.out.println("moving Figures " + view());
				//}
				//view().drawing().update();
				fLastX = x;
				fLastY = y;
			}
		}
	 }

	/**
	 * The drag operation has terminated with a drop on this DropTarget.
	 * Be nice to somehow incorporate FigureTransferCommand here.
	 */
	 public void drop(java.awt.dnd.DropTargetDropEvent dtde) {
		System.out.println("DropTargetDropEvent-drop");

		if (dtde.isDataFlavorSupported(DNDFiguresTransferable.DNDFiguresFlavor) == true) {
			log("DNDFiguresFlavor");
			if ((dtde.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE) != 0 ) {
				log("copy or move");
				if (dtde.isLocalTransfer() == false) {
					System.err.println("Intra-JVM Transfers not implemented for figures yet.");
					dtde.rejectDrop();
					return;
				}
				dtde.acceptDrop(dtde.getDropAction());
				try { /* protection from a malicious dropped object */
					setTargetUndoActivity( createTargetUndoActivity( view() ) );
					DNDFigures ff = (DNDFigures)DNDHelper.processReceivedData(DNDFiguresTransferable.DNDFiguresFlavor, dtde.getTransferable());
					getTargetUndoActivity().setAffectedFigures( ff.getFigures() );
					Point theO = ff.getOrigin();
					view().clearSelection();
					Point newP = dtde.getLocation();
					/** origin is where the figure thinks it is now
					  * newP is where the mouse is now.
					  * we move the figure to where the mouse is with this equation
					  */
					int dx = newP.x - theO.x;  /* distance the mouse has moved */
					int dy = newP.y - theO.y;  /* distance the mouse has moved */
					log("mouse at " + newP);
					FigureEnumeration fe = view().insertFigures( getTargetUndoActivity().getAffectedFigures() ,  dx, dy, false );
					getTargetUndoActivity().setAffectedFigures( fe );

					if (dtde.getDropAction() == DnDConstants.ACTION_MOVE) {
						view().addToSelectionAll( getTargetUndoActivity().getAffectedFigures() );
					}

					view().checkDamage();
					editor().getUndoManager().pushUndo( getTargetUndoActivity() );
					editor().getUndoManager().clearRedos();
					// update menus
					editor().figureSelectionChanged( view() );
					dtde.dropComplete(true);
				}
				catch (NullPointerException npe) {
					npe.printStackTrace();
					dtde.dropComplete(false);
				}
			}
			else {
				dtde.rejectDrop();
			}
		}
		else if (dtde.isDataFlavorSupported(DataFlavor.stringFlavor)) {
			log("String flavor dropped.");
			dtde.acceptDrop(dtde.getDropAction());
			Object o = DNDHelper.processReceivedData(DataFlavor.stringFlavor, dtde.getTransferable());
			if (o != null) {
				log("Received string flavored data.");
				dtde.getDropTargetContext().dropComplete(true);
			}
			else {
				dtde.getDropTargetContext().dropComplete(false);
			}
		}
		else if (dtde.isDataFlavorSupported(DNDHelper.ASCIIFlavor) == true) {
			log("ASCII Flavor dropped.");
			dtde.acceptDrop(DnDConstants.ACTION_COPY);
			Object o = DNDHelper.processReceivedData(DNDHelper.ASCIIFlavor, dtde.getTransferable());
			if (o!= null) {
				log("Received ASCII Flavored data.");
				dtde.getDropTargetContext().dropComplete(true);
				//System.out.println(o);
			}
			else {
				dtde.getDropTargetContext().dropComplete(false);
			}
		}
		else if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
			log("Java File List Flavor dropped.");
			dtde.acceptDrop(DnDConstants.ACTION_COPY);
			File [] fList = (File[]) DNDHelper.processReceivedData(DataFlavor.javaFileListFlavor, dtde.getTransferable());
			if (fList != null) {
				log("Got list of files.");
				for (int x=0; x< fList.length; x++ ) {
					System.out.println(fList[x].getAbsolutePath());
				}
				dtde.getDropTargetContext().dropComplete(true);
			}
			else {
				dtde.getDropTargetContext().dropComplete(false);
			}
		}
		fLastX = 0;
		fLastY = 0;
	}

	/**
	 * Called if the user has modified the current drop gesture.
	 */
	public void dropActionChanged(DropTargetDragEvent dtde) {
		log("DropTargetDragEvent-dropActionChanged");
		supportDropTargetDragEvent(dtde);
	}

	
	
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
	
	/**
	 * Tests wether the Drag event is of a type that we support handling
	 * Check the DND interface and support the events it says it supports
	 * if not a dnd interface comp, then dont support! because we dont even
	 * really know what kind of view it is.
	 */
	protected boolean supportDropTargetDragEvent(DropTargetDragEvent dtde) {
		if (dtde.isDataFlavorSupported(DNDFiguresTransferable.DNDFiguresFlavor) == true) {
			if ((dtde.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE) != 0) {
				dtde.acceptDrag(dtde.getDropAction());
				return true;
			}
			else {
				dtde.rejectDrag();
				return false;
			}
		}
		else if (dtde.isDataFlavorSupported(DNDHelper.ASCIIFlavor) == true) {
			dtde.acceptDrag(dtde.getDropAction());//accept everything because i am too lazy to fix yet
			return true;
		}
		else if (dtde.isDataFlavorSupported(DataFlavor.stringFlavor) == true) {
			dtde.acceptDrag(dtde.getDropAction());//accept everything because i am too lazy to fix yet
			return true;
		}
		else if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor) == true) {
			dtde.acceptDrag(dtde.getDropAction());//accept everything because i am too lazy to fix yet
			return true;
		}
		else {
			dtde.rejectDrag();
			return false;
		}
	}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
	
	/**
	 * Factory method for undo activity
	 */
	protected Undoable createTargetUndoActivity(DrawingView view) {
		return new AddUndoActivity( view );
	}
	protected void setTargetUndoActivity(Undoable undoable){
		targetUndoable = undoable;
	}
	protected Undoable getTargetUndoActivity(){
		return targetUndoable;
	}
	public static class AddUndoActivity extends org.jhotdraw.util.UndoableAdapter {
		private boolean undone=false;
		public AddUndoActivity(DrawingView newDrawingView) {
			super(newDrawingView);
			log("AddUndoActivity created " + newDrawingView);			
			setUndoable(true);
			setRedoable(true);
		}

		public boolean undo() {
			if (!super.undo()) {
				return false;
			}
			//undo of add really shouldnt need visitor !?!dnoyeb!?!
			log("AddUndoActivity AddUndoActivity undo");
			DeleteFromDrawingVisitor deleteVisitor = new DeleteFromDrawingVisitor(getDrawingView().drawing());
			FigureEnumeration fe = getAffectedFigures();
			while (fe.hasNextFigure()) {
	    		org.jhotdraw.framework.Figure f = fe.nextFigure();
				f.visit(deleteVisitor);
			}
			setAffectedFigures( deleteVisitor.getDeletedFigures() );
			getDrawingView().clearSelection();
			undone = true;
			return true;
		}

		public boolean redo() {
			// do not call execute directly as the selection might has changed
			if (!isRedoable()) {
				return false;
			}
			log("AddUndoActivity redo");
			getDrawingView().clearSelection();
			setAffectedFigures(getDrawingView().insertFigures(
				getAffectedFigures(), 0, 0, false));
			undone = false;
			return true;
		}
		/**
		 *	Since this is an add operation, figures can only be released if it
		 *  has been undone.
		 */
		public void release() {
			if(undone == true){
				FigureEnumeration fe = getAffectedFigures();
				while (fe.hasNextFigure()) {
					Figure f = fe.nextFigure();
					getDrawingView().drawing().remove(f);
					f.release();
				}
			}
			setAffectedFigures(org.jhotdraw.standard.FigureEnumerator.getEmptyEnumeration());
		}
	}
	private static void log(String message){
		//System.out.println("JHDDropTargetListener: " + message);
	}
}
