/*******************************************************************************
 * Copyright (c) 2002, 2008 QNX Software Systems and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 * QNX Software Systems - Initial API and implementation
 *******************************************************************************/

package org.eclipse.cdt.internal.ui.dnd;

import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourceAttributes;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.FileTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.actions.CopyFilesAndFoldersOperation;

/**
 * FileTransferDropAdapter
 */
public class FileTransferDropAdapter extends CDTViewerDropAdapter implements TransferDropTargetListener {

	public FileTransferDropAdapter(AbstractTreeViewer viewer) {
		super(viewer, DND.FEEDBACK_SCROLL | DND.FEEDBACK_EXPAND);
	}

	//---- TransferDropTargetListener interface ---------------------------------------
	
	@Override
	public Transfer getTransfer() {
		return FileTransfer.getInstance();
	}
	
	@Override
	public boolean isEnabled(DropTargetEvent event) {
		Object target= event.item != null ? event.item.getData() : null;
		if (target == null) {
			return false;
		}
		return target instanceof ICElement || target instanceof IResource;
	}

	//---- Actual DND -----------------------------------------------------------------
	
	@Override
	public void validateDrop(Object target, DropTargetEvent event, int operation) {
		event.detail= DND.DROP_NONE;
		boolean isContainer = false;
		if (target instanceof IContainer) {
			isContainer = true;
		} else if (target instanceof IAdaptable) {
			target = ((IAdaptable)target).getAdapter(IResource.class);
			isContainer = target instanceof IContainer;
		}
		if (isContainer) {
			IContainer container= (IContainer)target;
			if (container.isAccessible()) {
				ResourceAttributes attributes = container.getResourceAttributes();
				if (attributes != null && !attributes.isReadOnly()) {
					event.detail= DND.DROP_COPY;
				}
			}
		}
	}

	@Override
	public void drop(Object dropTarget, final DropTargetEvent event) {
		int operation= event.detail;
		
		event.detail= DND.DROP_NONE;
		final Object data= event.data;
		if (data == null || !(data instanceof String[]) || operation != DND.DROP_COPY)
			return;
		
		final IContainer target= getActualTarget(dropTarget);
		if (target == null)
			return;
		
		// Run the import operation asynchronously. 
		// Otherwise the drag source (e.g., Windows Explorer) will be blocked 
		// while the operation executes. Fixes bug 35796.
		Display.getCurrent().asyncExec(new Runnable() {
			@Override
			public void run() {
				getShell().forceActive();
				new CopyFilesAndFoldersOperation(getShell()).copyFiles((String[]) data, target);
				// Import always performs a copy.
				event.detail= DND.DROP_COPY;
			}
		});
	}
	
	private IContainer getActualTarget(Object dropTarget) {
		if (dropTarget instanceof IContainer) {
			return (IContainer)dropTarget;
		} else if (dropTarget instanceof ICElement) {
			return getActualTarget(((ICElement)dropTarget).getResource());
		}
		return null;
	}
	
	Shell getShell() {
		return getViewer().getControl().getShell();
	}

}
