package org.greenstone.gatherer.gui;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.ArrayList;
import java.util.Vector;
import java.io.File;
import java.util.Observer;
import java.util.Observable;

import org.greenstone.gatherer.Configuration;
import org.greenstone.gatherer.Dictionary;
import org.greenstone.gatherer.Gatherer;
import org.greenstone.gatherer.cdm.DynamicListModel;
import org.greenstone.gatherer.metadata.MetadataSet;
import org.greenstone.gatherer.metadata.MetadataSetManager;
import org.greenstone.gatherer.gems.*;

public class MetadataSetDialog 
    extends ModalDialog {

    static private Dimension SIZE = new Dimension(600, 300);
    static private Dimension ADD_SIZE = new Dimension(600, 500);
    
    private ArrayList current_metadata_sets;
    private DynamicListModel current_metadata_model;

    private JButton add_button = null;
    private JButton edit_button = null;
    private JButton remove_button = null;

    private JButton close_button = null;
    
    private JList current_set_list = null;
    private MetadataSetDialog set_dialog = null;
    private boolean sets_changed = false;

    private GEMS gems = null;
    
    public MetadataSetDialog() {
	super(Gatherer.g_man, true);
	set_dialog = this;
	this.setComponentOrientation(Dictionary.getOrientation());
	setJMenuBar(new SimpleMenuBar("selectingmetadatasets"));
	setSize(SIZE);
	setTitle(Dictionary.get("MetadataSetDialog.Title"));
	
	current_metadata_sets = MetadataSetManager.getMetadataSets();
	current_metadata_model = new DynamicListModel();
	
	int current_size = current_metadata_sets.size();
	for (int i=0; i<current_size; i++) {
	    current_metadata_model.addElement(current_metadata_sets.get(i));
	}
	JPanel content_pane = (JPanel) getContentPane();
        content_pane.setComponentOrientation(Dictionary.getOrientation());
        content_pane.setOpaque(true);
	
	JLabel current_metadata_sets_label = new JLabel(Dictionary.get("MetadataSetDialog.Current_Sets"));
	current_metadata_sets_label.setComponentOrientation(Dictionary.getOrientation());
        current_metadata_sets_label.setOpaque(true);
	current_set_list = new JList(current_metadata_model);
        current_set_list.setComponentOrientation(Dictionary.getOrientation());
	current_set_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

	JPanel button_pane = new JPanel();
        button_pane.setComponentOrientation(Dictionary.getOrientation());
	add_button = new GLIButton(Dictionary.get("MetadataSetDialog.Add"), Dictionary.get("MetadataSetDialog.Add_Tooltip"));
	add_button.setEnabled(true);
	
	edit_button = new GLIButton(Dictionary.get("MetadataSetDialog.Edit"), Dictionary.get("MetadataSetDialog.Edit_Tooltip"));
	edit_button.setEnabled(false);
	
	remove_button = new GLIButton(Dictionary.get("MetadataSetDialog.Remove"), Dictionary.get("MetadataSetDialog.Remove_Tooltip"));
	remove_button.setEnabled(false);
	
	close_button = new GLIButton(Dictionary.get("General.Close"), Dictionary.get("General.Close_Tooltip"));
	close_button.setEnabled(true);


	// Add listeners
	add_button.addActionListener(new AddButtonListener());
	edit_button.addActionListener(new EditButtonListener());
	remove_button.addActionListener(new RemoveButtonListener());
	close_button.addActionListener(new ActionListener() {
		public void actionPerformed(ActionEvent event) {
		    set_dialog.dispose();
		}
	    });
	current_set_list.addListSelectionListener(new MetadataSetListSelectionListener());

	button_pane.setLayout(new GridLayout(2,3));
	button_pane.add(add_button);
	button_pane.add(edit_button);
	button_pane.add(remove_button);
	button_pane.add(new JPanel());
	button_pane.add(new JPanel());
	button_pane.add(close_button);

	content_pane.setLayout(new BorderLayout());
	content_pane.add(current_metadata_sets_label, BorderLayout.NORTH);
        JScrollPane scrol_tmp;
        scrol_tmp = new JScrollPane(current_set_list);
        scrol_tmp.setComponentOrientation(Dictionary.getOrientation());
	content_pane.add(scrol_tmp, BorderLayout.CENTER);
	content_pane.add(button_pane, BorderLayout.SOUTH);
	
	// Show
	Dimension screen_size = Configuration.screen_size;
	setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
	TestingPreparation.setNamesRecursively(this);
	setVisible(true);

    }

    public boolean setsChanged() {
	return sets_changed;
    }
    
    private class AddButtonListener
	implements ActionListener {

	public void actionPerformed(ActionEvent event) {
	    AddMetadataSetPrompt amsp = new AddMetadataSetPrompt();
	    if (!amsp.isCancelled()) {
		sets_changed = true;
	    }
	}
    }
    
    private class EditButtonListener
	implements ActionListener, GEMSListener {
	
	public void actionPerformed(ActionEvent event) {
	    // do a pop up message
	    MetadataSet metadata_set = (MetadataSet) current_set_list.getSelectedValue();
	    String metadata_path = metadata_set.getMetadataSetFile().toString();
	    if (gems == null){
		
		//gems = new GEMS(Configuration.gsdl_path,Configuration.gsdl3_web_path, Configuration.gsdl3_writableweb_path, "", false, false); // dangerous: this version of GEMS constructor only for if GEMS not launched through GLI but standalone
		// refer to comments in GEMS.java for GEMS constructors
		gems = new GEMS("", false); // right way to create GEMS app when launched by GLI
		gems.addGEMSListener(this);
	    }
	    gems.displayMetadataSet(metadata_path);
	}

	public void gemsIsClosed()
	{
	    // We assume that the selected metadata was edited, so reload it and remember to update the table
	    MetadataSet edited_metadata_set = (MetadataSet) current_set_list.getSelectedValue();
	    MetadataSetManager.unloadMetadataSet(edited_metadata_set);
	    // If we can make that assumption for a local GLI, then we can make it for a client-GLI too:
	    // assume mds file was edited and reupload to the remote server
	    Gatherer.c_man.updateMetadataSet(edited_metadata_set); // takes care of remote case
	    MetadataSetManager.loadMetadataSet(edited_metadata_set.getMetadataSetFile());
	    sets_changed = true;
	}
    }

    private class RemoveButtonListener
	implements ActionListener {
	
	public void actionPerformed(ActionEvent event) {
	    MetadataSet metadata_set = (MetadataSet) current_set_list.getSelectedValue();
	    current_metadata_model.removeElement(metadata_set);
	    Gatherer.c_man.removeMetadataSet(metadata_set);
	    sets_changed = true;
	    
	}

    }


    private class MetadataSetListSelectionListener
	implements ListSelectionListener {
	
	public void valueChanged(ListSelectionEvent event)
	{
	    // Wait until we get a stable event
	    if (event.getValueIsAdjusting()) {
		return;
	    }

	    // Now we can process it
	    if (!current_set_list.isSelectionEmpty() && !((MetadataSet)current_set_list.getSelectedValue()).getNamespace().equals(MetadataSetManager.EXTRACTED_METADATA_NAMESPACE)) {
		remove_button.setEnabled(true);
		edit_button.setEnabled(true);
	    }
	    else { 
		remove_button.setEnabled(false);
		edit_button.setEnabled(false);
	    }
	    
	}
	
    }

    private class AddMetadataSetPrompt
	extends ModalDialog implements GEMSListener{
	
	private JDialog add_set_dialog;
	private boolean cancelled = false;
	
	private JList elements_list;
	private JList available_sets_list;

	private JButton add_button;

	private JButton new_button;
     
	private  GEMSListener self;

	public AddMetadataSetPrompt() {
	    super(Gatherer.g_man, true);
            this.setComponentOrientation(Dictionary.getOrientation());
	    add_set_dialog = this;
	    setModal(true);
	    setJMenuBar(new SimpleMenuBar("choosingmetadatasets"));
	    setSize(ADD_SIZE);
	    setTitle(Dictionary.get("MetadataSetDialog.Add_Title"));
	    self = this;
	   

	    JPanel center_pane = new JPanel();
            center_pane.setComponentOrientation(Dictionary.getOrientation());
	    JPanel sets_pane = new JPanel();
            sets_pane.setComponentOrientation(Dictionary.getOrientation());
	    JLabel sets_label = new JLabel(Dictionary.get("MetadataSetDialog.Available_Sets"));
            sets_label.setComponentOrientation(Dictionary.getOrientation());
	    sets_label.setOpaque(false);
	    
	    available_sets_list = new JList(getValidSetModel());
            available_sets_list.setComponentOrientation(Dictionary.getOrientation());
	    available_sets_list.addListSelectionListener(new AvailableSetListSelectionListener());
	    available_sets_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
            
	    JPanel elements_pane = new JPanel();
            elements_pane.setComponentOrientation(Dictionary.getOrientation());
	    JLabel elements_label = new JLabel(Dictionary.get("MetadataSetDialog.Elements"));
	    elements_label.setComponentOrientation(Dictionary.getOrientation());
            
	    elements_list = new JList();
            elements_list.setComponentOrientation(Dictionary.getOrientation());
	    elements_list.setCellRenderer(new MetadataElementListCellRenderer());
	    elements_list.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
	    elements_list.setForeground(Configuration.getColor("coloring.collection_tree_foreground", false));
	    elements_list.setSelectionBackground(Configuration.getColor("coloring.collection_tree_background", false));
	    elements_list.setSelectionForeground(Configuration.getColor("coloring.collection_tree_foreground", false));
	    
	    JPanel button_pane = new JPanel();
            button_pane.setComponentOrientation(Dictionary.getOrientation());
	    add_button = new GLIButton(Dictionary.get("MetadataSetDialog.Add_Set"), Dictionary.get("MetadataSetDialog.Add_Set_Tooltip"));
	    add_button.setEnabled(false);
          
	    new_button = new GLIButton(Dictionary.get("MetadataSetDialog.New_Set"), Dictionary.get("MetadataSetDialog.New_Set_Tooltip"));
	   
	    JButton browse_button = new GLIButton(Dictionary.get("MetadataSetDialog.Browse"), Dictionary.get("MetadataSetDialog.Browse_Tooltip"));
	    browse_button.setEnabled(true);
	    JButton cancel_button = new GLIButton(Dictionary.get("General.Cancel"), Dictionary.get("General.Pure_Cancel_Tooltip"));
	    
	    add_button.addActionListener(new AddSetActionListener());
	    browse_button.addActionListener(new BrowseActionListener());
	    cancel_button.addActionListener(new ActionListener() {
		    public void actionPerformed(ActionEvent event) {
			cancelled = true;
			if (gems != null) {
			    gems.removeGEMSListener(self);
			}
			add_set_dialog.dispose();
		    }
		});
	    
	    new_button.addActionListener(new ActionListener() {
		    public void actionPerformed(ActionEvent event) {
			if (gems == null) {
			    //gems = new GEMS(Configuration.gsdl_path, Configuration.gsdl3_web_path, Configuration.gsdl3_writableweb_path, "", false, false); // dangerous: this version of GEMS constructor only for if GEMS not launched through GLI but standalone
			    // refer to comments in GEMS.java for GEMS constructors
			    gems = new GEMS("", false); // right way to create GEMS app when launched by GLI
			}
			gems.newMetadataSet();
			gems.addGEMSListener(self);
		    }
		});
            	    	    

	    // Layout
	    sets_pane.setLayout(new BorderLayout());
	    sets_pane.add(sets_label, BorderLayout.NORTH);
	    sets_pane.add(new JScrollPane(available_sets_list), BorderLayout.CENTER);

	    elements_pane.setLayout(new BorderLayout());
	    elements_pane.add(elements_label, BorderLayout.NORTH);
	    elements_pane.add(new JScrollPane(elements_list), BorderLayout.CENTER);

	    center_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
	    center_pane.setLayout(new GridLayout(2,1,0,5));
	    center_pane.add(sets_pane);
	    center_pane.add(elements_pane);
	    
	    button_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
	    button_pane.setLayout(new GridLayout(1,4,5,0));
	    button_pane.add(add_button);
	    button_pane.add(new_button); 
	    button_pane.add(browse_button);
	    button_pane.add(cancel_button);
	    
	    JPanel content_pane = (JPanel) getContentPane();
            content_pane.setComponentOrientation(Dictionary.getOrientation());
	    content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
	    content_pane.setLayout(new BorderLayout());
	    content_pane.add(center_pane, BorderLayout.CENTER);
	    content_pane.add(button_pane, BorderLayout.SOUTH);

	    // Show
	    Dimension screen_size = Configuration.screen_size;
	    setLocation((screen_size.width - ADD_SIZE.width) / 2, (screen_size.height - ADD_SIZE.height) / 2);
	    TestingPreparation.setNamesRecursively(this);
	    setVisible(true);
	    	   
	}
	
	public DynamicListModel getValidSetModel(){
	    // Show the metadata sets (except extracted, exploded, and currently assigned sets) in the GLI metadata folder
	    ArrayList all_metadata_sets = MetadataSetManager.listMetadataSets(new File(Gatherer.getGLIMetadataDirectoryPath()));
	    ArrayList current_metadata_sets = MetadataSetManager.getMetadataSets();
	    DynamicListModel valid_sets_model = new DynamicListModel();
	    for (int i=0; i<all_metadata_sets.size(); i++) {
		 MetadataSet set = (MetadataSet) all_metadata_sets.get(i);
		 if (set.getNamespace().equals(MetadataSetManager.EXTRACTED_METADATA_NAMESPACE) || set.getNamespace().equals(MetadataSetManager.EXPLODED_METADATA_NAMESPACE)) {
		    continue;
		 }
		// indexOf uses the equals() method, which for MetadataSets compares the toString() output, not the objects
		 if (current_metadata_sets.indexOf(set)!=-1) {
		    continue;
		 }
		 valid_sets_model.addElement(set);
	     }
	     
	    return valid_sets_model;
	}

	
	public void  gemsIsClosed(){ 
	    available_sets_list.setModel(getValidSetModel()); 
	}

	public boolean isCancelled() {
	    return cancelled;
	}

	private class AddSetActionListener
	    implements ActionListener {

	    public void actionPerformed(ActionEvent event) {
		if (available_sets_list.isSelectionEmpty()) {
		    return;
		}
		MetadataSet metadata_set = (MetadataSet) available_sets_list.getSelectedValue();
		String namespace = metadata_set.getNamespace();
		// have we got a variant already in the collection??
		MetadataSet existing_set = null;
		if ((existing_set = MetadataSetManager.getMetadataSet(namespace)) != null) {
		    // warn that we are replacing
		    String [] args = new String [] {metadata_set.toString(), existing_set.toString()};
		    WarningDialog namespace_clash_dialog = new WarningDialog("warning.MetadataSetNamespaceClash", Dictionary.get("MetadataSetNamespaceClash.Title"), Dictionary.get("MetadataSetNamespaceClash.Message", args), null, true);
		    if (namespace_clash_dialog.display()==JOptionPane.CANCEL_OPTION) {
			namespace_clash_dialog.dispose();
			return;
		    }
		    // if we have got here, then we remove the old set
		    current_metadata_model.removeElement(existing_set);
		    Gatherer.c_man.removeMetadataSet(existing_set);
		    sets_changed = true;
		    namespace_clash_dialog.dispose();
		}
		
		
		Gatherer.c_man.importMetadataSet(metadata_set);
		metadata_set = MetadataSetManager.getMetadataSet(namespace);
		current_metadata_model.addElement(metadata_set);
		sets_changed = true;
		cancelled = false;
		add_set_dialog.dispose();

	    }
	}

	private class BrowseActionListener
	    implements ActionListener {

	    public void actionPerformed(ActionEvent event) {
		JFileChooser chooser = new JFileChooser(new File(Gatherer.getGLIMetadataDirectoryPath()));
                chooser.setComponentOrientation(Dictionary.getOrientation());
		chooser.setFileFilter(new MetadataSet.MetadataSetFileFilter());
		chooser.setDialogTitle(Dictionary.get("MetadataSetDialog.Add_Title"));
		int return_val = chooser.showDialog(Gatherer.g_man, Dictionary.get("MetadataSetDialog.Add_Set"));
		if (return_val == JFileChooser.APPROVE_OPTION) {
		    MetadataSet meta_set = new MetadataSet(chooser.getSelectedFile());
		    Gatherer.c_man.importMetadataSet(meta_set);
		    current_metadata_model.addElement(meta_set);
		    cancelled = false;
		    add_set_dialog.dispose();
		} else {
		    // we do nothing - user may want to add from the other dialog
		}
	    }
	}
	
		
	private class AvailableSetListSelectionListener 
	    implements ListSelectionListener
	{
	    public void valueChanged(ListSelectionEvent event)
	    {
		// Wait until we get a stable event
		if (event.getValueIsAdjusting()) {
		    return;
		}

		if (!available_sets_list.isSelectionEmpty()) {
		    // Retrieve the selected set
		    MetadataSet metadata_set = (MetadataSet) available_sets_list.getSelectedValue();
		    elements_list.setListData(new Vector(metadata_set.getMetadataSetElements()));
		    add_button.setEnabled(true);
		}
		else {
		    elements_list.setListData(new String[0]);
		    add_button.setEnabled(false);
		}
	    }
	}
	
	
    }
}
