/**
 *#########################################################################
 *
 * 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.
 *
 * Author: John Thompson, Greenstone Project, NZDL, University of Waikato
 *
 * Copyright (C) 2003 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.gui;

import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileView;
import org.greenstone.gatherer.Configuration;
import org.greenstone.gatherer.Dictionary;
import org.greenstone.gatherer.Gatherer;
import org.greenstone.gatherer.collection.BasicCollectionConfiguration;
import org.greenstone.gatherer.remote.RemoteGreenstoneServer;
import org.greenstone.gatherer.util.JarTools;
import org.greenstone.gatherer.util.StaticStrings;
import org.greenstone.gatherer.util.Utility;

public class NewCollectionDetailsPrompt
    extends ModalDialog {

    
    static public boolean titleClashes(String collectDir, String title, File current_config_file) {
	// An empty collection title never clashes with anything. It may look ugly in the final collection but there is nothing wrong with having no title for a particular language.
	if(title == null || title.length() == 0) {
	    return false;
	}
	File collect_directory = new File(collectDir);
	String file_name = (Gatherer.GS3)? Utility.CONFIG_GS3_FILE : Utility.CONFIG_FILE;
	File children[] = collect_directory.listFiles();
	for(int i = 0; children != null && i < children.length; i++) {
	    if(children[i].isDirectory()) {
		File config_file = new File(children[i], file_name);
		if(current_config_file == null || !config_file.equals(current_config_file)) {
		    BasicCollectionConfiguration other_collection = new BasicCollectionConfiguration(config_file);
		    if(other_collection.getName().equalsIgnoreCase(title)) {  
			return true;
		    }
		    other_collection = null;
		}
		config_file = null;
	    }
	}
	return false;
    }

    private boolean cancelled;
    private boolean collectDirChanged;
    private File base_final;
    private JButton chdir_button;
    private JButton create_button;
    private JComboBox base_collection;
    private JDialog self;
    private JRadioButton personal_collection_button = null;
    private JTextArea description;
    private JTextField title;
    private String collectBasePath;
    private String newCollectPath;
    private String description_final;
    private String title_final="";

    static private Dimension COMPONENT_SIZE = new Dimension(230, 25);
    /** The size of this new collection dialog box. */
    static private Dimension SIZE = new Dimension(600, 280);
    static private int FILENAME_SIZE = 8;

    /** Constructor.
     * @see org.greenstone.gatherer.util.Utility
     */
    public NewCollectionDetailsPrompt() {
	super(Gatherer.g_man, true);
	this.cancelled = true;
        this.setComponentOrientation(Dictionary.getOrientation());
	this.self = this;
	newCollectPath = Gatherer.getCollectDirectoryPath();
	collectBasePath = null;
	collectDirChanged = false;

	// Setup
	setJMenuBar(new SimpleMenuBar("creatingacollection"));
	setSize(SIZE);
	setTitle(Dictionary.get("NewCollectionPrompt.Title"));
	
	// Model building. Build a model of all of the collections in the gsdl collect directory with the appropriate directories.
	Vector base_collection_model = new Vector();
	setupBaseCollections(base_collection_model, null); // if no collect directory passed in: use default collect directory


	// Creation
	JPanel content_pane = (JPanel) getContentPane();
        content_pane.setComponentOrientation(Dictionary.getOrientation());
	content_pane.setOpaque(true);
	JPanel upper_pane = new JPanel();
        upper_pane.setComponentOrientation(Dictionary.getOrientation());
	JLabel instructions_label = new JLabel(Dictionary.get("NewCollectionPrompt.Instructions"));
	instructions_label.setComponentOrientation(Dictionary.getOrientation());
        
	JPanel title_pane = new JPanel();
        title_pane.setComponentOrientation(Dictionary.getOrientation());
	JLabel title_label = new JLabel(Dictionary.get("CDM.General.Collection_Name"));
        title_label.setComponentOrientation(Dictionary.getOrientation());
	title = new JTextField();
        title.setComponentOrientation(Dictionary.getOrientation());
	title.setPreferredSize(COMPONENT_SIZE);
	title.setToolTipText(Dictionary.get("CDM.General.Collection_Name_Tooltip"));
	JLabel name_label = new JLabel(Dictionary.get("NewCollectionPrompt.Collection_Name"));
	name_label.setComponentOrientation(Dictionary.getOrientation());
        
	JPanel center_pane = new JPanel();
        center_pane.setComponentOrientation(Dictionary.getOrientation());
	JPanel description_pane = new JPanel();
        description_pane.setComponentOrientation(Dictionary.getOrientation());
	JLabel description_label = new JLabel(Dictionary.get("NewCollectionPrompt.Collection_Description"));
        description_label.setComponentOrientation(Dictionary.getOrientation());
	description = new JTextArea();
        description.setComponentOrientation(Dictionary.getOrientation());
	description.setBackground(Configuration.getColor("coloring.editable_background", false));
	description.setForeground(Configuration.getColor("coloring.editable_foreground", false));
	description.setRows(5);
	description.setToolTipText(Dictionary.get("CDM.General.Collection_Extra_Tooltip"));
	
	JPanel bottom_pane = new JPanel();
        bottom_pane.setComponentOrientation(Dictionary.getOrientation());
	// Base Collection
	JPanel base_collection_pane = new JPanel();
        base_collection_pane.setComponentOrientation(Dictionary.getOrientation());
	
        JLabel base_collection_label = new JLabel(Dictionary.get("NewCollectionPrompt.Base_Collection"));
        base_collection_label.setComponentOrientation(Dictionary.getOrientation());
	
        base_collection = new JComboBox(base_collection_model);
        base_collection.setComponentOrientation(Dictionary.getOrientation());    
	base_collection.setOpaque(false);
	base_collection.setToolTipText(Dictionary.get("NewCollectionPrompt.Base_Collection_Tooltip"));
	
	JPanel collection_scope_pane = new JPanel();
        collection_scope_pane.setComponentOrientation(Dictionary.getOrientation());
	
        personal_collection_button = new JRadioButton(Dictionary.get("NewCollectionPrompt.Collection_Scope_Personal"));
        personal_collection_button.setToolTipText(Dictionary.get("NewCollectionPrompt.Collection_Scope_Personal_Tooltip"));
	personal_collection_button.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
	personal_collection_button.setOpaque(false);
        personal_collection_button.setComponentOrientation(Dictionary.getOrientation());
	
        JRadioButton shared_collection_button = new JRadioButton(Dictionary.get("NewCollectionPrompt.Collection_Scope_Shared"));        
	shared_collection_button.setToolTipText(Dictionary.get("NewCollectionPrompt.Collection_Scope_Shared_Tooltip")); 
	shared_collection_button.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
	shared_collection_button.setOpaque(false);
        shared_collection_button.setComponentOrientation(Dictionary.getOrientation());
	
        ButtonGroup collection_scope_group = new ButtonGroup();
	collection_scope_group.add(personal_collection_button);
	collection_scope_group.add(shared_collection_button);
	shared_collection_button.setSelected(true);

	JPanel button_pane = new JPanel();
        button_pane.setComponentOrientation(Dictionary.getOrientation());
	create_button = new GLIButton(Dictionary.get("General.OK"), Dictionary.get("General.OK_Tooltip"));
	chdir_button = new GLIButton(Dictionary.get("General.CD"), Dictionary.get("General.CD_Tooltip"));
	JButton cancel_button = new GLIButton(Dictionary.get("General.Cancel"), Dictionary.get("General.Cancel_Tooltip"));

	// Connection
	chdir_button.addActionListener(new ChangeDirListener());
	if(Gatherer.isGsdlRemote || Gatherer.isWebswing) { // for client GLI disable changing directories
	    chdir_button.setEnabled(false);	    
	} else { // can't base collections on any in OTHER collect dirs in client GLI
	    base_collection.addActionListener(new OtherCollectionsListener());
	}
	cancel_button.addActionListener(new CancelListener());
	create_button.addActionListener(new CreateListener());
	description.addKeyListener(new DescriptionListener());

	// Layout
	title_pane.setLayout(new BorderLayout(5,0));
	title_pane.add(title_label, BorderLayout.LINE_START);
	title_pane.add(title, BorderLayout.CENTER);

	upper_pane.setLayout(new GridLayout(2,1));
	upper_pane.add(instructions_label);
	upper_pane.add(title_pane);

        JScrollPane scrol_tmp;
        
	description_pane.setLayout(new BorderLayout());
	description_pane.add(description_label, BorderLayout.NORTH);        
        scrol_tmp=new JScrollPane(description);
        scrol_tmp.setComponentOrientation(Dictionary.getOrientation());
	description_pane.add(scrol_tmp, BorderLayout.CENTER);

	base_collection_pane.setLayout(new BorderLayout(5,0));
	base_collection_pane.add(base_collection_label, BorderLayout.LINE_START);
	base_collection_pane.add(base_collection, BorderLayout.CENTER);

	collection_scope_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
	collection_scope_pane.setLayout(new GridLayout(1,2));
	collection_scope_pane.add(personal_collection_button);
	collection_scope_pane.add(shared_collection_button);

	center_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
	center_pane.setLayout(new BorderLayout());
	center_pane.add(description_pane, BorderLayout.CENTER);

	bottom_pane.setLayout(new BorderLayout());
	bottom_pane.add(base_collection_pane, BorderLayout.NORTH);
	if (Gatherer.isGsdlRemote || Gatherer.isWebswing) {
          
	    bottom_pane.add(collection_scope_pane, BorderLayout.CENTER);
	    bottom_pane.add(button_pane, BorderLayout.SOUTH);
	}
	else {
	    bottom_pane.add(button_pane, BorderLayout.CENTER);
	}

        // should this apply to remote gli too?
        if (Gatherer.isWebswing) {
          if (!Gatherer.webswingAuthenticator.canEditSharedCollections()) {
            shared_collection_button.setEnabled(false);
            personal_collection_button.setSelected(true);
          }
          if (!Gatherer.webswingAuthenticator.canEditPersonalCollections()) {
            personal_collection_button.setEnabled(false);
            shared_collection_button.setSelected(true);
          }
        }
	button_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
	button_pane.setLayout(new GridLayout(1,3));
	button_pane.add(create_button);
	button_pane.add(chdir_button);
	button_pane.add(cancel_button);

	content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
	content_pane.setLayout(new BorderLayout());
	content_pane.add(upper_pane, BorderLayout.NORTH);
	content_pane.add(center_pane, BorderLayout.CENTER);
	content_pane.add(bottom_pane, BorderLayout.SOUTH);
	// Final dialog setup & positioning.
	getRootPane().setDefaultButton(create_button);
	Dimension screen_size = Configuration.screen_size;
	setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);

	TestingPreparation.setNamesRecursively(this);
	// Sadly, the following doesn't set the name of dialog for testing.
	// The name somehow assigned to the dialog is "col"
	//this.setName("NewCollectionDetailsPrompt");
	
	setVisible(true);
    }

    public boolean isCancelled() {
	return cancelled;
    }

    public File getBase() {
	return base_final;
    }

    public String getDescription() {
	return description_final;
    }
 
    /** Generates the collection short filename by taking the first eight characters of the title (spaces removed) and then adjusting by further truncating and then adding an unique suffix as necessary.
     * @return the filename as a String
     */
    public String getName()
    {
	// Retrieve the first 8 non-whitespace ASCII characters of title_final.
	StringBuffer name_buffer = new StringBuffer("");
	for (int i = 0, u = 0; (i < title_final.length() && u < 8); i++) {
	    // To be safe we make sure the internal collection name (folder name) contains only ASCII characters
	    char c = title_final.charAt(i);
	    if ((int) c < 128 && Character.isLetterOrDigit(c)) {
		name_buffer.append(Character.toLowerCase(c));
		u++;
	    }
	}

	// Use "col" as the base collection name if we have nothing left
	if (name_buffer.length() == 0) {
	    name_buffer = new StringBuffer("col");
	}

	// Remote collections that aren't shared have the user's username prefixed to the collection name
	if (Gatherer.isGsdlRemote && personal_collection_button.isSelected()) {
	    name_buffer = new StringBuffer(Gatherer.remoteGreenstoneServer.getUsername() + "@" + name_buffer.toString());
	}
	else if (Gatherer.isWebswing && personal_collection_button.isSelected()) {
	    name_buffer = new StringBuffer(Gatherer.webswingAuthenticator.getUsername() + "@" + name_buffer.toString());
	}
	

	// We need to ensure the filename is unique
	int counter = 0;
	StringBuffer new_name_buffer = new StringBuffer(name_buffer.toString());
	while(filenameClashes(new_name_buffer.toString())) {
	    new_name_buffer = new StringBuffer(name_buffer.toString());
	    counter++;
	    String suffix = String.valueOf(counter);
	    // If we have to truncate the namestring so as to fit the suffix
	    if(suffix.length() + new_name_buffer.length() > 8) {
		new_name_buffer.replace(new_name_buffer.length() - suffix.length(), new_name_buffer.length(), suffix);
	    }
	    // Or just append it if that isn't necessary
	    else {
		new_name_buffer.append(suffix);
	    }
	}

	// All done
	return new_name_buffer.toString();
    }
    
    private boolean filenameClashes(String filename)
    {
	File collect_directory = new File(Gatherer.getCollectDirectoryPath());
	File children[] = collect_directory.listFiles();
	for(int i = 0; children != null && i < children.length; i++) {
	    if(children[i].getName().equals(filename)) {
		return true;
	    }
	}
	return false;
    }

    public String getTitle() {
	return title_final;
    }

    private void setupBaseCollections(Vector base_collection_model, String collectDirectory) {

	File collect_directory = null;
	if(collectDirectory != null) {
	    collect_directory = new File(collectDirectory);
	}

	// need to modify this to base a coll on any collection from any site
	if (Gatherer.GS3 && !Gatherer.isGsdlRemote && !Gatherer.isWebswing) {
	    File sites_dir = new File(Gatherer.getSitesDirectoryPath());
	    File [] sites = sites_dir.listFiles();
	    for (int i=0; i<sites.length; i++) {
		if(collect_directory == null) {
		    collect_directory = new File(sites_dir + File.separator + sites[i].getName() + File.separator + "collect");
		} 
		if (collect_directory.exists()) {
		    addCollectionsToModel(base_collection_model, collect_directory, sites[i].getName());
		}
		collect_directory = null;
	    }
	} else {
	    if(collect_directory == null) { // if no collect directory passed in: use default collect directory
		collect_directory = new File(Gatherer.getCollectDirectoryPath());
	    }
	   addCollectionsToModel(base_collection_model, collect_directory, null);
	}

	// Sort the result.
	Collections.sort(base_collection_model);
	base_collection_model.add(0, new Item(null, Dictionary.get("NewCollectionPrompt.NewCollection")));
	
	// last item allows one to open up collections from other collect folders to base the new one on
	if(!Gatherer.isGsdlRemote && !Gatherer.isWebswing) { // Not yet implemented for client GLI
	    base_collection_model.add(new Item(null, Dictionary.get("NewCollectionPrompt.OtherCollections")));
	}
    }

    private void addCollectionsToModel(Vector base_collection_model, File collect_directory, String site) {
	File[] possible_collections = collect_directory.listFiles();
	String file_name = (Gatherer.GS3)? Utility.CONFIG_GS3_FILE : Utility.CONFIG_FILE;
	for (int i = 0; possible_collections != null && i < possible_collections.length; i++) {
	    // If the directory has a etc/collect.cfg file then it looks like a collection
	    File collect_cfg_file = new File(possible_collections[i], file_name);
	    if (collect_cfg_file.exists()) {
		// Check for group coll: Check the collect.cfg for collectgroup=true
		BasicCollectionConfiguration config = new BasicCollectionConfiguration(collect_cfg_file);
		if (config.getCollectGroup().equals("true")) {
		    // try subdirs in here
		    addCollectionsToModel(base_collection_model, possible_collections[i], site);
		} 
		else {
		    
		    // If the directory has a metadata/ then the collection can be used as a base
		    File metadata_directory = new File(possible_collections[i], "metadata");
		    if (metadata_directory.exists()) {
			// Add to model
			BasicCollectionConfiguration collect_cfg = new BasicCollectionConfiguration(collect_cfg_file);
			if (Gatherer.GS3 && site != null) {
			    collect_cfg.setSite(site);
			}
			Item item = new Item(possible_collections[i], collect_cfg);
			if (!base_collection_model.contains(item)) {
			    base_collection_model.add(item);
			}
		    }
		}
	    }
	}
       
    }

    private class OtherCollectionsListener implements ActionListener {

	// the JComboBox listener will receive an ActionEvent 
	// when a selection has been made

	public void actionPerformed(ActionEvent event) {

	    // If the Other Collections item was selected (which is the last one in the list)
	    if(base_collection.getSelectedIndex() == base_collection.getItemCount()-1) {

		// open a filechooser in whatever is the current collect directory
		// within the NewCollectionDetailsPrompt's settings
		if(collectBasePath == null) {
		    collectBasePath = newCollectPath;
		}

		JFileChooser chooser = new JFileChooser(collectBasePath);
		chooser.setFileView(new CollectionFileView());
		chooser.setDialogTitle(Dictionary.get("NewCollectionPrompt.ChooseACollection"));
		chooser.setApproveButtonText(Dictionary.get("NewCollectionPrompt.Select"));
		
		// to prevent the user from traversing into collection folders,
		// need to:
		// - NOT set the filechooser to Directories only, but files and directories
		// (so that they can still select directories)
		// - add a filefilter that accepts only directories (i.e. rejects files)
		// - remove the accept all filter
		chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
		//chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
		chooser.setFileFilter(new CollectionFileFilter());
		chooser.setAcceptAllFileFilterUsed(false);

		int returnVal = chooser.showOpenDialog(NewCollectionDetailsPrompt.this);
		if(returnVal == JFileChooser.APPROVE_OPTION) {

		    File selectedFile = chooser.getSelectedFile(); 
		    
		    // don't bother reloading if nothing has changed
		    if(collectBasePath.equals(selectedFile.getAbsolutePath() + File.separator)) { 
			// don't want Other Collections... selected
			base_collection.setSelectedIndex(0);
		    } else {

			// If the selected directory is a collection folder get its collect dir,
			// make collectBasePath the collect dir, and select the collection itself
			String cfg = (Gatherer.GS3)? Utility.CONFIG_GS3_FILE : Utility.CONFIG_FILE;
			boolean isCollection = false;
			while(new File(selectedFile, cfg).exists()) { // while loop handles collectgroup
			    selectedFile = selectedFile.getParentFile();
			    isCollection = true;
			} // else may be a collect dir, in which case leave it as it is again

			// found collect directory for base collections
			collectBasePath = selectedFile.getAbsolutePath()+File.separator; 

			// change the available collections to base this collection on
			base_collection.removeAllItems();
			Vector base_collection_model = new Vector();
			setupBaseCollections(base_collection_model, collectBasePath);
			for(int i = 0; i < base_collection_model.size(); i++) {
			    Item item = (Item)base_collection_model.get(i);
			    base_collection.addItem(item);

			    // select the originally chosen collection, if any, in the combobox
			    if(isCollection && chooser.getSelectedFile().equals(item.getFile())) {
				base_collection.setSelectedIndex(i);
			    }
			}
			
			// But if the user selected a collect group, set combobox to New Collection
			if(!isCollection) {
			    // if it was a collectgroup, nothing new would be selected, set to New Coll			    
			    if(base_collection.getSelectedIndex() == base_collection.getItemCount()-1) {
				base_collection.setSelectedIndex(0);
			    }
			}

		    } 

		} else { // cancelled out of dialog, so jump to New Collection
		    base_collection.setSelectedIndex(0);
		}		
	    }
	}
    }

    private class ChangeDirListener implements ActionListener {
	public void actionPerformed(ActionEvent event) {
	    String oldCollectPath = newCollectPath;
	    JFileChooser chooser = new JFileChooser(newCollectPath);
	    chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
	    chooser.setDialogTitle(Dictionary.get("General.ChooseCollectDirectory"));

	    int returnVal = chooser.showOpenDialog(NewCollectionDetailsPrompt.this);
	    if(returnVal == JFileChooser.APPROVE_OPTION) {
		newCollectPath = chooser.getSelectedFile().getAbsolutePath() + File.separator;

		// Must NOT change the available collections to base this collection on here.
		// It will change any collection the user previously chose to base the newcoll on.

		// will be used to test for duplicate collection names in current collect dir
		collectDirChanged = newCollectPath.equals(oldCollectPath) ? false : true;
	    }
	}
    }

    private class CancelListener
	implements ActionListener {
	public void actionPerformed(ActionEvent event) {
	    cancelled = true;
	    self.dispose();
	}
    }

    
    private class CreateListener
	implements ActionListener {
	
	public void actionPerformed(ActionEvent event) {
	    // Validate.
	    title_final = title.getText();
	    if(title_final.length() == 0) {
		JOptionPane jOptionPane=new JOptionPane();
                jOptionPane.setComponentOrientation(Dictionary.getOrientation());
		jOptionPane.setOpaque(!Utility.isMac());
		jOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("NewCollectionPrompt.Title_Error"), Dictionary.get("NewCollectionPrompt.Error"), JOptionPane.ERROR_MESSAGE);
		return;
	    }
	    // We must ensure that the collection title is unique. This is a pain in the nether regions as we are forced to load the collect.cfg of each other collection in turn looking for a conflicting title
	    else {
		String collectDir = collectDirChanged ? newCollectPath : Gatherer.getCollectDirectoryPath();
		if(titleClashes(collectDir, title_final, null)) {
		    JOptionPane jOptionPane=new JOptionPane();
                    jOptionPane.setComponentOrientation(Dictionary.getOrientation());
		    jOptionPane.setOpaque(!Utility.isMac());
		    if (jOptionPane.showConfirmDialog(Gatherer.g_man, Dictionary.get("NewCollectionPrompt.Title_Clash"), Dictionary.get("General.Warning"), JOptionPane.YES_NO_OPTION) == JOptionPane.NO_OPTION) {
			return;
		    }
		}
	    }		
	    description_final = description.getText();

	    // If we got this far there are no errors.
	    Item item_final = (Item) base_collection.getSelectedItem();
	    base_final = item_final.getFile();
	    
	    cancelled = false;
		
		self.dispose();
	    
	    // going through with collection creation
	    if(collectDirChanged) {		
		Gatherer.collectDirectoryHasChanged(Gatherer.getCollectDirectoryPath(), 
				newCollectPath, Gatherer.g_man.getContentPane()); 
		// will tell the server that the collect directory has changed and that
		// the workspace needs to be refreshed (Documents in Greenstone Collections)
	    }
	}
    }
    
    private class DescriptionListener
	extends KeyAdapter {
	public void keyPressed(KeyEvent event) {
	    if(event.getKeyCode() == KeyEvent.VK_TAB) {
		event.consume();
		base_collection.grabFocus();
	    }
	}
    }

    private class Item
	implements Comparable {
	private BasicCollectionConfiguration config;
	private File file;
	private String name;
	public Item(File file, BasicCollectionConfiguration config) {
	    this.config = config;
	    this.file = file;
	    this.name = null;
	}
	public Item(File file, String name) {
	    this.config = null;
	    this.file = file;
	    this.name = name;
	}
	public int compareTo(Object other) {
	    if(this == null && other == null) {
		return 0;
	    }
	    else if(other == null) { 
		return 1; 
	    }
	    else if(this == null) {
		return -1;
	    } 
	    else {
		return toString().toLowerCase().compareTo(other.toString().toLowerCase());
	    }
	}
	public boolean equals(Object other) {
	    return compareTo(other) == 0;
	}
	public File getFile() {
	    return file;
	}
	public String toString() {
	    if(name == null && config != null) {
		name = config.toString();
	    }
	    return name;
	}
    }

    /** FileFilter for the Filechooser to choose the collection to base the new one on: 
     * Only displays directories. */
    private class CollectionFileFilter extends FileFilter {	
	public boolean accept(File f) {
	    return f.isDirectory();
	}
	public String getDescription() {
	    return "greenstone collection view"; //return "directories only";
	}
    }

    /** Folders that can be used as a base collection have a special icon */
    private class CollectionFileView extends FileView {
	final String configfile_name;	
	final ImageIcon COLLECTION_ICON = JarTools.getImage("gsCollection.gif", true);
	
	private File previous = null;
	private boolean previousWasCollection = false;

	public CollectionFileView() {
	    configfile_name = (Gatherer.GS3)? Utility.CONFIG_GS3_FILE : Utility.CONFIG_FILE;
	}

	// A human readable description of the file.
	public String getDescription(File f) {
	    if(!f.equals(previous)) {
		previous = f;
		// no idea if it's a collection or not, calculate this next time
		previousWasCollection = false; 
	    }
	    return null; // FilewView superclass will handle it
	}
        
	// The icon that represents this file in the JFileChooser.
	public Icon getIcon(File f) {
	    
	    if(f.equals(previous) && previousWasCollection) {
		return COLLECTION_ICON;
	    } 
	    
	    if(isCollectionBase(f)) {
		return COLLECTION_ICON;
	    }	    
	    
	    return null; // FileView superclass will do the default
	}
        
	// The name of the file.
	public String getName(File f) { 
	    if(!f.equals(previous)) {
		previous = f;
		// no idea if it's a collection or not, calculate this next time
		previousWasCollection = false; 
	    }
	    return f.getName(); 
	}

	// A human readable description of the type of the file.
	public String getTypeDescription(File f) {
	    if(f.equals(previous) && previousWasCollection) {
		return "collection";
	    } 
	    if(isCollectionBase(f)) {
		return "collection";
	    }
	    // else
	    return "not a collection";
	}

	// Whether the directory is traversable or not.
	public Boolean isTraversable(File f) {
	    if(f.equals(previous) && previousWasCollection) {
		return Boolean.FALSE;
	    }		
	    
	    if(isCollectionBase(f)) {
		return Boolean.FALSE;
	    }

	    if(f.isFile()) { // not traversable
		return Boolean.FALSE;
	    }
	    // any other kind of directory is traversable
	    return Boolean.TRUE;	    
	}

    
	/** returns false for collect groups and collect dirs. */
	private boolean isCollectionBase(File f) {	    
	    previous = f;
	    previousWasCollection = false;

	    if(!f.isFile()) {
		// If the directory has a etc/collect.cfg file then it looks like a collection
		File collect_cfg_file = new File(f, configfile_name);
		if (collect_cfg_file.exists()) {
		    // Check for group coll: Check the collect.cfg for collectgroup=true
		    BasicCollectionConfiguration config = new BasicCollectionConfiguration(collect_cfg_file);
		    if (!config.getCollectGroup().equals("true")) {
			previousWasCollection = true;
		    }		
		}
	    }
	    return previousWasCollection;
	}

    }
}



