/**
 *#########################################################################
 *
 * 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.util;

import java.awt.Point;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.util.Vector;
import javax.swing.JComponent;
import javax.swing.tree.TreePath;
import org.greenstone.gatherer.gui.tree.DragTree;


/** This class acts as a linker between all the various drag and drop enabled DragComponent. It provides methods for ensuring only one component is the drop target, showing extra user feedback, and maintains a single point of focus. Moreover it provides a storage space for necessary shared variables such as mouse_offset of initial drag etc. */
public class DragGroup 
    implements FocusListener {
    /** The image used for the ghost icon when dragging. */
    public BufferedImage image_ghost = null;
    /** The initial offset of the mouse from the selection within a DragComponent. Then as you drag the mouse, the ghost appears in a visually consistant place, and remains at the same offset throughout the dragging process. */
    public Point mouse_offset = null;
    /** The component currently in charge of drawing the ghost icon. Note that this isn't necessarily the only component that needs to repaint 'spoilt' screen real-estate as a side effect of the ghost. */
    private DragComponent ghost_owner = null;
    /** The component where the drag began, so that extra information necessary for the drag can be garnered by the drop target, or so that focus can return to the source component if the drop is rejected. */
    private DragTree drag_source = null;
    /** The selected nodes, as determined when the drag begun. */
    private TreePath[] selection = null;
    /** A list of DragComponents registered as being part of this group. */
    private Vector registered = new Vector();

    /** Register a DragComponent as begin part of this group.
     * @param component The DragComponent to add.
     */
    public void add(DragComponent component) {
	if(!registered.contains(component)) {
	    registered.add(component);
	    component.addFocusListener(this);
	    component.setGroup(this);
	}
    }

    /** Invoked when a component gains the keyboard focus. */
    public void focusGained(FocusEvent event) {
	((DragComponent)event.getComponent()).gainFocus();
    }
          
    /** Invoked when a component loses the keyboard focus. */
    public void focusLost(FocusEvent event) {
	((DragComponent)event.getComponent()).loseFocus();
    }          
    /** Determines the current 'active' component, ie that component with focus.
     * @return The DragComponent which is currently responsible for drawing the ghost, and thus is active.
     */
    public DragComponent getActive() {
	return ghost_owner;
    }
    /** Retrieve the nodes selected at the beginning of this drag operation.
     * @return A TreePath[].
     */
    public TreePath[] getSelection() {
	return selection;
    }
    /** Retrieve the component which served as the source of this drag action.
     * @return The DragComponent in question.
     */
    public DragTree getSource() {
	return drag_source;
    }
    /** When called this method asserts that one of the registered GComponents just became the proud owner of focus, and is henceforth responsible for drawing the ghost, and acting like a component thats in focus.
     * @param new_owner The DragComponent that has gained focus during a drag action.
     */
    public void grabFocus(DragComponent new_owner) {
	// Tell the previous owner of ghost to clear itself.
	if(ghost_owner != null) {
	    ghost_owner.clearGhost();
	}
	// Assign new owner
	ghost_owner = new_owner;
	// Then tell all other GComponents to indicate they aren't in focus in whatever way they do that (ie selected items of a GTree go gray). Of course the new owners told it is in focus.
	for(int i = 0; i < registered.size(); i++) {
	    DragComponent comp = (DragComponent)registered.get(i);
	    if(comp == new_owner) {
		comp.gainFocus();
	    }
	    else {
		comp.loseFocus();
	    }
	}
    }
    /** Sets the value of selected_nodes.
     * @param selection The new value for selected_nodes as a TreePath[].
     */
    public void setSelection(TreePath[] selection) {
	this.selection = selection;
    }
    /** Sets the value of drag_source.
     * @param drag_source The new value for drag_source as a DragTree.
     */
    public void setSource(DragTree drag_source) {
	this.drag_source = drag_source;
	///ystem.err.println("The drag source is now " + drag_source);
    }
}
