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 ca.ucalgary.seahawk.util.DataFlowRecorder;
import ca.ucalgary.seahawk.util.FilterSearch;

public class WorkflowPreviewDialog extends JDialog implements ActionListener{
    public static final String PNG_GENERATOR_URL = "http://bioxml.info/authority/t2diagram.cgi";
    public static final String PNG_GENERATOR_PARAM = "workflow";
    public static final String TITLE_HINT = "Untitled workflow"; 
    public static final String DESC_HINT = "Enter a description of what the workflow does here";
    public static final String AUTHOR_HINT = "Author name?";

    private HintTextField titleField;
    private HintTextArea descArea;
    private HintTextField authorField;
    private JButton okButton;
    private JButton cancelButton;
    private WorkflowPreviewListener listener;
    private ByteArrayOutputStream byteArrayBuffer;
    private String workflowName;
    private DataFlowRecorder dataFlowRecorder;
    private Map<URL,FilterSearch> resultList;

    public WorkflowPreviewDialog(Frame owner, Map<URL,FilterSearch> resultList, DataFlowRecorder dataFlowRecorder, 
				 String workflowName, WorkflowPreviewListener wpl) throws Exception{
	super(owner, "Workflow Preview", true);

	this.workflowName = workflowName;
	this.dataFlowRecorder = dataFlowRecorder;
	this.resultList = resultList;
	String workflowTitle = workflowName;
	String workflowDescription = null;
	String workflowAuthor = null;
	byteArrayBuffer = new ByteArrayOutputStream();

	dataFlowRecorder.exportWorkflow(resultList, byteArrayBuffer, workflowName, workflowTitle, 
					workflowDescription, workflowAuthor, DataFlowRecorder.T2FLOW);

	ByteArrayOutputStream pngData = new ByteArrayOutputStream();

	URL pngGenerator = new URL(PNG_GENERATOR_URL);
	URLConnection conn = pngGenerator.openConnection(); 

	// send the workflow XML
	conn.setDoOutput(true); 
	OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream()); 
	wr.write(URLEncoder.encode(PNG_GENERATOR_PARAM, "UTF-8") + "=" + 
		 URLEncoder.encode(byteArrayBuffer.toString(), "UTF-8")); 
	wr.flush();
	
	// Get the image response 
	InputStream pngStream = conn.getInputStream(); 
	byte[] byteBufferChunk = new byte[1024];
	ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
	for(int r = pngStream.read(byteBufferChunk, 0, 1024);
	    r != -1;
	    r = pngStream.read(byteBufferChunk, 0, 1024)){
	    pngData.write(byteBufferChunk, 0, r);
	}

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

	titleField = new HintTextField(workflowTitle);
	ImageIcon drawing = new ImageIcon(pngData.toByteArray()); 
        descArea = new HintTextArea(DESC_HINT, 6, 0);
	descArea.setAutoscrolls(true);
	authorField = new HintTextField(AUTHOR_HINT);
	okButton = new JButton("Save");
	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;
	add(titleField, c);

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

	c.gridy = 2;
	add(new JLabel(drawing), c);

	c.gridy = 3;
	add(new JSeparator(SwingConstants.HORIZONTAL), c);

	c.gridy = 4;
	c.weighty = 1.0;
	add(descArea, c);

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

	listener = wpl;
	pack();
	setVisible(true);
    }

    public void actionPerformed(ActionEvent e){
	if(e.getSource() == okButton){
	    String workflowTitle = titleField.getText();
	    String workflowAuthor = authorField.getText();
	    String workflowDescription = descArea.getText();
	    if(workflowTitle.length() != 0 ||
	       workflowAuthor.length() != 0 ||
	       workflowDescription.length() != 0){
		byteArrayBuffer = new ByteArrayOutputStream();
		// recreate the workflow with the additional metadata
		try{
		    dataFlowRecorder.exportWorkflow(resultList, 
						    byteArrayBuffer, 
						    workflowName,
						    workflowTitle, 
						    workflowDescription, 
						    workflowAuthor, 
						    DataFlowRecorder.T2FLOW);
		}catch(Exception ex){
		    ex.printStackTrace();
		    JOptionPane.showMessageDialog(null, 
						  "Cannot save the Taverna workflow with the given " +
						  "metadata, will save the workflow unannotated: "+ex, 
						  "Error saving with new metadata", JOptionPane.WARNING_MESSAGE); 
		}
	    }
	    if(listener != null){
		listener.workflowConfirmed(this, byteArrayBuffer.toByteArray());
	    }
	    setVisible(false);
	    dispose();
	}
	else if(e.getSource() == cancelButton){
	    if(listener != null){
		listener.workflowCanceled(this);
	    }
	    setVisible(false);
	    dispose();
	}
    }

    // Show a hint if no value exists
    class HintTextField extends JTextField implements FocusListener {

	private final String hint;

	public HintTextField(final String hint) {
	    super(hint);
	    super.setForeground(Color.gray);
	    this.hint = hint;
	    super.addFocusListener(this);
	}
	
	@Override
	    public void focusGained(FocusEvent e) {
	    if(this.getText().isEmpty()) {
		super.setText("");
	    }
	    super.setForeground(Color.black);
	}
	@Override
	    public void focusLost(FocusEvent e) {
	    if(this.getText().isEmpty()) {
		super.setForeground(Color.gray);
		super.setText(hint);		
	    }
	}
	
	@Override
	    public String getText() {
	    String typed = super.getText();
	    return typed.equals(hint) ? "" : typed;
	}
    }

    // Show a hint if no value exists
    class HintTextArea extends JTextArea implements FocusListener {

	private final String hint;

	public HintTextArea(final String hint, int rows, int cols) {
	    super(hint, rows, cols);
	    super.setForeground(Color.gray);
	    this.hint = hint;
	    super.addFocusListener(this);
	}
	
	@Override
	    public void focusGained(FocusEvent e) {
	    if(this.getText().isEmpty()) {
		super.setText("");
	    }
	    super.setForeground(Color.black);
	}
	@Override
	    public void focusLost(FocusEvent e) {
	    if(this.getText().isEmpty()) {
		super.setForeground(Color.gray);
		super.setText(hint);		
	    }
	}
	
	@Override
	    public String getText() {
	    String typed = super.getText();
	    return typed.equals(hint) ? "" : typed;
	}
    }
}
