// ICISPedigreeTree.java
//
// Created: February 2006
//
// This file is a component of the BioMoby project.
// Copyright Martin Senger (martin.senger@gmail.com).
//

package org.biomoby.service.dashboard.renderers;

import org.biomoby.shared.MobyException;
import org.biomoby.shared.parser.MobyPackage;
import org.biomoby.shared.datatypes.MobyObject;
import org.biomoby.service.dashboard.data.DataContainer;
import org.biomoby.service.dashboard.DashboardProperties;
import org.biomoby.service.dashboard.PropertyChannel;
import org.biomoby.service.dashboard.SwingWorker;
import org.biomoby.service.dashboard.ServiceCallerModel;

import org.tulsoft.tools.loaders.ICreator;
import org.tulsoft.shared.GException;

import org.cgiar.icis.pedigree.PedigreeTreeComponent;
import org.cgiar.icis.pedigree.PedigreeTreeNodeObject;

import javax.swing.event.TreeSelectionEvent;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.JComponent;

import java.io.File;

/**
 * This is a very specific viewer (it understands just one specific
 * Biomoby type - <tt>GCP_GermplasmPedigreeTree</tt>). I have included
 * here, however, because it shows how a viewer can further ask for
 * additional data using the same Biomoby service that created the
 * initial data for this viewer. <p>
 *
 * @author <A HREF="mailto:martin.senger@gmail.com">Martin Senger</A>
 * @version $Id: ICISPedigreeTree.java,v 1.2 2006/02/20 05:51:11 senger Exp $
 */

public class ICISPedigreeTree
    extends AbstractMobyRenderer {

    private static org.apache.commons.logging.Log log =
	org.apache.commons.logging.LogFactory.getLog (ICISPedigreeTree.class);

    /*********************************************************************
     *
     ********************************************************************/
    public ICISPedigreeTree() {
        super ("Pedigree Tree", "images/tree.gif");
    }

    /*********************************************************************
     *
     ********************************************************************/
    public boolean canHandle (String criterion, Object value) {

	return (
		criterion.equals (MOBY_TYPE) &&
		isSubclassOfKnown (value.toString())
		);
    }

    /*********************************************************************
     *
     ********************************************************************/
    public JComponent getComponent (DataContainer data)
	throws MobyException {

	// deal with collections
        if (data.getData().getClass().isArray())
	    return new TabCollectionRenderer (this).getComponent (data);

	// the real job
	try {
	    String xmlPedigree = traverseToString (data.getData());

	    try {
		MobyPedigreeTree treeComp = new MobyPedigreeTree (data);
		treeComp.updatePedigreeTree (null, 0, xmlPedigree);
		return treeComp;

	    } catch (Exception e2) {
		throw new MobyException ("Cannot create a pedigree tree.", e2);
	    }

	} catch (Error e) {
	    throw new MobyException
		("Problem in renderer '" + getName() + "'.", e);
	}
    }

    /**************************************************************************
     * Does not provide any file saving facility.
     **************************************************************************/
    public boolean save2File (DataContainer data, File file)
	throws MobyException {
	return false;
    }



    class MobyPedigreeTree
	extends PedigreeTreeComponent {

	DataContainer initData;  // this is here because of metadata

	public MobyPedigreeTree (DataContainer data)
	    throws Exception {
	    super (350);   // width
	    initData = data;
	}

	public void valueChanged(final TreeSelectionEvent evt) {
	    if (evt.getSource() == this.pedigreeTree) {
		DefaultMutableTreeNode node =
		    (DefaultMutableTreeNode)this.pedigreeTree.getLastSelectedPathComponent();
		if (node != null) {
		    Object userNode = node.getUserObject();
		    if (userNode == null)
			return;
		    if (! (userNode instanceof PedigreeTreeNodeObject) ) {
			log.error ("Found '" + userNode.toString() + "' (of type: " +
				   userNode.getClass().getName() +
				   ") instead of a PedigreeTreeNodeObject.");
			return;
		    }
		    PedigreeTreeNodeObject treeNode = (PedigreeTreeNodeObject)userNode;
		    if (treeNode.getName() != null) {
			// a tree node is selected. If it's a leaf node, attempt to get
			// progenitors, if any, and update the pedigree tree
			if (node.isLeaf()) {
			    MyCaller runWorker =
				new MyCaller (treeNode.getPropertyValue ("icis:gid"),
					      (PropertyChannel)initData.getMetadata(),
					      node
					      );
			    runWorker.start(); 
			}
			updateGermplasmItemInfo (treeNode);
		    }
		}
	    }
	}

	/**************************************************************************
	 *
	 * A worker that calls the service...
	 *
	 **************************************************************************/
	class MyCaller
	    extends SwingWorker {
	    
	    MobyException exception = null;
	    DataContainer data = new DataContainer();
	    String gid;
	    PropertyChannel propertyChannel;
	    DefaultMutableTreeNode node;
	    
	    public MyCaller (String gid,
			     PropertyChannel propertyChannel,
			     DefaultMutableTreeNode node) {
		super();
		this.gid = gid;
		this.propertyChannel = propertyChannel;
		this.node = node;
	    }
	    
	    public Object construct() {
		try {
		    propertyChannel.fire (DashboardProperties.DP_STATUS_MSG,
					  "Calling service to update pedigree tree...");
		    
		    // create a data container with input data...
		    MobyObject mInp = (MobyObject)ICreator.createInstance
			("org.biomoby.shared.datatypes.GCP_GermplasmId");
		    mInp.setId (gid);
		    MobyPackage moby = new MobyPackage (mInp, "germplasm_id");
		    data.setData (moby.toXML());
		    
		    // call the service
		    ServiceCallerModel callerModel = new ServiceCallerModel();
		    callerModel.setPropertyChannel (propertyChannel);
		    callerModel.runIt (data);
		    
		} catch (MobyException e) {
		    exception = e;
		    
		} catch (GException e) {
		    exception = new MobyException ("Problem updating pedigree tree.", e);
		    
		} catch (Error e) {
		    exception = new MobyException ("Problem updating pedigree tree.", e);
		}
		return null;  // not used here
	    }
	    
	    // runs on the event-dispatching thread
	    public void finished() {
		
		if (exception == null) {
		    propertyChannel.fire (DashboardProperties.DP_STATUS_MSG,
					  "Service invocation finished.");
		    try {
 			MobyPackage response = MobyPackage.createFromXML (data.getData());
			String xml = traverseToString (response.getJob(0).getData());
			PedigreeTreeNodeObject treeNode =
			    (PedigreeTreeNodeObject)node.getUserObject();
			updatePedigreeTree (node, 0, xml);
			updateGermplasmItemInfo (treeNode);
		    } catch (Exception e2) {
			log.error ("Unable to update pedigree tree: " + e2.toString());
		    }
		} else {
		    propertyChannel.fire (DashboardProperties.DP_STATUS_MSG,
					  "Service invocation failed (see the log file).");
		    log.error ("Unable to update pedigree tree: " + exception.toString());
		}
	    }
	}
    }
}
