/**
 *############################################################################
 * A component of the Greenstone Librarian Interface, part of the Greenstone
 * digital library suite from the New Zealand Digital Library Project at the
 * University of Waikato, New Zealand.
 *
 * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
 *
 * Copyright (C) 2006 New Zealand Digital Library Project
 *
 * 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.
 *
 * 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.
 *
 * 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.collection;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.tree.*;
import org.greenstone.gatherer.Configuration;
import org.greenstone.gatherer.Dictionary;
import org.greenstone.gatherer.Gatherer;
import org.greenstone.gatherer.gui.tree.DragTree;
import org.greenstone.gatherer.gui.tree.DragTreeCellRenderer;


public class CollectionTree
    extends DragTree
    implements MouseListener
{
    public CollectionTree(CollectionTreeModel collection_tree_model, boolean mixed_selection)
    {
	super(collection_tree_model, mixed_selection);
	addMouseListener(this);

	setCellRenderer(new CollectionTreeCellRenderer());
	setBackgroundNonSelectionColor(Configuration.getColor("coloring.collection_tree_background", false));
	setBackgroundSelectionColor(Configuration.getColor("coloring.collection_selection_background", false));
	setTextNonSelectionColor(Configuration.getColor("coloring.collection_tree_foreground", false));
	setTextSelectionColor(Configuration.getColor("coloring.collection_selection_foreground", false));

	filter.setBackground(Configuration.getColor("coloring.collection_heading_background", false));
	filter.setEditable(Configuration.getMode() > Configuration.LIBRARIAN_MODE);
    }


    public boolean isDraggable()
    {
	return true;
    }


    public boolean isDroppable()
    {
	return true;
    }


    public void mouseClicked(MouseEvent event)
    {
	if (SwingUtilities.isRightMouseButton(event)) {
	    new CollectionTreeRightClickMenu(this, event);
	}
    }

    public void mouseEntered(MouseEvent event) { }

    public void mouseExited(MouseEvent event) { }

    public void mousePressed(MouseEvent event) { }

    public void mouseReleased(MouseEvent event) { }


    public String toString()
    {
	return "Collection";
    }


    private class CollectionTreeCellRenderer
	extends DragTreeCellRenderer
    {
	public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus)
	{
	    JLabel tree_cell = (JLabel) super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);

	    // Mark explodable files with a different icon
	    if (value instanceof CollectionTreeNode && ((CollectionTreeNode) value).isExplodable()) {
		tree_cell.setIcon(CollectionTreeNode.GREEN_FILE_ICON);
	    }

	    return tree_cell;
	}
    }


    /** When a user right-clicks within the workspace and collection trees they are presented with a small popup menu of context based options. This class provides such functionality.
     */
    private class CollectionTreeRightClickMenu
	extends JPopupMenu
	implements ActionListener
    {
	/** The tree over which the right click action occurred. */
	private CollectionTree collection_tree = null;
	/** The tree nodes selected when the right click action occurred. */
	private TreePath[] selection_paths = null;
	/** The file record over which the right click action occurred. */
	private CollectionTreeNode node = null;

	private JMenuItem collapse_folder = null;
	private JMenuItem expand_folder = null;
	private JMenuItem explode_metadata_database = null;
	private JMenuItem delete = null;
	private JMenuItem metaaudit = null;
	private JMenuItem new_folder = null;
	private JMenuItem new_dummy_doc = null;
	private JMenuItem open_externally = null;
	private JMenuItem rename = null;
	private JMenuItem replace = null;


	private CollectionTreeRightClickMenu(CollectionTree collection_tree, MouseEvent event)
	{
	    super();
	    this.collection_tree = collection_tree;

	    // Note we have to use setImmediate() with the set selction paths
	    // otherwise the selection doesn't get updated until after the 
	    // popup comes up.

	    // the right click position
	    TreePath right_click_path = collection_tree.getPathForLocation(event.getX(), event.getY());
	    if (right_click_path == null) {
		// user has clicked outside of the tree, clear the selection
		selection_paths = null;
		collection_tree.setImmediate(true);
		collection_tree.clearSelection();
		collection_tree.setImmediate(false);
	    }
	    else {
		// Get the paths currently selected in the tree
		selection_paths = collection_tree.getSelectionPaths();
		if (selection_paths == null) {
		    // nothing currently selected - we shift the selection to 
		    // the node that was right clicked on
		    selection_paths = new TreePath[1];
		    selection_paths[0] = right_click_path;
		    collection_tree.setImmediate(true);
		    collection_tree.setSelectionPath(right_click_path);
		    collection_tree.setImmediate(false);
		}
		else if (selection_paths.length == 1 && ! selection_paths[0].equals( right_click_path)) {
		    collection_tree.setImmediate(true);
		    collection_tree.clearSelection();
		    collection_tree.setSelectionPath(right_click_path);
		    collection_tree.setImmediate(false);
		    selection_paths[0] = right_click_path;
		}
		else {
		    // we had multiply selected paths in the tree.
		    // if we clicked on one of those paths, then use all the 
		    // current selection, otherwise clear the selection and 
		    // select the one we right clicked on
		    boolean clicked_in_selection = false;
		    for (int i = 0; i < selection_paths.length; i++) {
			if (selection_paths[i].equals(right_click_path)) {
			    clicked_in_selection = true;
			    break;
			}
		    }
		    if (!clicked_in_selection) {
			// want the tree to update right away
			collection_tree.setImmediate(true);
			collection_tree.clearSelection();
			collection_tree.setSelectionPath(right_click_path);
			collection_tree.setImmediate(false);
			selection_paths = new TreePath[1];
			selection_paths[0] = right_click_path;
		    }
		}
	    }
	    
	    // Create an appropriate context menu, based on what is selected
	    buildContextMenu(selection_paths);

	    // Show the popup menu on screen
	    show(collection_tree, event.getX(), event.getY());
	}


	private void buildContextMenu(TreePath[] selection_paths)
	{
	    // If nothing is selected, only the new folder/dummy doc options are available...
	    if (selection_paths == null) {
		new_folder = new JMenuItem(Dictionary.get("CollectionPopupMenu.New_Folder"), KeyEvent.VK_N);
		new_folder.addActionListener(this);
		add(new_folder);

		new_dummy_doc = new JMenuItem(Dictionary.get("CollectionPopupMenu.New_Dummy_Doc"));
		new_dummy_doc.addActionListener(this);
		add(new_dummy_doc);

		node = (CollectionTreeNode) collection_tree.getModel().getRoot();
		return;
	    }

	    // Meta-audit and delete options
	    metaaudit = new JMenuItem(Dictionary.get("Menu.Metadata_View", collection_tree.getSelectionDetails()), KeyEvent.VK_A);
	    metaaudit.addActionListener(this);
	    add(metaaudit);

	    delete = new JMenuItem(Dictionary.get("CollectionPopupMenu.Delete"), KeyEvent.VK_D);
	    delete.addActionListener(this);
	    add(delete);

	    // Only meta-audit and delete are available if multiple items are selected...
	    if (selection_paths.length > 1) {
		return;
	    }

	    // Rename option
	    // !! TO DO: Remote building
	    if (!Gatherer.isGsdlRemote) {
		rename = new JMenuItem(Dictionary.get("CollectionPopupMenu.Rename"), KeyEvent.VK_R);
		rename.addActionListener(this);
		add(rename);
	    }

	    TreePath path = selection_paths[0];
	    node = (CollectionTreeNode) path.getLastPathComponent();

	    // ---- Options for file nodes ----
	    if (node.isLeaf()) {
		// Explode metadata databases, for explodable files only
		if (node.isExplodable()) {
		    explode_metadata_database = new JMenuItem(Dictionary.get("Menu.Explode_Metadata_Database"), KeyEvent.VK_E);
		    explode_metadata_database.addActionListener(this);
		    add(explode_metadata_database);
		}
		// Replace file
		// !! TO DO: Remote building
		if (!Gatherer.isGsdlRemote) {
		    replace = new JMenuItem(Dictionary.get("CollectionPopupMenu.Replace"), KeyEvent.VK_P);
		    replace.addActionListener(this);
		    add(replace);
		}
		
		// Open the file in an external program
		open_externally = new JMenuItem(Dictionary.get("Menu.Open_Externally"), KeyEvent.VK_O);
		open_externally.addActionListener(this);
		add(open_externally);

		return;
	    }

	    // ---- Options for folder nodes ----
	    // Collapse or expand, depending on current status
	    if (collection_tree.isExpanded(path)) {
		collapse_folder = new JMenuItem(Dictionary.get("Menu.Collapse"), KeyEvent.VK_C);
		collapse_folder.addActionListener(this);
		add(collapse_folder);
	    }
	    else {
		expand_folder = new JMenuItem(Dictionary.get("Menu.Expand"), KeyEvent.VK_O);
		expand_folder.addActionListener(this);
		add(expand_folder);
	    }

	    // New folder/dummy doc options
	    if (!node.isReadOnly()) {
		new_folder = new JMenuItem(Dictionary.get("CollectionPopupMenu.New_Folder"), KeyEvent.VK_N);
		new_folder.addActionListener(this);
		add(new_folder);

		new_dummy_doc = new JMenuItem(Dictionary.get("CollectionPopupMenu.New_Dummy_Doc"));
		new_dummy_doc.addActionListener(this);
		add(new_dummy_doc);
	    }
	}


	/** Called whenever one of the menu items is clicked, this method then causes the appropriate effect. */
	public void actionPerformed(ActionEvent event)
	{
  	    Object source = event.getSource();

	    // Collapse folder
	    if (source == collapse_folder) {
		collection_tree.collapsePath(selection_paths[0]);
	    }

	    // Expand folder
	    else if (source == expand_folder) {
		collection_tree.expandPath(selection_paths[0]);
	    }

	    // Explode metadata database
	    else if (source == explode_metadata_database) {
 		Gatherer.f_man.explodeMetadataDatabase(node.getFile());
	    }

	    // Delete
	    else if (source == delete) {
		CollectionTreeNode[] source_nodes = new CollectionTreeNode[selection_paths.length];
		for (int i = 0; i < selection_paths.length; i++) {
		    source_nodes[i] = (CollectionTreeNode) selection_paths[i].getLastPathComponent();
		}

		// Fire a delete action
		Gatherer.f_man.action(collection_tree, source_nodes, Gatherer.recycle_bin, null);
	    }

	    // Meta-audit
	    else if (source == metaaudit) {
 		Gatherer.g_man.showMetaAuditBox();
 	    }

	    // New folder
  	    else if (source == new_folder) {
 		Gatherer.f_man.newFolder(collection_tree, node);
 	    }

	    // New dummy doc
	    else if (source == new_dummy_doc) {
		Gatherer.f_man.newDummyDoc(collection_tree, node);
	    }

	    // Open in external program
	    else if (source == open_externally) {
		Gatherer.f_man.openFileInExternalApplication(node.getFile());
	    }

	    // Rename
	    else if (source == rename) {
		Gatherer.f_man.renameCollectionFile(collection_tree, node);
	    }

	    // Replace
	    else if (source == replace) {
		Gatherer.f_man.replaceCollectionFile(collection_tree, node);
	    }
  	}
    }
}
