package ca.ucalgary.seahawk.gui;


import ca.ucalgary.seahawk.services.MobyClient;
import javax.swing.*;
import org.w3c.dom.*;
import org.biomoby.shared.*;
import org.biomoby.shared.data.*;
import org.biomoby.client.MobyRequest;
import org.biomoby.client.MobyRequestEvent;
import org.biomoby.client.MobyRequestEventHandler;

import java.lang.ref.WeakReference;
import java.awt.event.*;
import java.awt.*;
import java.io.*;
import java.text.Collator;
import java.util.*;

/**
 * The purpose of this class is to improve service interoperability "shims" by
 * checking the MOBY service listings for services that do format conversion
 * on the given data, then adds service options for the output types of those services,
 * if they aren't in the menu already. Not fully functional yet.
 */
public class MobyShimmer implements MobyRequestEventHandler{
    public static final String MOBY_SHIM_SERVICE_TYPE = "FormatConversion";

    private MobyServiceType shimServiceType;
    private MobyServicesGUI servicesGUI;
    private static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(MobyShimmer.class);

    /**
     * @throws Exception if the default shim service type cannot be found in the ontology
     */
    public MobyShimmer(MobyServicesGUI gui) throws Exception{
	this(gui, MobyServiceType.getServiceType(MOBY_SHIM_SERVICE_TYPE));
    }

    /**
     * @throws Exception if the service type is null.
     */
    public MobyShimmer(MobyServicesGUI gui, MobyServiceType serviceType) throws Exception{
	servicesGUI = gui;
	shimServiceType = serviceType;
    }

    public void addPopupOptions(MobyPrimaryData mobyData, 
				JPopupMenu popupList, 
				boolean asynchronous, 
				MobyRequestEventHandler handler){
	MobyService templateService = new MobyService();
	templateService.addInput(mobyData);
	templateService.setServiceType(shimServiceType);

	Central mobyCentral = servicesGUI.getMobyCentralImpl();
	if(mobyCentral == null){
	    logger.warn("Could not find shim services, MobyCentral was null in MobyShimmer");
	}

	MobyService[] services = null;
	try{
	    services = mobyCentral.findService(templateService);
	} catch(MobyException me){
	    logger.warn("While fetching shim services listing from MOBY Central: " +me); 
	}

	Map<MobyData[], Vector<MobyService>> outputData2Services = new TreeMap<MobyData[], Vector<MobyService>>();
	for(int i = 0; services != null && i < services.length; i++){
	    MobyData[] outParams = services[i].getPrimaryOutputs();

	    if(outParams.length == 0){
		continue;  // ignore void methods
	    }

	    if(outputData2Services.containsKey(outParams)){
		outputData2Services.get(outParams).add(services[i]);
	    }
	    else{
		Vector<MobyService> serviceVector = new Vector<MobyService>();
		serviceVector.add(services[i]);
		outputData2Services.put(outParams, serviceVector);
	    }
	}

	for(MobyData[] inParams: outputData2Services.keySet()){
	    if(inParams.length == 1 && inParams[0] != null){
      		if(!(inParams[0] instanceof MobyPrimaryData)){
		    logger.warn("Cannot create shim menu for non-MobyPrimaryData " + 
				inParams[0].getClass().getName()); 
		    continue;
		}
		MobyPrimaryData param = (MobyPrimaryData) inParams[0];
		if(param instanceof MobyPrimaryDataSimple){
		    MobyDataObject skeletonObject = new MobyDataObject("skeleton");
		    skeletonObject.setId(param.getId());
		    skeletonObject.setDataType(((MobyPrimaryDataSimple) param).getDataType());
		    MobyNamespace[] ns = ((MobyPrimaryDataSimple) param).getNamespaces();
		    if(ns != null && ns.length > 0){
			skeletonObject.addNamespace(ns[0]);
		    }
		    servicesGUI.addPopupOptions(skeletonObject, 
						popupList, 
						true, 
						this);
		}
	    }
	    else if(inParams.length > 1){
		// TO DO, deal with multiple outputs
		continue;
	    }
	    else{ // null return?
		continue;
	    }
	}
    }

    public void start(MobyRequestEvent requestEvent){
    }

    public void processEvent(MobyRequestEvent mre){
	logger.debug("Shimmer starting to process request " + mre);
	
    }

    /**
     * If a client, denotes the end of a service request.
     * If a server, denotes that the server is shutting down/this event handler should terminate.
     */
    public void stop(MobyRequest request, int requestID){
    }

}
