package com.extjs.gxt.ui.client.dnd;

import java.util.Iterator;

import com.extjs.gxt.ui.client.Events;
import com.extjs.gxt.ui.client.event.DNDEvent;
import com.extjs.gxt.ui.client.widget.Component;
import com.extjs.gxt.ui.client.widget.grid.Grid;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;

public class MyDNDManager extends DNDManager {

	public static DNDManager get() {
		if (manager == null) {
			manager = new MyDNDManager();
		}
		return manager;
	}

	@Override
	void registerDropTarget(DropTarget target) {
		Element newEl = target.getComponent().getElement();
		Iterator<DropTarget> it = targets.iterator();
		int i = 0;
		while (it.hasNext()) {
			Component rcomp = it.next().component;
			if (DOM.isOrHasChild(rcomp.getElement(), newEl)) {
				targets.add(i, target);
				return;
			}
			i++;
		}
		targets.add(target);
	}

	private int colIndex = -1;

	@Override
	void handleDragMove(DragSource source, DNDEvent event) {
		DropTarget target = getTarget(event.getTarget());

		// no target with current
		if (target == null) {
			if (currentTarget != null) {
				currentTarget.handleDragLeave(event);
				currentTarget.fireEvent(Events.DragLeave, event);
				currentTarget = null;
			}
			return;
		}

		// match move
		// if (target == currentTarget) {
		if (isSameTarget(currentTarget, target, event)) {
			event.doit = false;
			event.target = currentTarget;
			currentTarget.onDragMove(event);
			currentTarget.fireEvent(Events.DragMove, event);
			if (event.doit == true) {
				currentTarget.showFeedback(event);
			} else {
				Insert.get().hide();
			}
			return;
		}

		if (target != currentTarget) {
			if (!source.getGroup().equals(target.getGroup())) {
				return;
			}

			if (currentTarget != null) {
				currentTarget.handleDragLeave(event);
				currentTarget = null;
			}
			if (!target.isEnabled() || !target.component.isEnabled()) {
				return;
			}
			currentTarget = target;
		}

		if (!currentTarget.isAllowSelfAsSource()
				&& source.getComponent() == currentTarget.getComponent()) {
			currentTarget = null;
			return;
		}

		// entering
		event.doit = false;
		event.target = currentTarget;
		currentTarget.handleDragEnter(event);
		currentTarget.fireEvent(Events.DragEnter, event);
	}

	private boolean isSameTarget(DropTarget tg1, DropTarget tg2, DNDEvent de) {
		if (tg1 != null && tg2 != null && tg1.component instanceof Grid
				&& tg2.component instanceof Grid) {
			int i = getIndex(de);
			boolean b = colIndex == i;
			if (!b) {
				colIndex = i;
			}
			return b;
		}
		return tg1 == tg2;
	}

	private int getIndex(DNDEvent event) {
		if (event.component instanceof Grid) {
			Grid grid = (Grid) event.component;
			return grid.getView().findCellIndex(event.getTarget(), null);
		}
		return -1;
	}

}
