 /**
 *#########################################################################
 *
 * A component of the Gatherer application, part of the Greenstone digital
 * library suite from the New Zealand Digital Library Project at th * University of Waikato, New Zealand.
 *
 * <BR><BR>
 *
 * Author: Shaoqun Wu, Greenstone Digital Library, University of Waikato
 *
 * <BR><BR>
 *
 * Copyright (C) 2006 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.gems;

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import java.lang.String;
import javax.swing.event.*;
import javax.swing.filechooser.*;
import javax.swing.text.*;
import javax.swing.tree.*;
import java.awt.*;
import java.awt.event.*;

import java.io.File;

import org.greenstone.gatherer.Configuration;
import org.greenstone.gatherer.DebugStream;
import org.greenstone.gatherer.Dictionary;
import org.greenstone.gatherer.GetOpt;
import org.greenstone.gatherer.gui.GComboBox;
import org.greenstone.gatherer.gui.GLIButton;
import org.greenstone.gatherer.gui.HelpFrame;
import org.greenstone.gatherer.gui.ModalDialog;
import org.greenstone.gatherer.gui.NonWhitespaceField;
import org.greenstone.gatherer.util.Codec;
import org.greenstone.gatherer.util.JarTools;
import org.greenstone.gatherer.util.Utility;
import org.greenstone.gatherer.util.XMLTools;
import org.greenstone.gatherer.Dictionary;
import org.w3c.dom.*;


/* 
 * @author Shaoqun Wu, Greenstone Digital Library, University of Waikato
 * @version 2.4
 */ 
