package ca.ucalgary.seahawk.gui;

/**
 * Generates a preview of a Taverna2 workflow and shows it in a dialog where
 * metadata such as title, author, and description can be entered.
 *
 * Renders the workflow using a remote CGI and asks the user if they want to 
 * proceed with the export of the workflow.
 */

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.regex.*;
import javax.swing.*;
import javax.swing.event.*;

import org.biomoby.shared.*;
import org.biomoby.shared.data.*;
import org.biomoby.shared.parser.MobyTags;

public class ServiceSearchDialog extends JDialog implements ActionListener, ListCellRenderer, DocumentListener{

    private List<JMenuItem> serviceChoices;
    private DefaultListModel activeChoices;
    private JTextField searchField;
    private JList choiceList;
    private JButton okButton;
    private JButton cancelButton;
    private ServiceChoiceListener listener;
    
    public static final int MAX_ITEM_DESC_WIDTH = 50;

    public ServiceSearchDialog(java.awt.Frame owner,
			       String actionText,
			       ServiceChoiceListener scl){
	super(owner, "Select service to run (mouse over for details)", true);

	serviceChoices = new Vector<JMenuItem>();
	activeChoices = new DefaultListModel();
	listener = scl;

	searchField = new JTextField(40);
	searchField.setToolTipText("Enter a text string or regular expression the service name or description must match");
	searchField.getDocument().addDocumentListener(this);

	choiceList = new JList(activeChoices);
	// Make double click import an item directly
	choiceList.addMouseListener(new DoubleClickListener(choiceList, activeChoices, this, listener));
	choiceList.setCellRenderer(this);
	
	okButton = new JButton(actionText);
	okButton.addActionListener(this);
	cancelButton = new JButton("Cancel");
	cancelButton.addActionListener(this);

	setLayout(new GridBagLayout());
	GridBagConstraints c = new GridBagConstraints();

	c.weightx = 1;
	c.fill = GridBagConstraints.HORIZONTAL;
       	c.gridx = 0;
	c.gridwidth = 2;

	c.gridy = 0;
	c.weighty = 0;
	add(new JLabel("Find services matching keyword:"), c);

	c.gridy = 1;
	add(searchField, c);

	c.gridy = 2;
	c.weighty = 1.0;
	JScrollPane scrollPane = new JScrollPane(choiceList);
	//scrollPane.setPreferredSize(400, 400);
	add(scrollPane, c);

	c.gridy = 3;
	c.weighty = 0;
	c.weightx = 0.5;
	c.gridwidth = 1; // two buttons on one line
	c.anchor = GridBagConstraints.PAGE_END;
	add(okButton, c);
	c.gridx = 1;
	add(cancelButton, c);
    }

    public void addOption(JMenuItem serviceMenuItem, boolean refreshUI){
	serviceChoices.add(serviceMenuItem);
	if(refreshUI){
	    updateActiveChoices(searchField.getText());
	}
    }

    public void initializeList(){
	updateActiveChoices(searchField.getText());
    }

    public void setVisible(boolean visible){
	if(visible){
	    updateActiveChoices(searchField.getText()); // so list displayed on first load
	}
	super.setVisible(visible);
    }

    /**
     * Called when the regex has been changed by the user
     */
    public void changedUpdate(DocumentEvent e){
	updateActiveChoices(searchField.getText());
    }

    public void insertUpdate(DocumentEvent e){
	updateActiveChoices(searchField.getText());
    }

    public void removeUpdate(DocumentEvent e){
	updateActiveChoices(searchField.getText());
    }

    // Set the GUI choice list based on the current regex matching the service name or description
    private void updateActiveChoices(String searchTerm){
	Pattern searchPattern = Pattern.compile(searchTerm == null ? "" : searchTerm, 
						Pattern.DOTALL | Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
	activeChoices.clear();
	for(JMenuItem serviceChoice: serviceChoices){
	    if(serviceChoice.getText() == null){
		continue;
	    }
	    
	    String label = serviceChoice.getText().replaceAll("<.*?>", "").replaceAll("see description", "");
	    // get rid of any coloring

	    // Anything's okay??
	    if(searchTerm == null || searchTerm.trim().length() == 0){
		serviceChoice.setText(label);
		activeChoices.addElement(serviceChoice);
		continue;
	    }
	    Matcher matcher = searchPattern.matcher(label);
	    // In the label?
	    if(matcher.find()){
		label = label.substring(0, matcher.start())+"<font color='red'>" +
		    matcher.group(0) + "</font>" +
		    (matcher.end() >= label.length() ? "" : label.substring(matcher.end()));
		serviceChoice.setText("<html>" + label + "</html>");
		activeChoices.addElement(serviceChoice);
	    }
	    // In the tooltip?
	    else if(serviceChoice.getToolTipText() != null && 
		    searchPattern.matcher(serviceChoice.getToolTipText()).find()){
		serviceChoice.setText("<html>"+label+" <font color='red'><i>see description</i></font></html>");
		activeChoices.addElement(serviceChoice);
	    }
	    else{
		serviceChoice.setText(label);  //no match, do not add to choice list
	    }
	}
    }

    public java.awt.Component getListCellRendererComponent(JList list,              // the list
							   Object value,            // the MobyDataObject
							   int index,               // cell index
							   boolean isSelected,      // is the cell selected
							   boolean cellHasFocus){   // does the cell have focus
	JMenuItem item = (JMenuItem) value;
	
	if (isSelected) {
	    item.setBackground(list.getSelectionBackground());
	    item.setForeground(list.getSelectionForeground());
	} else {
	    item.setBackground(list.getBackground());
	    item.setForeground(list.getForeground());
	}

	return item;
    }

    public void actionPerformed(ActionEvent e){
	if(e.getSource() == okButton){
	    int[] selectedIndices = choiceList.getSelectedIndices();
	    if(listener != null){
		listener.serviceSelected(this, (JMenuItem) choiceList.getSelectedValue());
	    }
	    setVisible(false);
	    dispose();
	}
	else if(e.getSource() == cancelButton){
	    if(listener != null){
		listener.selectionCanceled(this);
	    }
	    setVisible(false);
	    dispose();
	}
    }

    // imports an item if double clicked, then closes the dialog
    class DoubleClickListener extends MouseAdapter {
	JList list;
	DefaultListModel data;
	ServiceSearchDialog dialog;
	ServiceChoiceListener listener;

	public DoubleClickListener(JList list,
				   DefaultListModel data,
				   ServiceSearchDialog dialog,
				   ServiceChoiceListener listener){
	    this.list = list;
	    this.data = data;
	    this.dialog = dialog;
	    this.listener = listener;
	}

	public void mouseClicked(MouseEvent e) {
	    if (listener != null && e.getClickCount() == 2) {
		int index = list.locationToIndex(e.getPoint());
		if(index >= 0 && index < data.size()){
		    listener.serviceSelected(dialog, (JMenuItem) data.get(index));
		    dialog.setVisible(false);
		    dialog.dispose();
		}
	    }
	}
    }
}
