/**
 *#########################################################################
 *
 * 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 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.StaticStrings;
import org.greenstone.gatherer.util.Utility;

public class NewCollectionDetailsPrompt
    extends ModalDialog {

    static public boolean titleClashes(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(Gatherer.getCollectDirectoryPath());
	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], Utility.CONFIG_FILE);
		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 File base_final;
    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 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.self = this;
	// 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();
	// need to modify this to base a coll on any collection from any site
	if (Gatherer.GS3) {
	    File sites_dir = new File(Gatherer.getSitesDirectoryPath());
	    File [] sites = sites_dir.listFiles();
	    for (int i=0; i<sites.length; i++) {
		File collect_directory = new File(sites_dir + sites[i].getName() + File.separator + "collect");
		if (collect_directory.exists()) {
		    addCollectionsToModel(base_collection_model, collect_directory, sites[i].getName());
		}
	    }
	} else {
	   File 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")));

	// Creation
	JPanel content_pane = (JPanel) getContentPane();
	content_pane.setOpaque(true);
	JPanel upper_pane = new JPanel();
	JLabel instructions_label = new JLabel(Dictionary.get("NewCollectionPrompt.Instructions"));
	
	JPanel title_pane = new JPanel();
	JLabel title_label = new JLabel(Dictionary.get("CDM.General.Collection_Name"));
	title = new JTextField();
	title.setPreferredSize(COMPONENT_SIZE);
	title.setToolTipText(Dictionary.get("CDM.General.Collection_Name_Tooltip"));
	JLabel name_label = new JLabel(Dictionary.get("NewCollectionPrompt.Collection_Name"));
	
	JPanel center_pane = new JPanel();
	JPanel description_pane = new JPanel();
	JLabel description_label = new JLabel(Dictionary.get("NewCollectionPrompt.Collection_Description"));
	description = new JTextArea();
	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();
	// Base Collection
	JPanel base_collection_pane = new JPanel();
	JLabel base_collection_label = new JLabel(Dictionary.get("NewCollectionPrompt.Base_Collection"));
	base_collection = new JComboBox(base_collection_model);
	base_collection.setOpaque(false);
	base_collection.setToolTipText(Dictionary.get("NewCollectionPrompt.Base_Collection_Tooltip"));
	
	JPanel collection_scope_pane = new JPanel();
	personal_collection_button = new JRadioButton(Dictionary.get("NewCollectionPrompt.Collection_Scope_Personal"));
	personal_collection_button.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
	personal_collection_button.setOpaque(false);
	JRadioButton shared_collection_button = new JRadioButton(Dictionary.get("NewCollectionPrompt.Collection_Scope_Shared"));
	shared_collection_button.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
	shared_collection_button.setOpaque(false);
	ButtonGroup collection_scope_group = new ButtonGroup();
	collection_scope_group.add(personal_collection_button);
	collection_scope_group.add(shared_collection_button);
	personal_collection_button.setSelected(true);

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

	// Connection
	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.WEST);
	title_pane.add(title, BorderLayout.CENTER);

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

	description_pane.setLayout(new BorderLayout());
	description_pane.add(description_label, BorderLayout.NORTH);
	description_pane.add(new JScrollPane(description), BorderLayout.CENTER);

	base_collection_pane.setLayout(new BorderLayout(5,0));
	base_collection_pane.add(base_collection_label, BorderLayout.WEST);
	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) {
	    bottom_pane.add(collection_scope_pane, BorderLayout.CENTER);
	    bottom_pane.add(button_pane, BorderLayout.SOUTH);
	}
	else {
	    bottom_pane.add(button_pane, BorderLayout.CENTER);
	}

	button_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
	button_pane.setLayout(new GridLayout(1,2));
	button_pane.add(create_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.
	Dimension screen_size = Configuration.screen_size;
	setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
	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(RemoteGreenstoneServer.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 addCollectionsToModel(Vector base_collection_model, File collect_directory, String site) {
	File[] possible_collections = collect_directory.listFiles();
	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], Utility.CONFIG_FILE);
	    if (collect_cfg_file.exists()) {
		// 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 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.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 {
		if(titleClashes(title_final, null)) {
		    JOptionPane jOptionPane=new JOptionPane();
		    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();
	}
    }
    
    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) {
	    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;
	}
    }
}