public class GEMS
    extends JFrame implements WindowFocusListener 
{
 
    static final private Dimension SIZE = new Dimension(800,550);

    // we have a card pane to switch between the no set loaded view, and the 
    // set loaded view
    private CardLayout card_layout = null;
    private JPanel card_pane = null;
    /** The name of the panel containing the "set loaded" card. */
    private String SET_LOADED_CARD = "";
    /** The name of the panel containing the "no set loaded" placeholder */
    private String NO_SET_LOADED_CARD = "No set loaded";

    private GEMS self = null;

    private OpenMetadataSetPrompt open_prompt;
    private DeleteMetadataSetPrompt delete_prompt;
    private NewMetadataSetPrompt new_prompt;   
    
    // this is the main panel that gets switched in once a set is loaded
    private JSplitPane metadata_set_details_split_pane = null;
    // this is the split with the attribute tables in it
    private JSplitPane attribute_tables_split_pane = null;
     
    /** Um, the size of the screen I'd guess. */
    private Dimension screen_size = null;
    
    private MetadataSetManager msm;

    private AttributeTable attribute_table;  // meta_element_table
    private AttributeTable language_dependent_attribute_table; //lang_element_table; 

    private MetadataSetTree meta_set_tree;     

    private MetadataSetModel metadata_set_model;

    private boolean stand_alone = true;

    private ArrayList listeners;

    static public void main(String[] args)
    {
	//TODO: add an option to open a paticular metadata set

	// Parse arguments
	GetOpt go = new GetOpt(args);

	if (go.debug) {
	    DebugStream.enableDebugging();

	    Calendar now = Calendar.getInstance();
	    String debug_file_path = "debug" + now.get(Calendar.DATE) + "-" + now.get(Calendar.MONTH) + "-" + now.get(Calendar.YEAR) + ".txt";
	    
	    // Debug file is created in the GLI directory
	    DebugStream.println("Debug file path: " + debug_file_path);
	    DebugStream.setDebugFile(debug_file_path);   

	}
       	new GEMS(go.gsdl_path,go.metadata_path,true,go.new_set);
    }


    /** Constructor.
     */
    public GEMS(String gsdl_path, String metadata_path, boolean standalone, boolean new_set)
    {
	self = this;
	JarTools.initialise(this);        
	screen_size = Configuration.screen_size;
        msm = new MetadataSetManager(gsdl_path);       
        stand_alone = standalone;
	listeners = new ArrayList();

        addWindowListener(new WindowAdapter(){
		public void windowClosing(WindowEvent e){
		    metadata_set_model.save(true);
		    if (stand_alone){
			System.exit(0);
		    }
		    else {
			notifyListeners();
			setVisible(false);
		    }
		}
	    });
	
	setSize(SIZE);
	setTitle(Dictionary.get("GEMS.Title"));
	setJMenuBar(new GEMSMenuBar());

	addWindowFocusListener(this);

	card_layout = new CardLayout();
	card_pane = new JPanel();

        metadata_set_model = new MetadataSetModel(msm);
        msm.setMetadataSetModel(metadata_set_model);
	meta_set_tree = new MetadataSetTree(self);
        metadata_set_model.addObserver(meta_set_tree);

	attribute_table = new AttributeTable(false);
	MetadataElementModel mem = new MetadataElementModel();
        mem.addMetadataElementListener((MetadataElementListener)attribute_table);
	attribute_table.addAttributeListener(metadata_set_model);

	language_dependent_attribute_table = new AttributeTable(true);
        mem.addMetadataElementListener((MetadataElementListener)language_dependent_attribute_table);
	language_dependent_attribute_table.addAttributeListener(metadata_set_model);

      	MetadataSetInfo msti= new MetadataSetInfo();
        msti.addMetadataSetListener((MetadataSetListener)attribute_table);
        msti.addMetadataSetListener((MetadataSetListener)language_dependent_attribute_table);
        msti.setMetadataSetModel(metadata_set_model);
        
        open_prompt = new OpenMetadataSetPrompt(self,msm);
        open_prompt.addMetadataSetListener((MetadataSetListener)metadata_set_model);
        open_prompt.addMetadataSetListener((MetadataSetListener)attribute_table);        
	open_prompt.addMetadataSetListener((MetadataSetListener)language_dependent_attribute_table); 	
	
        delete_prompt = new DeleteMetadataSetPrompt(self,msm);
        delete_prompt.addMetadataSetListener((MetadataSetListener)metadata_set_model); 
        delete_prompt.addMetadataSetListener((MetadataSetListener)attribute_table);
	delete_prompt.addMetadataSetListener((MetadataSetListener)language_dependent_attribute_table);
	
        new_prompt = new NewMetadataSetPrompt(self,msm);
        new_prompt.addMetadataSetListener((MetadataSetListener)metadata_set_model); 
        new_prompt.addMetadataSetListener((MetadataSetListener)attribute_table);
        new_prompt.addMetadataSetListener((MetadataSetListener)language_dependent_attribute_table);
  

        // load the initial metadataset
        if (metadata_path !=null && !metadata_path.equals("")){
	    open_prompt.openMetadataSet(metadata_path);
	}
	else{
	    if (new_set) new_prompt.display();
	}

	// the set tree
        JScrollPane treePane = new JScrollPane(meta_set_tree);
	// the language independent attributes
	JScrollPane tablePane = new JScrollPane(attribute_table);
	// the language dependent attributes
	JScrollPane langTablePane =  new JScrollPane(language_dependent_attribute_table);

	// no set loaded pane
	JPanel no_set_loaded_pane = new JPanel();
	no_set_loaded_pane.setBackground(Color.lightGray);
	JLabel no_set_loaded_label = new JLabel(Dictionary.get("GEMS.No_Set_Loaded"));
	no_set_loaded_label.setHorizontalAlignment(JLabel.CENTER);
	no_set_loaded_label.setVerticalAlignment(JLabel.CENTER);

	no_set_loaded_pane.setLayout(new BorderLayout());
	no_set_loaded_pane.add(no_set_loaded_label, BorderLayout.CENTER);

        JPanel buttonPane = new JPanel(new GridLayout(1,2));
        
        JButton arrow_up_button = new GLIButton(Dictionary.get("GEMS.Move_Up"));
	arrow_up_button.setIcon(JarTools.getImage("arrow-up.gif"));

        JButton arrow_down_button = new GLIButton(Dictionary.get("GEMS.Move_Down"));
	arrow_down_button.setIcon(JarTools.getImage("arrow-down.gif")); 
        
        arrow_up_button.setActionCommand(GEMSConstants.MOVE_UP);
	arrow_up_button.addActionListener(meta_set_tree);
        arrow_down_button.addActionListener(meta_set_tree);
	arrow_down_button.setActionCommand(GEMSConstants.MOVE_DOWN);
	
	buttonPane.add(arrow_up_button);
        buttonPane.add(arrow_down_button);
        
        JPanel leftPane =  new JPanel(new BorderLayout());          
        leftPane.add(treePane,BorderLayout.CENTER);  
	leftPane.add(buttonPane,BorderLayout.SOUTH);  
         
	JLabel selected_language_label = new JLabel(Dictionary.get("GEMS.SelectedLanguage"));
	selected_language_label.setOpaque(true);
        
	Vector language_vector = new Vector(msm.getLanguageList());
        language_vector.add(0, Dictionary.get("GEMS.Language"));
	JComboBox language_combo = new JComboBox(language_vector);
	
	language_combo.addActionListener(new ActionListener(){
		public void actionPerformed(ActionEvent e){
		    JComboBox language_combo = (JComboBox) e.getSource();
		    String langInfo = (String)language_combo.getSelectedItem(); 
		    if (!langInfo.equals(Dictionary.get("GEMS.Language"))) {
			String lang = langInfo.split("\\s")[0];     		    
			language_dependent_attribute_table.addNewLanguage(lang);
		    }
		}

	    });      

       	JLabel language_label = new JLabel(Dictionary.get("GEMS.LanguageDependent"));
	language_label.setOpaque(true);
      
         	
	JPanel selectLangPane = new JPanel(new BorderLayout(5,5));
        selectLangPane.add(selected_language_label,BorderLayout.WEST);
        selectLangPane.add(language_combo, BorderLayout.CENTER);   


        JPanel languagePane =  new JPanel(new BorderLayout(5,5));
	languagePane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
	languagePane.add(language_label,BorderLayout.NORTH);  
        languagePane.add(selectLangPane,BorderLayout.CENTER);        


        JPanel languageAttributePane =  new JPanel(new BorderLayout());
	languageAttributePane.add(languagePane,BorderLayout.NORTH);  
        languageAttributePane.add(langTablePane,BorderLayout.CENTER);        

	JLabel attribute_label = new JLabel(Dictionary.get("GEMS.Attribute_Table"));
	attribute_label.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
	JPanel mainAttributePane = new JPanel(new BorderLayout());
	mainAttributePane.add(attribute_label, BorderLayout.NORTH);
	mainAttributePane.add(tablePane, BorderLayout.CENTER);
	
	attribute_tables_split_pane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,mainAttributePane,languageAttributePane);
	
	metadata_set_details_split_pane =  new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,leftPane,attribute_tables_split_pane); 	

	card_pane.setLayout(card_layout);
	card_pane.add(no_set_loaded_pane, NO_SET_LOADED_CARD);
	card_pane.add(metadata_set_details_split_pane, SET_LOADED_CARD);

	getContentPane().add(card_pane,BorderLayout.CENTER);
	setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
	if (stand_alone)
	    setVisible(true);
    }

    public void setVisible(boolean visible) {
	super.setVisible(visible);
	if (visible) {
	    attribute_tables_split_pane.setDividerLocation(0.3);
	}
    }
    
    // called from GLI
    public void displayMetadataSet(String metadata_path){
	open_prompt.openMetadataSet(metadata_path);
	updateCardLayout(true);
	setVisible(true);
    }   

    // called from GLI
    public void newMetadataSet(){
	new_prompt.display();
	if (!new_prompt.isCancelled()) {
	    updateCardLayout(true);
	    setVisible(true);
	}

    }

    public void addGEMSListener(GEMSListener listener){
	listeners.add(listener);
    }  

    public void removeGEMSListener(GEMSListener listener){
	listeners.remove(listener);
    }  

    public void notifyListeners(){
	for (int i=0;i<listeners.size();i++){
	    GEMSListener listener = (GEMSListener) listeners.get(i); 
	    listener.gemsIsClosed();
	}
    }


    public void exit(){
	//clean up things
	cleanUpListeners();
    }
    
    protected void cleanUpListeners() {
	MetadataSetInfo msti= new MetadataSetInfo();
	msti.removeAllMetadataSetListeners();
	MetadataElementModel mem= new MetadataElementModel();
	mem.removeAllMetadataElementListeners();

    }
    
    public void windowGainedFocus(WindowEvent e) {
	//System.out.println("windowGainedFocus.");
    }

    public void windowLostFocus(WindowEvent e) {
        //System.out.println("windowLostFocus.");
          
	//save stuff
	
    }

    protected void updateCardLayout(boolean set_loaded) {
	if (set_loaded) {
	    card_layout.show(card_pane, SET_LOADED_CARD);
	} else {
	    card_layout.show(card_pane, NO_SET_LOADED_CARD);
	}
    }
   
    private class GEMSMenuBar
	extends JMenuBar
	implements ActionListener
    {
	private JMenu file = null;
	private JMenu edit = null;

	public JMenuItem file_exit   = null;
	public JMenuItem file_new    = null;
	public JMenuItem file_open   = null;
	public JMenuItem file_close   = null;
	public JMenuItem file_save   = null;
	public JMenuItem edit_copy   = null;
	public JMenuItem edit_cut    = null;
	public JMenuItem edit_paste  = null;
	public JMenuItem help_help   = null;
        public JMenuItem file_delete = null;
        //public JMenuItem file_preferences = null;
	public GEMSMenuBar()
	{
	    file = new JMenu();
	    file.setText(Dictionary.get("Menu.File"));
	    
	    file_exit = new JMenuItem(Dictionary.get("Menu.File_Exit"));
	    file_exit.addActionListener(this);
	    
	    file_new = new JMenuItem(Dictionary.get("Menu.File_New"));
	    file_new.addActionListener(this);

	    file_open = new JMenuItem(Dictionary.get("Menu.File_Open"));
	    file_open.addActionListener(this);
	    
	    file_close = new JMenuItem(Dictionary.get("Menu.File_Close"));
	    file_close.addActionListener(this);

	    file_save = new JMenuItem(Dictionary.get("Menu.File_Save"));
	    file_save.addActionListener(this);
   
            file_delete = new JMenuItem(Dictionary.get("Menu.File_Delete"));
	    file_delete.addActionListener(this);
	                
            //file_preferences = new JMenuItem(Dictionary.get("Menu.File_Options"));
	    //file_preferences.addActionListener(this);
	    
	    if (!stand_alone) {
		// when running from GLI, we disable most of the menu so 
		// that we have control over what sets the user is editing
		file_new.setEnabled(false);
		file_open.setEnabled(false);
		file_close.setEnabled(false);
		file_delete.setEnabled(false);
	    }
	    
	    // Layout (file menu)
	    file.add(file_new);
	    file.add(file_open);
	    file.add(file_close);
	    file.add(file_save);
            file.add(file_delete);
	    file.add(new JSeparator());
            //file.add(file_preferences);
            //file.add(new JSeparator());
	    file.add(file_exit);
            
	    // Edit menu
	    edit = new JMenu();
	    edit.setText(Dictionary.get("Menu.Edit"));
	    
	    edit_cut = new JMenuItem(Dictionary.get("Menu.Edit_Cut"));
	    edit_cut.addActionListener(this);
	    
	    edit_copy = new JMenuItem(Dictionary.get("Menu.Edit_Copy"));
	    edit_copy.addActionListener(this);
	    
	    edit_paste = new JMenuItem(Dictionary.get("Menu.Edit_Paste"));
	    edit_paste.addActionListener(this);
	    
	    // Layout (edit menu)
	    edit.add(edit_cut);
	    edit.add(edit_copy);
	    edit.add(edit_paste);

	
	    // Layout (menu bar)
	    this.add(file);
	    this.add(Box.createHorizontalStrut(15));
	    this.add(edit);
	    this.add(Box.createHorizontalGlue());
	    //this.add(help);
	}


	public void actionPerformed(ActionEvent event)
	{
	    Object event_source = event.getSource();

	    // File -> New
	    if (event_source == file_new) {
		new_prompt.display();
		if (!new_prompt.isCancelled()) {
		    updateCardLayout(true);
		}
 		return;
	    }

	    // File -> Open
	    if (event_source == file_open) {               
		open_prompt.display();
		if (!open_prompt.isCancelled()) {
		    updateCardLayout(true);
		}
		return;
	    }

	    // File -> Close
	    if (event_source == file_close) {
		metadata_set_model.save(true); 
		updateCardLayout(false);
		return;
	    }
              // File -> Delete
	    if (event_source == file_delete) {               
                delete_prompt.display();
		return;
	    }


	    // File -> Save
	    if (event_source == file_save) {
		metadata_set_model.save(false);
		return;
	    }        

	    // File -> Exit
	    if (event_source == file_exit) {
               	metadata_set_model.save(true); 
		if (stand_alone){
		    System.exit(0);
		}
		else {
		    self.notifyListeners();
		    self.setVisible(false);
		    return;
		}
	    }

	    /// File -> Preferences
	    // if(event_source == file_preferences){
		// GEMSPreferences GemsPreferences = new GEMSPreferences();  
            //}

	    // Edit -> Cut
	    if (event_source == edit_cut) {
		try {
		    KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
		    // Get the component with selected text as a JTextComponent
		    JTextComponent text = (JTextComponent) kfm.getPermanentFocusOwner();
		    // Cut the text to the clipboard
		    text.cut();
		}
		catch (ClassCastException cce) {
		    // If the component is not a text component ignore the cut command
		    DebugStream.println(cce.toString());
		}
		return;
	    }

	    // Edit -> Copy
	    if (event_source == edit_copy) {
		try {
		    KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
		    // Get the component with selected text as a JTextComponent
		    JTextComponent text = (JTextComponent) kfm.getPermanentFocusOwner();//getFocusOwner();
		    text.copy();
		}
		catch (Exception cce) {
		    // If the component is not a text component ignore the copy command
		    DebugStream.println(cce.toString());
		}
		return;
	    }

	    // Edit -> Paste
	    if (event_source == edit_paste) {
		try {
		    KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
		    // Get the component with selected text as a JTextComponent
		    JTextComponent text = (JTextComponent) kfm.getPermanentFocusOwner();
		    // Cut the text to the clipboard
		    text.paste();
		}
		catch (ClassCastException cce) {
		    // If the component is not a text component ignore the paste command
		    DebugStream.println(cce.toString());
		}
		return;
	    }
	  
	}
    }

}
