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.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.util.*;
import javax.swing.*;

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

public class DataImportChoiceDialog extends JDialog implements ActionListener, ListCellRenderer{

    private MobyDataObject[] dataChoices;
    private JList choiceList;
    private JButton okButton;
    private JButton cancelButton;
    private DataImportChoiceListener listener;
    private String workflowName;
    
    public static final int MAX_ITEM_DESC_WIDTH = 50;

    public DataImportChoiceDialog(Frame owner, MobyDataObject[] dataChoices, 
				  MobyDataType preferredDataType, MobyNamespace preferredNs, 
				  DataImportChoiceListener dicl){
	super(owner, "Import data as...", true);

	setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);  //user must choose ok or cancel

	this.dataChoices = dataChoices;
	listener = dicl;

	// Default select items inheriting from the preferred data type, or 
	choiceList = new JList(this.dataChoices);
	Vector<Integer> initialSelectionIndices = new Vector<Integer>();
	if(preferredDataType != null && !preferredDataType.getName().equals(MobyTags.MOBYOBJECT)){
	    for(int i = 0; i < dataChoices.length; i++){
		if(dataChoices[i].getDataType().inheritsFrom(preferredDataType)){
		    initialSelectionIndices.add(new Integer(i));
		}
	    }
	}
	else{ // base object, get things with same namespace
	    for(int i = 0; i < dataChoices.length; i++){
		MobyNamespace ns = dataChoices[i].getPrimaryNamespace();
		if(ns != null && ns.equals(preferredNs)){
		    initialSelectionIndices.add(new Integer(i));
		}
	    }
	}

	if(initialSelectionIndices.isEmpty()){
	    initialSelectionIndices.add(new Integer("0"));
	}
	int isi[] = new int[initialSelectionIndices.size()];
	int i = 0;
	for(Integer selectedIndex: initialSelectionIndices){
	    isi[i++] = selectedIndex.intValue();
	}
	choiceList.setSelectedIndices(isi);

	// Make double click import an item directly
	choiceList.addMouseListener(new DoubleClickListener(choiceList, this.dataChoices, this, listener));
	choiceList.setCellRenderer(this);  //so we can add data preview tooltips to the list items

	// todo: preselect data based on data type and namespace preferences

	okButton = new JButton("Import selected items");
	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("Select one or more items to import (Ctrl+click for multi-select)"), c);

	c.gridy = 1;
	c.weighty = 1.0;
	add(new JScrollPane(choiceList), c);

	c.gridy = 2;
	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);

	pack();
	setVisible(true);
    }

    public 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
	JLabel jlabel = new JLabel();
	String label;
	MobyDataObject item = (MobyDataObject) value;
	
	// setup useful display info for each object, including a tooltip previewing the HTML representation 
	// if the cell is in focus and the data is too long for the JLabel and need to be truncated
	MobyDataType dt = item.getDataType();
	MobyNamespace ns = item.getPrimaryNamespace();
	if(dt.getName().equals(MobyTags.MOBYOBJECT)){
	    label = "ID "+item.getId();
	}
	else{ // object of some sort
	    label = dt.getName();
	    int oldXmlMode = item.getXmlMode();
	    item.setXmlMode(MobyDataInstance.SERVICE_XML_MODE);
	    label += "<i>"+item.toXML().replaceAll("<.*?>", " ")+"</i>";  //text contents of object
	    item.setXmlMode(oldXmlMode);
	}

	label = label.trim();
	if(ns != null){
	    label += " ("+ns.getName()+")";
	}

	if(label.length() > MAX_ITEM_DESC_WIDTH+7){
	    if(cellHasFocus){
		if(dt.getName().equals(MobyTags.MOBYOBJECT)){
		    String htmlPreview = "<html>"+label.replaceAll("(.*{,100}\\s)", "$1<br>")+"</html>";
		    jlabel.setToolTipText(htmlPreview);
		}
		else{  // to preview complex object in tooltip
		    int oldXmlMode = item.getXmlMode();
		    item.setXmlMode(MobyDataInstance.SERVICE_XML_MODE);
		    String htmlPreview = "<html>"+item.toXML().replaceAll("<.*?>", " ").trim()+"</html>";
		    item.setXmlMode(oldXmlMode);
		    jlabel.setToolTipText(htmlPreview);
		}
	    }
	    label = label.substring(0, MAX_ITEM_DESC_WIDTH)+"...</i>";
	}
	jlabel.setText("<html>"+label+"</html>");

	if (isSelected) {
	    jlabel.setBackground(list.getSelectionBackground());
	    jlabel.setForeground(list.getSelectionForeground());
	} else {
	    jlabel.setBackground(list.getBackground());
	    jlabel.setForeground(list.getForeground());
	}

	jlabel.setEnabled(list.isEnabled());
	jlabel.setFont(list.getFont());
	jlabel.setOpaque(true);
	return jlabel;
    }

    public void actionPerformed(ActionEvent e){
	if(e.getSource() == okButton){
	    int[] selectedIndices = choiceList.getSelectedIndices();
	    MobyDataObject[] selectedData = new MobyDataObject[selectedIndices.length];
	    int i = 0;
	    for(int selectedIndex: selectedIndices){
		selectedData[i++] = dataChoices[selectedIndex];
	    }
	    if(listener != null){
		listener.importConfirmed(this, selectedData);
	    }
	    setVisible(false);
	    dispose();
	}
	else if(e.getSource() == cancelButton){
	    if(listener != null){
		listener.importCanceled(this);
	    }
	    setVisible(false);
	    dispose();
	}
    }

    // imports an item if double clicked, then closes the dialog
    class DoubleClickListener extends MouseAdapter {
	JList list;
	MobyDataObject[] data;
	DataImportChoiceDialog dialog;
	DataImportChoiceListener listener;

	public DoubleClickListener(JList list,
				   MobyDataObject[] data,
				   DataImportChoiceDialog dialog,
				   DataImportChoiceListener 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.length){
		    listener.importConfirmed(dialog, new MobyDataObject[]{data[index]});
		    dialog.setVisible(false);
		    dialog.dispose();
		}
	    }
	}
    }
}
