/*
 * This source code is made available under the terms of the
 * Common Public License Version 1.0 distibuted along with the
 * source code package.
 */
package de.uka.cmtm.serviceregistry;

import java.util.Collection;

import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbenchPage;

import de.uka.cmtm.serviceregistry.plugin.editors.SearchResultsEditorInput;
import de.uka.cmtm.serviceregistry.publish.uddi.WsdlPublisher;
import de.uka.cmtm.serviceregistry.publish.uddi.WsdlPublisherFactory;
import de.uka.cmtm.serviceregistry.query.ClassNotFoundEvent;
import de.uka.cmtm.serviceregistry.query.ServiceInfo;
import de.uka.cmtm.serviceregistry.query.ServiceLocator;
import de.uka.cmtm.serviceregistry.query.ServiceLocatorEventListener;
import de.uka.cmtm.serviceregistry.query.ServiceLocatorFactory;
import de.uka.cmtm.serviceregistry.query.ServiceParameter;

/**
 * This class represents the controller part of the service registry pugin
 * 
 * @author tilmann
 */
public class RegistryController implements ServiceLocatorEventListener {

	private ServiceLocator serviceLocator;

	private WsdlPublisher wsdlPublisher;

	private IWorkbenchPage workbenchPage;

	private Shell shell;

	private ServiceLocatorFactory serviceLocatorFactory = new ServiceLocatorFactory();

	private WsdlPublisherFactory wsdlPublisherFactory = new WsdlPublisherFactory();

	private String invalidClassNames;

	public RegistryController(IWorkbenchPage workbenchPage, Shell shell) {
		this.workbenchPage = workbenchPage;
		this.shell = shell;
	}

	/**
	 * Sets the resouce configuration parameters.
	 * 
	 * @return if the update succeeded
	 */
	public void updateConfiguration(String digReasonerUrl,
			String serviceOntologyUrl, String upperOntologyUrl,
			String topOntologyUrl, String uddiInquiryUrl,
			String uddiPublishUrl, String uddiUserName, String uddiPassword) {

		if (serviceLocator != null)
			serviceLocator.removeServiceLocatorEventListener(this);
		serviceLocator = null;
		serviceLocatorFactory.setDigReasonerUrl(digReasonerUrl);
		serviceLocatorFactory.setServiceOntologyUrl(serviceOntologyUrl);
		serviceLocatorFactory.setUpperServiceOntologyUrl(upperOntologyUrl);
		serviceLocatorFactory.setTopOntologyUrl(topOntologyUrl);
		serviceLocatorFactory.setUddiInquiryUrl(uddiInquiryUrl);

		wsdlPublisher = null;
		wsdlPublisherFactory.setSaWsdlPublishingCapable(true);
		wsdlPublisherFactory.setUpperServiceOntologyUrl(upperOntologyUrl);
		wsdlPublisherFactory.setUddiInquiryUrl(uddiInquiryUrl);
		wsdlPublisherFactory.setUddiPublishUrl(uddiPublishUrl);
		wsdlPublisherFactory.setUddiUser(uddiUserName);
		wsdlPublisherFactory.setUddiPassword(uddiPassword);
	}

	/**
	 * Publish all services defined in the WSDL identified by the given URL.
	 * Search for a business with the given name to publish the services for. If
	 * none can be found publish a new business with given name and description.
	 * 
	 * @param wsdlUrl
	 *            the URL of the WSDL file
	 * @param businessName
	 *            the name of the business to search for
	 */
	public void publishWsdl(String wsdlUrl, String businessName) {

		if (wsdlPublisher == null) {
			try {
				wsdlPublisher = wsdlPublisherFactory.createWsdlPublisher();
			} catch (InstantiationException e) {
				displayErrorMsg("Problem while creating wsdl publisher.", e);
			}
		}

		if (wsdlPublisher != null)
			try {
				wsdlPublisher.publishWsdl(wsdlUrl, businessName, null);

				MessageDialog.openInformation(shell, "Success",
						"WSDL published successfully.");

			} catch (Exception e) {
				displayErrorMsg("Problem while publishing.", e);
			}
	}

	/**
	 * This method can be used to search for services suitable to the given
	 * searchParameters. The resulting list may also contain services that do
	 * not perfectly match the parameters. This is indicated with a relevance
	 * below 1.
	 * 
	 * @param searchParameter
	 *            the parameters the services shoud have
	 * @return a list of search results sorted by relevance
	 */
	public void findServices(ServiceParameter searchParameter) {
		if (serviceLocator == null) {
			try {
				serviceLocator = serviceLocatorFactory.createServiceLocator();
			} catch (InstantiationException e) {
				displayErrorMsg("Problem while creating service locator.", e);
			}
			serviceLocator.addServiceLocatorEventListener(this);
		}

		if (serviceLocator != null)
			try {
				invalidClassNames = null;
				Collection<ServiceInfo> results = serviceLocator
						.findServices(searchParameter);
				if (invalidClassNames != null) {
					MessageDialog
							.openInformation(
									shell,
									"Class not found.",
									"The classes "
											+ invalidClassNames
											+ " could not be found in the ontology and have been ignored during search.");
				}

				workbenchPage
						.openEditor(new SearchResultsEditorInput(results),
								"de.uka.cmtm.serviceregistry.plugin.editors.SearchResultsEditor");
			} catch (Exception e) {
				displayErrorMsg("Problem while querrying.", e);
			}
	}

	/**
	 * @return the shell
	 */
	public Shell getShell() {
		return shell;
	}

	/**
	 * @param shell
	 *            the shell to set
	 */
	public void setShell(Shell shell) {
		this.shell = shell;
	}

	/**
	 * @return the workbenchPage
	 */
	public IWorkbenchPage getWorkbenchPage() {
		return workbenchPage;
	}

	/**
	 * @param workbenchPage
	 *            the workbenchPage to set
	 */
	public void setWorkbenchPage(IWorkbenchPage workbenchPage) {
		this.workbenchPage = workbenchPage;
	}

	/**
	 * Comupte the root cause of the given Throwable
	 * 
	 * @param t
	 *            the Throwable
	 * @return the root cause
	 */
	private Throwable getCause(Throwable t) {
		while (t.getCause() != null)
			t = t.getCause();
		return t;
	}

	private void displayErrorMsg(String msg, Throwable t) {
		Platform.getPlugin("de.uka.cmtm.serviceregistry").getLog().log(
				new Status(Status.ERROR, "de.uka.cmtm.serviceregistry", 1, msg,
						t));
		Throwable cause = getCause(t);
		String exMsg = cause.getMessage();
		if (cause instanceof NullPointerException) {
			exMsg = "A NullPointerException occured.";
		}
		MessageDialog.openError(shell, msg, exMsg);
	}

	public void classNotFound(ClassNotFoundEvent e) {

		if (invalidClassNames == null) {
			invalidClassNames = e.getClassName();
		} else {
			invalidClassNames += ", " + e.getClassName();
		}
	}

}
