/*
 * 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.publish.uddi;

import java.util.List;
import java.util.Vector;

import org.uddi4j.UDDIException;
import org.uddi4j.client.UDDIProxy;
import org.uddi4j.datatype.Name;
import org.uddi4j.datatype.OverviewDoc;
import org.uddi4j.datatype.binding.AccessPoint;
import org.uddi4j.datatype.binding.BindingTemplate;
import org.uddi4j.datatype.binding.TModelInstanceDetails;
import org.uddi4j.datatype.business.BusinessEntity;
import org.uddi4j.datatype.service.BusinessService;
import org.uddi4j.datatype.tmodel.TModel;
import org.uddi4j.response.AuthToken;
import org.uddi4j.response.BindingDetail;
import org.uddi4j.response.BusinessDetail;
import org.uddi4j.response.BusinessInfo;
import org.uddi4j.response.BusinessInfos;
import org.uddi4j.response.ServiceDetail;
import org.uddi4j.response.ServiceInfo;
import org.uddi4j.response.ServiceInfos;
import org.uddi4j.response.TModelDetail;
import org.uddi4j.response.TModelInfos;
import org.uddi4j.transport.TransportException;
import org.uddi4j.util.CategoryBag;

/**
 * Some utility methods to encapsulate UDDI calls
 * 
 * @author tilmann
 * 
 */
public class UddiUtils {

	/**
	 * UDDIProxy used vor communication.
	 */
	private UDDIProxy uddiProxy;

	/**
	 * AuthToken for publishing services
	 */
	private AuthToken authToken;

	/**
	 * Create new UddiUtils for querying only
	 * 
	 * @param uddiProxy
	 *            the UDDIProxy to be used
	 */
	public UddiUtils(UDDIProxy uddiProxy) {
		this.uddiProxy = uddiProxy;
	}

	/**
	 * Create new UddiUtils for querying and publishing
	 * 
	 * @param uddiProxy
	 *            the UDDIProxy to be used
	 * @param authToken
	 *            the AuthToken to be used
	 */
	public UddiUtils(UDDIProxy uddiProxy, AuthToken authToken) {
		this(uddiProxy);
		this.authToken = authToken;
	}

	/**
	 * Find all businesses with a name starting with the contents of the name
	 * parameter
	 * 
	 * @param name
	 *            the beginning of the business name to be searched
	 * @param maxNumber
	 *            the maximum number of results to retrieve
	 * @return a collection containing the results
	 * @throws UDDIException
	 * @throws TransportException
	 */
	public List<BusinessInfo> findBusinesses(String name, int maxNumber)
			throws UDDIException, TransportException {
		Vector<Name> businessNames = new Vector<Name>();
		businessNames.add(new Name(name));
		BusinessInfos businessInfos = uddiProxy.find_business(businessNames,
				null, null, null, null, null, maxNumber).getBusinessInfos();
		return businessInfos.getBusinessInfoVector();
	}

	/**
	 * Find all services belonging to a business with the given key and
	 * containing all references from the given CategoryBag.
	 * 
	 * @param businessKey
	 *            the key of the business
	 * @param categoryBag
	 *            the category bag constraints
	 * @param maxNumber
	 *            the maximum number of results to retrieve
	 * @return a collection containing the results
	 * @throws UDDIException
	 * @throws TransportException
	 */
	public List<ServiceInfo> findServices(String businessKey,
			CategoryBag categoryBag, int maxNumber) throws UDDIException,
			TransportException {
		ServiceInfos serviceInfos = uddiProxy.find_service(businessKey, null,
				categoryBag, null, null, maxNumber).getServiceInfos();
		return serviceInfos.getServiceInfoVector();
	}

	/**
	 * Search for a tModel with the given name and CategoryBag
	 * 
	 * @param name
	 *            the name of the tModel
	 * @param categoryBag
	 *            the category bag constraints
	 * @return a TModel if found, null otherwise
	 * @throws UDDIException
	 * @throws TransportException
	 */
	public TModel findTModel(String name, CategoryBag categoryBag)
			throws UDDIException, TransportException {
		TModelInfos tModelInfos = uddiProxy.find_tModel(name, categoryBag,
				null, null, 1).getTModelInfos();
		if (tModelInfos.size() > 0) {
			return getTModel(tModelInfos.get(0).getTModelKey());
		} else {
			return null;
		}
	}

	/**
	 * Retrieve the TModel with the given key
	 * 
	 * @param tModelKey
	 *            the key
	 * @return the TModel
	 * @throws UDDIException
	 * @throws TransportException
	 */
	public TModel getTModel(String tModelKey) throws UDDIException,
			TransportException {
		return (TModel) uddiProxy.get_tModelDetail(tModelKey).getTModelVector()
				.get(0);
	}

	/**
	 * Retrieve the BusinessEntity with the given key
	 * 
	 * @param businessKey
	 *            the key
	 * @return the BusinessEntity
	 * @throws UDDIException
	 * @throws TransportException
	 */
	public BusinessEntity getBusinessEntity(String businessKey)
			throws UDDIException, TransportException {
		return (BusinessEntity) uddiProxy.get_businessDetail(businessKey)
				.getBusinessEntityVector().get(0);
	}

