package org.objectstyle.wolips.componenteditor.inspector;

import org.eclipse.jface.util.LocalSelectionTransfer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSource;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DragSourceListener;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.DropTargetListener;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TableItem;
//import org.eclipse.ui.internal.dnd.IDropTarget2;
import org.objectstyle.wolips.bindings.wod.BindingValueKey;

// IDropTarget2 does not exists anymore?! (it only dragFinished(boolean)).
public class BindingsDragHandler implements DragSourceListener, /* IDropTarget2, */ PaintListener, DropTargetListener {
	private static final int endpointSize = 3;

	private WOBrowserColumn _browserColumn;

	private Point _startingPoint;

	private Point _currentPoint;

	private Canvas _lineCanvas;

	public BindingsDragHandler(WOBrowserColumn browserColumn) {
		_browserColumn = browserColumn;
		_browserColumn.getViewer().addDragSupport(DND.DROP_COPY, new Transfer[] { LocalSelectionTransfer.getTransfer() }, this);
	}

	public Shell getShell() {
		return _browserColumn.getShell();
	}

	public void createCanvas() {
		Shell shell = getShell();
		if (_lineCanvas == null) {
			_lineCanvas = new Canvas(shell, SWT.NO_BACKGROUND);
			_lineCanvas.setLocation(0, 0);
			_lineCanvas.setSize(shell.getSize());
			_lineCanvas.moveAbove(null);
			_lineCanvas.addPaintListener(this);
			_lineCanvas.setCapture(false);
			_lineCanvas.setEnabled(false);

			DropTarget dropTarget = new DropTarget(_lineCanvas, DND.DROP_NONE | DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK);
			LocalSelectionTransfer transfer = LocalSelectionTransfer.getTransfer();
			transfer.setSelection(new StructuredSelection("Test"));
			dropTarget.setTransfer(new Transfer[] { transfer });
			dropTarget.addDropListener(this);
		}
	}

	public void disposeCanvas() {
		if (_lineCanvas != null) {
			if (!_lineCanvas.isDisposed()) {
				_lineCanvas.removePaintListener(this);
				_lineCanvas.dispose();
			}
			_lineCanvas = null;
		}
	}

	public void paintControl(PaintEvent e) {
		if (_startingPoint != null && _currentPoint != null) {
			Point startingPoint = getShell().toControl(_startingPoint);
			Point currentPoint = getShell().toControl(_currentPoint);

			e.gc.setForeground(e.widget.getDisplay().getSystemColor(SWT.COLOR_BLACK));
			e.gc.setBackground(e.widget.getDisplay().getSystemColor(SWT.COLOR_BLACK));

			// e.gc.setAlpha(150);
			e.gc.setLineWidth(2);
			e.gc.setLineJoin(SWT.JOIN_ROUND);

			e.gc.drawOval(currentPoint.x - endpointSize, currentPoint.y - endpointSize, endpointSize * 2, endpointSize * 2);

			e.gc.drawLine(startingPoint.x, startingPoint.y, currentPoint.x, startingPoint.y);
			e.gc.drawLine(currentPoint.x, startingPoint.y, currentPoint.x, currentPoint.y);

			// e.gc.setAlpha(255);
			e.gc.fillRectangle(startingPoint.x - endpointSize, startingPoint.y - endpointSize, endpointSize * 2, endpointSize * 2);
		}
	}

	public void dispose() {
		disposeCanvas();
	}

	public void dragEnter(DropTargetEvent event) {
		event.detail = DND.DROP_COPY;
	}

	public void dragLeave(DropTargetEvent event) {
		// TODO Auto-generated method stub

	}

	public void dragOperationChanged(DropTargetEvent event) {
		event.detail = DND.DROP_COPY;
	}

	public void dragOver(DropTargetEvent event) {
		Point lastPoint = _currentPoint;
		_currentPoint = new Point(event.x, event.y);

		Point startingPoint = getShell().toControl(_startingPoint);
		Point currentPoint = getShell().toControl(_currentPoint);

		int redrawX1 = Math.min(startingPoint.x, currentPoint.x);
		int redrawY1 = Math.min(startingPoint.y, currentPoint.y);
		int redrawX2 = Math.max(startingPoint.x, currentPoint.x);
		int redrawY2 = Math.max(startingPoint.y, currentPoint.y);
		if (lastPoint != null) {
			lastPoint = getShell().toControl(lastPoint);
			redrawX1 = Math.min(redrawX1, lastPoint.x);
			redrawY1 = Math.min(redrawY1, lastPoint.y);
			redrawX2 = Math.max(redrawX2, lastPoint.x);
			redrawY2 = Math.max(redrawY2, lastPoint.y);
		}
		int slop = 5 + endpointSize;
		redrawX1 -= slop;
		redrawY1 -= slop;
		redrawX2 += slop;
		redrawY2 += slop;
		_lineCanvas.redraw(redrawX1, redrawY1, redrawX2 - redrawX1, redrawY2 - redrawY1, true);

		event.detail = DND.DROP_COPY;

		if (_browserColumn.getDelegate() != null) {
			_browserColumn.getDelegate().bindingDragging(_browserColumn, _currentPoint);
		}
	}

	public void drop(DropTargetEvent event) {
		_currentPoint = new Point(event.x, event.y);
	}

	public void dropAccept(DropTargetEvent event) {
		event.detail = DND.DROP_COPY;
	}

	public void dragFinished(boolean dropPerformed) {
		disposeCanvas();
	}

	public void drop() {
		// DO NOTHING
	}

	public Cursor getCursor() {
		return null;
	}

	public Rectangle getSnapRectangle() {
		return null;
	}

	public void bindingDropFinished() {
		disposeCanvas();
	}
	
	public void dragFinished(DragSourceEvent event) {
		if (_browserColumn.getDelegate() != null) {
			if (event.doit) {
				boolean dropFinished = _browserColumn.getDelegate().bindingDropped(_browserColumn, _currentPoint, this);
				if (dropFinished) {
					disposeCanvas();
				}
			} else {
				disposeCanvas();
				_browserColumn.getDelegate().bindingDragCanceled(_browserColumn);
			}
		} else {
			disposeCanvas();
		}
	}

	public void dragSetData(DragSourceEvent event) {
		event.data = _browserColumn.getSelection();
	}

	public void dragStart(DragSourceEvent event) {
		DragSource dragSource = (DragSource) event.getSource();
		Control control = dragSource.getControl();
		_startingPoint = null;
		_currentPoint = null;

		event.detail = DND.DROP_COPY;

		event.doit = false;

		ISelection selection = _browserColumn.getSelection();
		if (selection instanceof IStructuredSelection) {
			Object obj = ((IStructuredSelection) selection).getFirstElement();
			if (obj instanceof BindingValueKey) {
				Control listControl = _browserColumn.getViewer().getControl();
				Rectangle listBounds = listControl.getBounds();
				TableItem itemControl = (TableItem) _browserColumn.getViewer().testFindItem(obj);
				Rectangle itemBounds = itemControl.getBounds();
				int magicRightMarginOnMac = 27;
				_startingPoint = control.toDisplay(new Point(listBounds.x + listBounds.width - magicRightMarginOnMac, itemBounds.y + itemBounds.height / 2));
				event.doit = true;
			}
		}

		if (event.doit) {
			createCanvas();
		}
	}
}
