/**
 *#########################################################################
 *
 * A component of the Gatherer application, part of the Greenstone digital
 * library suite from the New Zealand Digital Library Project at the
 * University of Waikato, New Zealand.
 *
 * <BR><BR>
 *
 * Author: John Thompson, Greenstone Digital Library, University of Waikato
 *
 * <BR><BR>
 *
 * Copyright (C) 1999 New Zealand Digital Library Project
 *
 * <BR><BR>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * <BR><BR>
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * <BR><BR>
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *########################################################################
 */
package org.greenstone.gatherer.file;

import java.awt.*;
import java.awt.dnd.*;
import java.awt.event.*;
import java.awt.geom.AffineTransform;
import java.io.*;
import java.util.*;
import javax.swing.*;
import javax.swing.tree.*;
import org.greenstone.gatherer.Configuration;
import org.greenstone.gatherer.Gatherer;
import org.greenstone.gatherer.gui.GLIButton;
import org.greenstone.gatherer.util.DragComponent;
import org.greenstone.gatherer.util.DragGroup;
import org.greenstone.gatherer.util.JarTools;


public class RecycleBin
    extends GLIButton
    implements DragComponent, DropTargetListener {

    private boolean ignore = false;
    /** The group encompasses all of the objects you plan to drag and drop within, and ensures that only one has focus (as clearly identified by the colour of the selection field or, in this particular case, the background) and that actions only occur between components in the same group. */
    private DragGroup group;
    /** In order to make this button a drop target we have to create a DropTarget instance with the button as its target. */
    private DropTarget drop_target;
    private FileSystemModel model;
    /** What sort of action should a drag resemble. Not really used as we override with custom drag icon. */
    private int drag_action = DnDConstants.ACTION_MOVE;
    /** The last point the mouse was at. Used to repaint 'spoilt' area. */
    private Point pt_last = null;
    /** The area covered by the drag ghost, our custom drag icon. */
    private Rectangle ra_ghost = new Rectangle();


    public RecycleBin()
    {
	super(JarTools.getImage("bin.gif"));
	this.drop_target = new DropTarget(this, drag_action, this, true);

	setBackground(Configuration.getColor("coloring.button_background", true));
	setForeground(Configuration.getColor("coloring.button_foreground", true));
	setOpaque(true);

	this.model = new FileSystemModel(new RecycleBinNode(new File(Gatherer.getGLIUserDirectoryPath() + "recycle")));
    }


    /** In order for the appearance to be consistant, given we may be in the situation where the pointer has left our focus but the ghost remains, this method allows other members of the GGroup to tell this component to repair the 'spoilt' region left by its ghost. */
    public void clearGhost(){
    }


    /** Any implementation of DropTargetListener must include this method so we can be notified when the drag focus enters this component. We want to provide some sort of indication whether the current component is an acceptable drop target as well as indicating focus. */
    public void dragEnter(DropTargetDragEvent event) {
	group.grabFocus(this);
	setBackground(Configuration.getColor("coloring.button_selected_background", true));
	setForeground(Configuration.getColor("coloring.button_selected_foreground", true));
    }

    /** Any implementation of DropTargetListener must include this method so we can be notified when the drag focus leaves this component. We need to indicate that we have lost focus. */
    public void dragExit(DropTargetEvent event) {
	setBackground(Configuration.getColor("coloring.button_background", true));
	setForeground(Configuration.getColor("coloring.button_foreground", true));
    }

    /** Any implementation of DropTargetListener must include this method so we can be notified when the drag moves in this component. This is where we repaint our ghost icon at the tip of the mouse pointer. */
    public void dragOver(DropTargetDragEvent event) {
	Graphics2D g2 = (Graphics2D) getGraphics();
	Point pt = event.getLocation();
	if(pt_last != null && pt.equals(pt_last)) {
	    return;
	}
	pt_last = pt;
	if(!DragSource.isDragImageSupported()) {
	    // Erase the last ghost image and or cue line
	    paintImmediately(ra_ghost.getBounds());
	    // Remember where you are about to draw the new ghost image
	    ra_ghost.setRect(pt.x - group.mouse_offset.x, pt.y - group.mouse_offset.y, group.image_ghost.getWidth(), group.image_ghost.getHeight());
	    // Draw the ghost image
	    g2.drawImage(group.image_ghost, AffineTransform.getTranslateInstance(ra_ghost.getX(), ra_ghost.getY()), null);
	}
    }

    /** Any implementation of DropTargetListener must include this method so we can be notified when the drag ends, ie the transferable is dropped. This in turn triggers a series of add events preceded by a pre() and followed by a post(). */
    public void drop(DropTargetDropEvent event) {
	ignore = true;
	group.grabFocus(this);
	setBackground(Configuration.getColor("coloring.button_background", true));
	setForeground(Configuration.getColor("coloring.button_foreground", true));

	try {
	    DragComponent source = group.getSource();
	    TreePath[] selection = group.getSelection();
	    FileNode[] source_nodes = new FileNode[selection.length];
	    for(int i = 0; i < source_nodes.length; i++) {
		source_nodes[i] = (FileNode) selection[i].getLastPathComponent();
	    }
	    event.acceptDrop(drag_action);
	    // Action delete
	    Gatherer.f_man.action(source, source_nodes, this, null);
	    group.setSource(null);
	    group.setSelection(null);
	}
	catch(Exception error) {
	    error.printStackTrace();
	    event.rejectDrop();
	}
	ignore = false;
	// Clear up the group.image_ghost
	paintImmediately(ra_ghost.getBounds());
	event.getDropTargetContext().dropComplete(true);
    }

    /** Any implementation of DropTargetListener must include this method so we can be notified when the action to be taken upon drop changes. We never change so we don't do anything here. */
    public void dropActionChanged(DropTargetDragEvent event) {
    }

    /** Used to notify this component that it has gained focus by some method other that mouse focus. */
    public void gainFocus() {
    }

    /** Any implementation of DragComponent must include this method so that a outsider can get at the underlying tree model behind the component. */
    public FileSystemModel getTreeModel(){
  	return (FileSystemModel) model;
    }

    public boolean ignore() {
	return ignore;
    }

    /** This method is used to inform this component when it loses focus by means other than a drag mouse event, and should indicate this somehow. */
    public void loseFocus() {
    }

    public void setGroup(DragGroup group) {
	this.group = group;
    }


    public class RecycleBinNode
	extends FileNode
    {
	public RecycleBinNode(File file)
	{
	    super(file);
	}

	public FileNode addChildNode(File file) { return null; }
    }
}