	/**
	 * Retrieve the BusinessService with the given key
	 * 
	 * @param serviceKey
	 *            the key
	 * @return the BusinessService
	 * @throws UDDIException
	 * @throws TransportException
	 */
	public BusinessService getBusinessService(String serviceKey)
			throws UDDIException, TransportException {
		return (BusinessService) uddiProxy.get_serviceDetail(serviceKey)
				.getBusinessServiceVector().get(0);
	}

	/**
	 * Publish the business with given name and description and return it. If a
	 * business with the given name can be found, don't publish anything. Return
	 * the found business instead.
	 * 
	 * @param name
	 *            the name of the business
	 * @param description
	 *            the description of the business
	 * @return the published/found business
	 * @throws TransportException
	 * @throws UDDIException
	 */
	public BusinessEntity publishBusiness(String name, String description)
			throws TransportException, UDDIException {

		List<BusinessInfo> businessInfos = findBusinesses(name, 1);

		if (businessInfos.size() > 0) {
			return getBusinessEntity(businessInfos.get(0).getBusinessKey());

		} else {
			BusinessEntity business = new BusinessEntity();
			business.setDefaultName(new Name(name));
			business.setDefaultDescriptionString(description);

			Vector<BusinessEntity> businesses = new Vector<BusinessEntity>();
			businesses.add(business);

			BusinessDetail businessDetail = uddiProxy.save_business(authToken
					.getAuthInfoString(), businesses);

			return (BusinessEntity) businessDetail.getBusinessEntityVector()
					.get(0);
		}
	}

	/**
	 * Publish the tModel with given name, description overview URL and category
	 * bag and return it. If a tModel with the given name and category bag can
	 * be found, don't publish anything. Return the found tModel instead.
	 * 
	 * @param name
	 *            the name of the tModel
	 * @param description
	 *            the description of the tModel
	 * @param overviewUrl
	 *            the overview URL of the tModel
	 * @param categoryBag
	 *            the category bag of the tModel
	 * @return the published/found tModel
	 * @throws UDDIException
	 * @throws TransportException
	 */
	public TModel publishTModel(String name, String description,
			String overviewUrl, CategoryBag categoryBag) throws UDDIException,
			TransportException {

		TModel tModel = findTModel(name, categoryBag);
		if (tModel != null)
			return tModel;
		else {
			tModel = new TModel();
			tModel.setName(name);
			tModel.setDefaultDescriptionString(description);
			tModel.setCategoryBag(categoryBag);
			OverviewDoc oDoc = new OverviewDoc();
			oDoc.setOverviewURL(overviewUrl);
			tModel.setOverviewDoc(oDoc);

			Vector<TModel> tModels = new Vector<TModel>();
			tModels.add(tModel);
			TModelDetail tModelDetail = uddiProxy.save_tModel(authToken
					.getAuthInfoString(), tModels);

			return (TModel) tModelDetail.getTModelVector().get(0);
		}
	}

	/**
	 * Publish a new BindingTemplate with the given parameters.
	 * 
	 * @param accessPoint
	 *            the AccessPoint of the BindingTemplate
	 * @param serviceKey
	 *            the key of the service
	 * @param tModelInstanceDetails
	 *            the TModelInstanceDetails
	 * @return the newly published BindingTemplate
	 * @throws TransportException
	 * @throws UDDIException
	 */
	public BindingTemplate publishBindingTemplate(AccessPoint accessPoint,
			String serviceKey, TModelInstanceDetails tModelInstanceDetails)
			throws TransportException, UDDIException {

		BindingTemplate bindingTemplate = new BindingTemplate();

		bindingTemplate.setServiceKey(serviceKey);
		bindingTemplate.setAccessPoint(accessPoint);

		bindingTemplate.setTModelInstanceDetails(tModelInstanceDetails);

		Vector<BindingTemplate> bindingTemplates = new Vector<BindingTemplate>();
		bindingTemplates.add(bindingTemplate);

		BindingDetail bindingDetail = uddiProxy.save_binding(authToken
				.getAuthInfoString(), bindingTemplates);

		return (BindingTemplate) bindingDetail.getBindingTemplateVector()
				.get(0);
	}

	/**
	 * Publish a new BusinessService with the given parameters
	 * 
	 * @param name
	 *            the name of the service
	 * @param description
	 *            the description of the service
	 * @param businessKey
	 *            the key of the business
	 * @param categoryBag
	 *            the CategoryBag of the service
	 * @return the newly published BusinessService
	 * @throws TransportException
	 * @throws UDDIException
	 */
	public BusinessService publishService(String name, String description,
			String businessKey, CategoryBag categoryBag)
			throws TransportException, UDDIException {

		BusinessService businessService = new BusinessService();
		businessService.setDefaultName(new Name(name));
		businessService.setDefaultDescriptionString(description);
		businessService.setBusinessKey(businessKey);

		businessService.setCategoryBag(categoryBag);

		Vector<BusinessService> businessServices = new Vector<BusinessService>();
		businessServices.add(businessService);

		ServiceDetail serviceDetail = uddiProxy.save_service(authToken
				.getAuthInfoString(), businessServices);

		return (BusinessService) serviceDetail.getBusinessServiceVector()
				.get(0);
	}

	public AuthToken getAuthToken() {
		return authToken;
	}

	public void setAuthToken(AuthToken authToken) {
		this.authToken = authToken;
	}

}
