/*
 * This file has been developed at the University of Munich, Chair for Programming & Software Engineering.
 * 
 * This file is licensed under the Eclipse Public License (EPL) 1.0
 * 
 */
package eu.mdd4soa.trans.smm2bpel.actions;

import java.io.IOException;
import java.util.List;

import org.eclipse.bpel.apache.ode.deploy.model.dd.DocumentRoot;
import org.eclipse.bpel.apache.ode.deploy.model.dd.TDeployment;
import org.eclipse.bpel.apache.ode.deploy.model.dd.ddFactory;
import org.eclipse.bpel.apache.ode.deploy.model.dd.util.ddResourceFactoryImpl;
import org.eclipse.bpel.apache.ode.deploy.model.dd.util.ddResourceImpl;
import org.eclipse.bpel.model.resource.BPELResource;
import org.eclipse.bpel.model.resource.BPELResourceImpl;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.wst.wsdl.Definition;
import org.eclipse.wst.wsdl.util.WSDLResourceImpl;
import org.eclipse.xsd.XSDSchema;
import org.eclipse.xsd.util.XSDResourceImpl;

import eu.mdd4soa.smm.exception.InvalidSetupException;
import eu.mdd4soa.smm.exception.TransformationException;
import eu.mdd4soa.smm.statik.Participant;
import eu.mdd4soa.trans.smm2bpel.BPELImplementationPackage;
import eu.mdd4soa.trans.smm2bpel.EMFUtil;
import eu.mdd4soa.trans.smm2bpel.SMM2BPELPlugin;
import eu.mdd4soa.trans.smm2bpel.impl.SMM2BpelTransformer;

public class ConvertSMM2BpelAction implements IObjectActionDelegate {

	private IWorkbenchPart fWorkbenchPart;

	private IFile fSelectedFile;

	@Override
	public void run(IAction action) {

		try {
			if (fSelectedFile == null) {
				MessageDialog.openError(getShell(), "No File", "Attempt to run conversion without a file -- exiting");
				return;
			}

			// Get or create source folder.
			IProject project= fSelectedFile.getProject();
			IFolder bpelFolder= project.getFolder("bpel");

			if (bpelFolder == null || !bpelFolder.exists())
				bpelFolder.create(true, true, new NullProgressMonitor());

			Participant participant= EMFUtil.loadParticipant(fSelectedFile);

			convertParticipantToWS(bpelFolder, participant);

		} catch (InvalidSetupException e) {
			SMM2BPELPlugin.logError("Cannot load input SMM XMI", e);
			MessageDialog.openError(getShell(), "SMM2BPEL", "Cannot load input SMM XMI: " + e.getMessage());

		} catch (CoreException e) {
			SMM2BPELPlugin.logError("Problem accessing workspace target directory", e);
			MessageDialog.openError(getShell(), "SMM2BPEL", "Problem accessing workspace target directory: " + e.getMessage());
		} catch (TransformationException e) {
			SMM2BPELPlugin.logError("Problem transforming to BPEL", e);
			MessageDialog.openError(getShell(), "SMM2BPEL", "Problem transforming to BPEL: " + e.getMessage());
		}
	}

	public static void convertParticipantToWS(IFolder bpelFolder, Participant participant) throws TransformationException, CoreException {
		BPELImplementationPackage bpelModel= SMM2BpelTransformer.execute(participant);

		List<org.eclipse.bpel.model.Process> bpels= bpelModel.getBPELProcesses();
		for (org.eclipse.bpel.model.Process process : bpels) {

			BPELResource bpelResource= new BPELResourceImpl(URI.createFileURI(bpelFolder.getFile(process.getName() + ".bpel").getFullPath()
					.toString()));
			bpelResource.getContents().add(process);
			try {
				bpelResource.save(null);
			} catch (IOException e) {
				throw new TransformationException("Unable to write output BPEL file.", e);
			}
		}

		List<Definition> definitions= bpelModel.getWSDLDefinitions();
		for (Definition definition : definitions) {

			ResourceSet set= new ResourceSetImpl();
			WSDLResourceImpl wsdlResource= (WSDLResourceImpl) set.createResource(URI.createFileURI(bpelFolder
					.getFile(definition.getQName().getLocalPart() + ".wsdl").getFullPath().toString()));
			wsdlResource.getContents().add(definition);
			try {
				wsdlResource.save(null);
			} catch (IOException e) {
				throw new TransformationException("Unable to write output WSDL file.", e);
			}
		}

		XSDSchema schema= bpelModel.getXSDSchema();
		ResourceSet set= new ResourceSetImpl();
		XSDResourceImpl xsdResource= (XSDResourceImpl) set.createResource(URI.createFileURI(bpelFolder.getFile(participant.getName() + ".xsd")
				.getFullPath().toString()));

		xsdResource.getContents().add(schema);
		try {
			xsdResource.save(null);
		} catch (IOException e) {
			throw new TransformationException("Unable to write output XSD file.", e);
		}

		List<TDeployment> deploymentDescriptors= bpelModel.getDeploymentDescriptors();
		for (TDeployment tDeployment : deploymentDescriptors) {
			ddResourceFactoryImpl fac= new ddResourceFactoryImpl();
			ddResourceImpl ddResource= (ddResourceImpl) fac.createResource(URI.createFileURI(bpelFolder.getFile("deploy.xml").getFullPath()
					.toString()));
			ddResource.setEncoding("UTF-8");
			DocumentRoot rootElm= ddFactory.eINSTANCE.createDocumentRoot();
			rootElm.setDeploy(tDeployment);
			ddResource.getContents().add(rootElm);

			try {
				ddResource.save(null);
			} catch (IOException e) {
				throw new TransformationException("Unable to write output deploy.xml file.", e);
			}
		}

		bpelFolder.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor());
	}

	@Override
	public void setActivePart(IAction action, IWorkbenchPart targetPart) {
		fWorkbenchPart= targetPart;
	}

	@Override
	public void selectionChanged(IAction action, ISelection selection) {
		if (selection == null || ! (selection instanceof StructuredSelection) && ( ((StructuredSelection) selection).isEmpty()))
			fSelectedFile= null;
		else {
			Object element= ((StructuredSelection) selection).getFirstElement();
			if (element instanceof IFile)
				fSelectedFile= (IFile) element;
			else
				fSelectedFile= null;
		}
	}

	private Shell getShell() {
		return fWorkbenchPart.getSite().getShell();
	}

}
