/*******************************************************************************
 * Copyright (c) 2007 Intel Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Vitaly Tishkov, Intel - Initial API and Implementation
 *
 *******************************************************************************/ 

package org.eclipse.bpel.ui;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.eclipse.bpel.common.extension.model.ExtensionMap;
import org.eclipse.bpel.common.ui.editmodel.IEditModelListener;
import org.eclipse.bpel.common.ui.editmodel.ResourceInfo;
import org.eclipse.bpel.model.Activity;
import org.eclipse.bpel.model.CorrelationSet;
import org.eclipse.bpel.model.ExtensibleElement;
import org.eclipse.bpel.model.MessageExchange;
import org.eclipse.bpel.model.PartnerLink;
import org.eclipse.bpel.model.Process;
import org.eclipse.bpel.model.Variable;
import org.eclipse.bpel.model.util.BPELUtils;
import org.eclipse.bpel.ui.adapters.AdapterNotification;
import org.eclipse.bpel.ui.editparts.ProcessTrayEditPart;
import org.eclipse.bpel.ui.editparts.util.OutlineTreePartFactory;
import org.eclipse.bpel.ui.properties.BPELPropertySection;
import org.eclipse.bpel.ui.uiextensionmodel.StartNode;
import org.eclipse.bpel.ui.util.BPELEditModelClient;
import org.eclipse.bpel.ui.util.BPELEditorUtil;
import org.eclipse.bpel.ui.util.BPELReader;
import org.eclipse.bpel.ui.util.ModelHelper;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IMarkerDelta;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.draw2d.LightweightSystem;
import org.eclipse.draw2d.Viewport;
import org.eclipse.draw2d.parts.ScrollableThumbnail;
import org.eclipse.draw2d.parts.Thumbnail;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.impl.NotificationImpl;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.gef.ContextMenuProvider;
import org.eclipse.gef.DefaultEditDomain;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPartViewer;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.LayerConstants;
import org.eclipse.gef.RootEditPart;
import org.eclipse.gef.commands.CommandStack;
import org.eclipse.gef.ui.actions.ActionRegistry;
import org.eclipse.gef.ui.parts.ContentOutlinePage;
import org.eclipse.gef.ui.parts.TreeViewer;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.viewers.IPostSelectionProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.ide.FileStoreEditorInput;
import org.eclipse.ui.ide.IGotoMarker;
import org.eclipse.ui.internal.views.properties.tabbed.view.TabDescriptor;
import org.eclipse.ui.internal.views.properties.tabbed.view.TabbedPropertyViewer;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.part.IPageSite;
import org.eclipse.ui.part.MultiPageEditorPart;
import org.eclipse.ui.part.PageBook;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
import org.eclipse.ui.views.properties.IPropertySheetPage;
import org.eclipse.ui.views.properties.tabbed.ISection;
import org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor;
import org.eclipse.ui.views.properties.tabbed.TabContents;
import org.eclipse.wst.sse.core.StructuredModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
import org.eclipse.wst.sse.ui.StructuredTextEditor;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

public class BPELMultipageEditorPart extends MultiPageEditorPart
implements IEditModelListener,
IGotoMarker/*, CommandStackListener*/ {

	class OutlinePage extends ContentOutlinePage {
		private PageBook pageBook;
		private Control outline;
		private Canvas overview;
		private IAction showOutlineAction, showOverviewAction;
		static final int ID_OUTLINE  = 0;
		static final int ID_OVERVIEW = 1;
		private Thumbnail thumbnail;

		public OutlinePage(EditPartViewer viewer) {
			super(viewer);
		}

		// increase visibility.
		@Override
		public EditPartViewer getViewer() {
			return super.getViewer();
		}

		private void configureOutlineViewer() {
			getViewer().setEditDomain(getEditDomain());
			getViewer().setEditPartFactory(new OutlineTreePartFactory());

			BPELMultipageEditorPart.this.fDesignViewer.registerViewer(getViewer());

			//FIXME should we add the same for src tab?
			ContextMenuProvider provider = new ProcessContextMenuProvider(getDesignEditor(), BPELMultipageEditorPart.this.fDesignViewer.getActionRegistry());

			getViewer().setContextMenu(provider);
			getSite().registerContextMenu("org.eclipse.bpel.outline.contextmenu", //$NON-NLS-1$
					provider,
					getSite().getSelectionProvider());
			getViewer().setKeyHandler(BPELMultipageEditorPart.this.fDesignViewer.getKeyHandler());
			// TODO: Drag and drop support goes here
			// getViewer().addDropTargetListener(new BPELTemplateTransferDropTargetListener(getViewer()));
			IToolBarManager tbm = getSite().getActionBars().getToolBarManager();
			this.showOutlineAction = new Action() {
				@Override
				public void run() {
					showPage(ID_OUTLINE);
				}

				@Override
				public String getToolTipText() {
					return Messages.OutlinePage_showOutlineView;
				}
			};
			this.showOutlineAction.setImageDescriptor(BPELUIPlugin.INSTANCE.getImageDescriptor(IBPELUIConstants.ICON_OUTLINE_16));
			tbm.add(this.showOutlineAction);
			this.showOverviewAction = new Action() {
				@Override
				public void run() {
					showPage(ID_OVERVIEW);
				}

				@Override
				public String getToolTipText() {
					return Messages.OutlinePage_showOverviewView;
				}
			};
			this.showOverviewAction.setImageDescriptor(BPELUIPlugin.INSTANCE.getImageDescriptor(IBPELUIConstants.ICON_OVERVIEW_16));
			tbm.add(this.showOverviewAction);
			showPage(ID_OUTLINE);
		}

		@Override
		public Control getControl() {
			return this.pageBook;
		}

		@Override
		public void createControl(Composite parent) {
			this.pageBook = new PageBook(parent, SWT.NONE);
			this.outline = getViewer().createControl(this.pageBook);
			this.overview = new Canvas(this.pageBook, SWT.NONE);
			this.pageBook.showPage(this.outline);
			configureOutlineViewer();
			// TODO: Add to the adapting selection provider
			//getSelectionSynchronizer().addViewer(getViewer());

			getViewer().setContents(getProcess());
		}

		private void initializeOverview() {
			LightweightSystem lws = new LightweightSystem(this.overview);
			RootEditPart rep = BPELMultipageEditorPart.this.fDesignViewer.getGraphicalViewer().getRootEditPart();
			if (rep instanceof GraphicalBPELRootEditPart) {
				GraphicalBPELRootEditPart root = (GraphicalBPELRootEditPart)rep;
				this.thumbnail = new ScrollableThumbnail((Viewport)root.getFigure());
				this.thumbnail.setSource(root.getLayer(LayerConstants.PRINTABLE_LAYERS));
				lws.setContents(this.thumbnail);
			}
		}

		private void showPage(int id) {
			if (id == ID_OUTLINE) {
				this.showOutlineAction.setChecked(true);
				this.showOverviewAction.setChecked(false);
				this.pageBook.showPage(this.outline);
				if (this.thumbnail != null)
					this.thumbnail.setVisible(false);
			} else if (id == ID_OVERVIEW) {
				initializeOverview();
				this.showOutlineAction.setChecked(false);
				this.showOverviewAction.setChecked(true);
				this.pageBook.showPage(this.overview);
				this.thumbnail.setVisible(true);
			}
		}

		@Override
		public void dispose() {
			super.dispose();
		}

		@Override
		public void init(IPageSite pageSite) {
			super.init(pageSite);
			//should ActionRegistry be here too?
			ActionRegistry registry = BPELMultipageEditorPart.this.fDesignViewer.getActionRegistry();
			IActionBars bars = pageSite.getActionBars();
			String id = ActionFactory.UNDO.getId();
			bars.setGlobalActionHandler(id, registry.getAction(id));
			id = ActionFactory.REDO.getId();
			bars.setGlobalActionHandler(id, registry.getAction(id));
			id = ActionFactory.DELETE.getId();
			bars.setGlobalActionHandler(id, registry.getAction(id));
			id = ActionFactory.REVERT.getId();
			bars.setGlobalActionHandler(id, registry.getAction(id));
			bars.updateActionBars();
		}
	}

	protected class TextEditorSelectionListener implements ISelectionChangedListener {
		public void selectionChanged(SelectionChangedEvent event) {
			if (getActivePage() != DESIGN_PAGE_INDEX) {
				ISelection selection = event.getSelection();
				if (selection instanceof IStructuredSelection) {
					List<Object> selections = new ArrayList<Object>();
					for (Iterator<Object> i = ((IStructuredSelection) selection).iterator(); i.hasNext();) {
						Object domNode = i.next();
						if (domNode instanceof Element) {
							Object facade = BPELEditorUtil.getInstance().findModelObjectForElement(BPELMultipageEditorPart.this.process, (Element)domNode);
							if (facade != null) {
								selections.add(facade);
							}
						}
					}

					if (!selections.isEmpty()) {
						StructuredSelection bpelSelection = new StructuredSelection(selections);
						BPELMultipageEditorPart.this.fDesignViewer.getAdaptingSelectionProvider().setSelection(bpelSelection);
					}
				}
			}
		}
	}

	protected class DesignViewerSelectionListener implements ISelectionChangedListener {
		public void selectionChanged(SelectionChangedEvent event) {
			//force selection update if only source page is not active
			if (getActivePage() != SOURCE_PAGE_INDEX) {
				try {
					ISelection sel = BPELMultipageEditorPart.this.fDesignViewer.getSelection();
					Object selectedNode = ((IStructuredSelection)sel).getFirstElement();
					Element selectedNodeElement = null;

					if (selectedNode instanceof StartNode) {
						selectedNodeElement = ((StartNode)selectedNode).getProcess().getElement();
					} else if (selectedNode instanceof ExtensibleElement) {
						selectedNodeElement = ((ExtensibleElement)selectedNode).getElement();
					}

					if (selectedNodeElement != null) {
						if (selectedNodeElement instanceof IDOMNode && ((IDOMNode)selectedNodeElement).getModel().isModelStateChanging()) {
							return;
						}
						StructuredSelection nodeSelection = new StructuredSelection(selectedNodeElement);
						getTextEditor().getSelectionProvider().setSelection(nodeSelection);
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

	private Process process;

	private DefaultEditDomain editDomain;

	protected ModelListenerAdapter modelListenerAdapter;

	private Resource extensionsResource;

	private ExtensionMap extensionMap;

	protected StructuredTextEditor fTextEditor = null;
	protected BPELEditor fDesignViewer = null;
	protected int currentPage = -1;


	protected TextEditorSelectionListener textEditorSelectionListener;
	protected DesignViewerSelectionListener designViewerSelectionListener;

	// reacts to changes on the BPEL file (e.g. move, rename)
	private IFileChangeListener fileChangeListener;

	// refactoring listeners
	protected IResourceChangeListener postBuildRefactoringListener;

	BPELModelReconcileAdapter bpelModelReconcileAdapter;

	private OutlinePage outlinePage;
	protected BPELTabbedPropertySheetPage currentPropertySheetPage;

	protected ActionRegistry actionRegistry;

	private static int DESIGN_PAGE_INDEX = 0;
	private static int SOURCE_PAGE_INDEX = 1;

	private final Map<Long, EObject>fMarkers2EObject = new HashMap<Long, EObject>();
	private final Notification fMarkersStale = new NotificationImpl(
			AdapterNotification.NOTIFICATION_MARKERS_STALE, null, null);

	public BPELMultipageEditorPart() {
		super();
		setEditDomain(new BPELEditDomain(this));
	}

	/**
	 * Connects the design viewer with the viewer selection manager. Should be
	 * done after createSourcePage() is done because we need to get the
	 * ViewerSelectionManager from the TextEditor. setModel is also done here
	 * because getModel() needs to reference the TextEditor.
	 */
	protected void connectDesignPage() {

		/*
		 * Connect selection from the Design page to the selection provider of
		 * the Source page so that selection in the Design page will drive
		 * selection in the Source page.
		 */
		this.designViewerSelectionListener = new DesignViewerSelectionListener();
		this.fDesignViewer.getAdaptingSelectionProvider().addSelectionChangedListener(this.designViewerSelectionListener);

		/*
		 * Connect selection from the Source page to the selection provider of
		 * the Design page so that selection in the Source page will drive
		 * selection in the Design page.
		 */
		this.textEditorSelectionListener = new TextEditorSelectionListener();
		ISelectionProvider provider = getTextEditor().getSelectionProvider();
		if (provider instanceof IPostSelectionProvider) {
			((IPostSelectionProvider) provider).addPostSelectionChangedListener(this.textEditorSelectionListener);
		} else {
			provider.addSelectionChangedListener(this.textEditorSelectionListener);
		}

	}

	/**
	 * Creates the design page of the multi-page editor.
	 */
	protected void createDesignPage() {
		this.fDesignViewer = new BPELEditor(getEditDomain(), this);
		// Bug #209341 - starting patch
		if( getFileInput() == null ) {
			MessageDialog.openError(
					getSite().getShell(),
					"Error while opening the file",
			"The file could be opened, no input could be retrieved." );
			return;
		}
		// End of patch
		loadModel();
		try
		{
			addPage(0, this.fDesignViewer, getEditorInput());
			//FIXME I18N
			setPageText(0, "Design");
		} catch (PartInitException e) {
			ErrorDialog.openError(getSite().getShell(), "Error creating Design page", null, e.getStatus()); //$NON-NLS-1$
		}
	}

	/**
	 * Creates the source page of the multi-page editor.
	 */
	protected void createSourcePage() throws PartInitException {
		this.fTextEditor = new StructuredTextEditor();
		try
		{
			addPage(0, this.fTextEditor, getEditorInput());
			//FIXME I18N
			setPageText(0, "Source");
		} catch (PartInitException e) {
			ErrorDialog.openError(getSite().getShell(), "Error creating Source page", null, e.getStatus()); //$NON-NLS-1$
		}
	}

	/**
	 * Creates the pages of this multi-page editor.
	 */
	@Override
	protected void createPages() {
		try {
			// source page must be created before design page
			createSourcePage();
			createDesignPage();
			firePropertyChange(PROP_TITLE);
			connectDesignPage();
			initializeFileChangeListener();
			initializeRefactoringListener();
		} catch (PartInitException e) {
			//Logger.logException(e);
			throw new RuntimeException(e);
		}

		if (BPELUIPlugin.INSTANCE.getDefaultPage().equals(IBPELUIConstants.SOURCE_PAGE)) {
			setActivePage(SOURCE_PAGE_INDEX);
		} else {
			setActivePage(DESIGN_PAGE_INDEX);
		}

		//updateTitle();
	}


	@Override
	public void dispose() {
		/*if (outlinePage != null && outlinePage.getViewer() != null) {
			outlinePage.getViewer().setContents(null);
		}*/
		if (this.currentPage == SOURCE_PAGE_INDEX) {
			BPELUIPlugin.INSTANCE.setDefaultPage(IBPELUIConstants.SOURCE_PAGE);
		} else {
			BPELUIPlugin.INSTANCE.setDefaultPage(IBPELUIConstants.DESIGN_PAGE);
		}

		this.outlinePage = null;
		this.process = null;

		if (this.fileChangeListener != null) {
			BPELUIPlugin.INSTANCE.getResourceChangeListener().removeListener(this.fileChangeListener);
		}

		if (this.postBuildRefactoringListener != null) {
			IWorkspace workspace = ResourcesPlugin.getWorkspace();
			workspace.removeResourceChangeListener(this.postBuildRefactoringListener);
		}

		IStructuredModel model = this.fTextEditor.getModel();
		if (model != null) {
			model.releaseFromEdit();
			this.fDesignViewer.dispose();
			this.fTextEditor.dispose();
		}

		super.dispose();
	}
	
	public void doRevertToSaved(IProgressMonitor monitor) {
		// Do the work within an operation because this is a long running activity that modifies the workbench.
//		WorkspaceModifyOperation operation = new WorkspaceModifyOperation() {
//			protected void execute(IProgressMonitor monitor) throws CoreException {
//				try {
//					getCommandFramework().abortCurrentChange();
//					getCommandStack().flush();
//					
//					// de-select anything selected on the canvas!  Otherwise removing things
//					// will trigger a bunch of behaviour when the selected object(s) are
//					// removed..
//					adaptingSelectionProvider.setSelection(StructuredSelection.EMPTY);
//					
//					process = null;
//					extensionMap = null;
//					extensionsResource = null;
//					lastSelectedEditPart = null;
//					// unload all resources (otherwise they stay around taking up space..?)
//					for (Iterator it = getResourceSet().getResources().iterator(); it.hasNext(); ) {
//						Resource res = (Resource)it.next();
//						res.unload();
//					}
//					loadModel();
//					getGraphicalViewer().setContents(process);
//					getTrayViewer().setContents(process);
//					if (outlinePage != null && outlinePage.getViewer() != null) {
//                      // hack!
//						if (Platform.getWS().equals(Platform.WS_GTK)) {
//							Tree tree = (Tree) outlinePage.getViewer().getControl();
//							if (tree != null) {
//								tree.setRedraw(false);
//								TreeItem[] items = tree.getItems();
//								for (int i = 0; i < items.length; i++) {
//									items[i].dispose();
//								}
//								tree.setRedraw(true);
//							}
//						}
//						outlinePage.getViewer().setContents(process);
//					}
//					selectModelObject(getProcess());
//				}
//				catch (Exception e) {
//					BPELUIPlugin.log(e);
//				}
//			}
//		};
//
//		try {
//			// This runs the options, and shows progress.
//			// (It appears to be a bad thing to fork this onto another thread.)
//			new ProgressMonitorDialog(getSite().getShell()).run(false, false, operation);
//
//			// Refresh the necessary state.
//			firePropertyChange(IEditorPart.PROP_DIRTY);
//		} catch (Exception e) {
//			BPELUIPlugin.log(e);
//		}
	}

	/**
	 * @see org.eclipse.ui.IEditorPart#doSave(org.eclipse.core.runtime.IProgressMonitor)
	 */
	@Override
	public void doSave(IProgressMonitor progressMonitor) {
		// We use fTextEditor to save, because fDesignViewer.doSave() removes comments on save
		// Save bpel only
		this.fDesignViewer.getCommandFramework().applyCurrentChange();
		this.fTextEditor.doSave(progressMonitor);
		// Reset sync stamp and modified flag after save
		this.fDesignViewer.getEditModelClient().getPrimaryResourceInfo().resetSynchronizeStamp();
		this.fDesignViewer.getEditModelClient().getPrimaryResourceInfo().getResource().setModified(false);
		// Save extensions
		this.fDesignViewer.doSave(progressMonitor);
		getCommandStack().markSaveLocation();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.ISaveablePart#doSaveAs()
	 */
	@Override
	public void doSaveAs() {
		//saveAs is not allowed; do nothing
	}

	protected BPELTabbedPropertySheetPage createBPELTabbedPropertySheetPage() {
		//FIXME should the BPELTabbedPropertySheetPage has BPELMultiPageEditorPart as the 2nd argument?
		return new BPELTabbedPropertySheetPage(new ITabbedPropertySheetPageContributor() {
			public String getContributorId() {
				// same as the palette one
				//return fDesignViewer.getPaletteAdditionsContributorId();
				return IBPELUIConstants.BPEL_EDITOR_ID;
			}
		}, this.fDesignViewer);
	}


	protected ActionRegistry getActionRegistry() {
		if (this.actionRegistry == null)
			this.actionRegistry = new ActionRegistry();
		return this.actionRegistry;
	}


	@Override
	public Object getAdapter(Class type) {
		if (type == Process.class) {
			return this.process;
		}

		if (type == BPELEditModelClient.class) {
			return this.process;
		}

		//FIXME should we kill it?
		if (type == ModelListenerAdapter.class) {
			return this.modelListenerAdapter;
		}

		//FIXME should we kill it?
		if (type == Resource.class) {
			return this.extensionsResource;
		}

		//FIXME should we kill it?
		if (type == ExtensionMap.class) {
			return this.extensionMap;
		}

		//FIXME should we kill it?
		if (type == CommandStack.class) {
			return getCommandStack();
		}

		if (type == IContentOutlinePage.class) {
			if (this.outlinePage == null) {
				this.outlinePage = new OutlinePage(new TreeViewer());
			}
			return this.outlinePage;
		}

		if (type == IPropertySheetPage.class) {
			// We can't cache this object because the properties framework needs a new instance
			// every time it calls this method.
			this.currentPropertySheetPage = createBPELTabbedPropertySheetPage();
			return this.currentPropertySheetPage;
		}

		if (type == ActionRegistry.class) {
			return getActionRegistry();
		}

		return super.getAdapter(type);
	}

	public CommandStack getCommandStack() {
		return getEditDomain().getCommandStack();
	}

	protected int getDefaultPageTypeIndex() {
		int pageIndex = DESIGN_PAGE_INDEX;
		if (BPELUIPlugin.INSTANCE.getDefaultPage().equals(IBPELUIConstants.SOURCE_PAGE)) {
			pageIndex = SOURCE_PAGE_INDEX;
		}
		return pageIndex;
	}


	/**
	 * Returns the design viewer
	 * @return the design viewer
	 */
	protected BPELEditor getDesignEditor() {
		return this.fDesignViewer;
	}

	/**
	 * Returns the edit domain.
	 * @return the edit domain
	 */
	protected DefaultEditDomain getEditDomain() {
		return this.editDomain;
	}

	// Bug #209341 - patch
	// By Vincent Zurczak - EBM WebSourcing
	private IFile openFile;
	private static String filePrefix = new SimpleDateFormat( "yyyyMMF_" ).format( new GregorianCalendar().getTime());

	/**
	 * 
	 * @return
	 */
	protected IFile getFileInput() {

		if( this.openFile == null ) {
			try {
				// Case where the file is in the workspace
				if( getEditorInput() instanceof IFileEditorInput )
					this.openFile = ((IFileEditorInput) getEditorInput()).getFile();

				// Outside the workspace
				// Since everything relies on IFiles, we create a temporary file in the workspace
				// linking to the file outside the workspace
				else if( getEditorInput() instanceof FileStoreEditorInput ) {
					File f = new File(((FileStoreEditorInput) getEditorInput()).getURI());
					IPath path = new Path( f.getAbsolutePath());

					// Create a temporary project
					IProgressMonitor monitor =  new NullProgressMonitor();
					IProject tempProject = ResourcesPlugin.getWorkspace().getRoot().getProject( ".temp" );
					if( ! tempProject.exists())
						tempProject.create( monitor );

					if( ! tempProject.isOpen())
						tempProject.open( monitor );

					// Remove old temporary files
					// The file prefix is designed so that natural comparison order is enough
					for( IResource res : tempProject.members()) {
						if( res.getName().substring( 0, 7 ).compareTo( filePrefix ) < 0 ) {
							try {
								res.delete( false, monitor );
							} catch( Exception e ) {
								e.printStackTrace();
							}
						}
					}

					// Create a temporary file
					this.openFile = tempProject.getFile( filePrefix + path.lastSegment());
					this.openFile.createLink( path, IResource.NONE, monitor );
				}

			} catch( CoreException e ) {
				e.printStackTrace();
			}
		}

		return this.openFile;
	}
	// End of patch

	public Process getProcess() {
		return this.process;
	}

	/**
	 * Returns the design viewer
	 * @return the design viewer
	 */
	protected StructuredTextEditor getSourceViewer() {
		return this.fTextEditor;
	}

	StructuredTextEditor getTextEditor() {
		return this.fTextEditor;
	}

	public void gotoMarker(IMarker marker) {

		// One such mechanism is to use the href of the model object
		// generated by the validator or whatever ...

		String href = null;
		try {
			href = (String) marker.getAttribute( "address.model" );
		} catch (CoreException ex) {
			BPELUIPlugin.log(ex);
		}

		// lookup by object href in the model.
		EObject modelObject = null;

		if (href != null) {
			try {
				modelObject = this.fDesignViewer.getResource().getEObject( href );
			} catch (Throwable t) {
				BPELUIPlugin.log(t);
			}
		}

		gotoText(marker);

		if (modelObject == null) {
			return;
		}

		gotoMarker ( marker, modelObject );
	}

	private void gotoText(IMarker marker) {
		Integer charStart = null;
		Integer charEnd = null;
		try {
			charStart = (Integer) marker.getAttribute( "charStart" );
			charEnd = (Integer) marker.getAttribute( "charEnd" );
		} catch (CoreException ex) {
			BPELUIPlugin.log(ex);
		}
		charStart = charStart == null ? 0 : charStart;
		charEnd = charEnd == null ? charStart : charEnd;
		try {
			this.fTextEditor.setHighlightRange(charStart, charEnd - charStart, true);
		} catch (Throwable t) {
			BPELUIPlugin.log(t);
		}
	}

	void gotoMarker ( IMarker marker, EObject modelObject ) {

		// TODO: is this bogus now that we have AdaptingSelectionProvider?


		// The closest parent which has an edit part in the graph view.
		//
		// The following do not have viewers in the graph view:
		//  1) Variables, PartnerLinks, Correlation Sets, Message Exchanges
		// If it's any of those, then we have to reveal the closest container
		// and then select the model object and show the properties.

		GraphicalViewer graphViewer = this.fDesignViewer.getGraphicalViewer();
		EObject refObj = null;

		EditPart editPart = null;
		if ( modelObject instanceof Variable ||
				modelObject instanceof PartnerLink ||
				modelObject instanceof CorrelationSet ||
				modelObject instanceof MessageExchange) {

			refObj = ModelHelper.getContainingScope(modelObject);
			editPart = (EditPart)graphViewer.getEditPartRegistry().get(refObj);
			if (editPart != null) {
				graphViewer.reveal(editPart);
			}
			this.fDesignViewer.selectModelObject(modelObject);

		} else if (modelObject instanceof Activity) {

			// activity objects are on the graphical viewer
			refObj = modelObject;
			editPart = (EditPart)graphViewer.getEditPartRegistry().get(refObj);

			if (editPart != null) {
				graphViewer.reveal(editPart);
			}

			this.fDesignViewer.selectModelObject(modelObject);


		} else {

			refObj = modelObject;
			while (refObj != null && !(refObj instanceof Activity) ) {
				refObj = refObj.eContainer();
			}

			// select process by default.
			if (refObj == null) {
				refObj = BPELUtils.getProcess( modelObject ) ;
			}

			modelObject = refObj;

			editPart = (EditPart)graphViewer.getEditPartRegistry().get(modelObject);

			if (editPart != null) {
				graphViewer.reveal(editPart);
			}

			this.fDesignViewer.selectModelObject(modelObject);
		}

		// If possible, try to display the marker in a property section.
		BPELTabbedPropertySheetPage propertySheetPage = this.currentPropertySheetPage;
		if (propertySheetPage == null) {
			return;
			// if currentPropertySheetPage is null it means that the properties
			// page hasn't shown yet. Since we only want to show it if we have
			// markers for it we create a new BPELTabbedPropertySheetPage. This
			// new one should only be used to select which tab and section to show.
			// TODO: this doesn't work
			//propertySheetPage = createBPELTabbedPropertySheetPage();
		}

		TabbedPropertyViewer viewer = propertySheetPage.getTabbedPropertyViewer();

		int j = 0;
		while (true) { // while we don't get an exception...
			TabDescriptor descriptor = null;
			try {
				descriptor = (TabDescriptor)viewer.getElementAt(j++);
			} catch (IndexOutOfBoundsException iobe) {
				break;
			}

			if (descriptor == null) {
				break; // no more descriptors
			}

			TabContents tab = descriptor.createTab();
			ISection[] sections = tab.getSections();
			for (int i = 0; i < sections.length; i++) {

				if (BPELPropertySection.class.isInstance( sections[i]) == false) {
					continue;
				}

				BPELPropertySection section = (BPELPropertySection)sections[i];

				// HACK: we have to fake the initialization of this section in order to
				// make isValidMarker work. This section should not be used as a normal section.
				section.createControls(new Composite(getSite().getShell(), 0), propertySheetPage);
				section.setInput(this, new StructuredSelection(modelObject));

				if (section.isValidMarker (marker) ) {

					// the first section that handles this kind of marker wins
					showPropertiesView();
					// get real viewer, Tab and ISection objects since we are probably using fake ones
					viewer = this.currentPropertySheetPage.getTabbedPropertyViewer();
					viewer.setSelection(new StructuredSelection(descriptor));
					tab = this.currentPropertySheetPage.getCurrentTab();
					section = (BPELPropertySection)tab.getSectionAtIndex(i);
					section.gotoMarker(marker);
					return; // ignore other sections and tabs

				}
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.IEditorPart#init(org.eclipse.ui.IEditorSite,
	 *      org.eclipse.ui.IEditorInput)
	 */
	@Override
	public void init(IEditorSite site, IEditorInput input) throws PartInitException {
		try {
			super.init(site, input);
			//			getCommandStack().addCommandStackListener(this);
		} catch (Exception e) {
			e.printStackTrace();
		}
		setPartName(input.getName());
	}

	protected void initializeFileChangeListener() {
		this.fileChangeListener = new IFileChangeListener() {
			public void deleted(IFile file) {
				IFile current = ((IFileEditorInput)getEditorInput()).getFile();
				if (current.equals(file)) {
					// Close the editor.
					Display display = getSite().getShell().getDisplay();
					display.asyncExec(new Runnable() {
						public void run() {
							getSite().getPage().closeEditor(BPELMultipageEditorPart.this, false);
						}
					});
				}
			}
			public void moved(IFile source, final IFile destination) {
//				IFile current = ((IFileEditorInput) getEditorInput()).getFile();
//				if (!current.equals(source)) {
//					return;
//				}
//				// update editors input
//				final IFileEditorInput input = new FileEditorInput(destination);
//				Display display = getDetailsEditor().getSite().getShell().getDisplay();
//				display.syncExec(new Runnable() {
//					public void run() {
//						getBPELDetailsEditor().setInput(input);
//						setInput(input);
//					}
//				});
//				// update resources
//				IPath path = destination.getFullPath();
//				URI uri = URI.createPlatformResourceURI(path.toString());
//				processResource.setURI(uri);
//				// JM: Comment out. We don't want to re-name the process just because
//				// the file name has changed
////				display.syncExec(new Runnable() {
////					public void run() {
////						BPELUtil.updateNameAndNamespace(destination, process);
////					}
////				});
//				path = path.removeFileExtension().addFileExtension(IBPELUIConstants.EXTENSION_MODEL_EXTENSIONS);
//				URI extensionsUri = URI.createPlatformResourceURI(path.toString());
//				extensionsResource = resourceSet.createResource(extensionsUri);
//				extensionsResource.setURI(extensionsUri);
//				try {
//					// JM: Comment out for now. We should re-test this
////					processResource.save(Collections.EMPTY_MAP);
////					destination.refreshLocal(IResource.DEPTH_ZERO, null);
//				} catch (Exception e) {
//					BPELUIPlugin.log(e);
//				}
			}
		};
		BPELUIPlugin.INSTANCE.getResourceChangeListener().addListener(this.fileChangeListener);
	}


	/**
	 * Installs the refactoring listener
	 */
	protected void initializeRefactoringListener() {
		final IWorkspace workspace = ResourcesPlugin.getWorkspace();
		this.postBuildRefactoringListener = new IResourceChangeListener() {
			public void resourceChanged(IResourceChangeEvent event) {
				IFile newFile = ((FileEditorInput)getEditorInput()).getFile();
				final IResourceDelta bpelFileDelta = event.getDelta().findMember(newFile.getFullPath());
				// we only care about the change if it is a move or a rename
				if (bpelFileDelta != null && (bpelFileDelta.getFlags() & IResourceDelta.MOVED_FROM) != 0) {
					getSite().getShell().getDisplay().syncExec(new Runnable() {
						public void run() {
							doRevertToSaved(null);
						}
					});
				}
			}
		};
		workspace.addResourceChangeListener(this.postBuildRefactoringListener, IResourceChangeEvent.POST_BUILD);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.ISaveablePart#isSaveAsAllowed()
	 */
	@Override
	public boolean isSaveAsAllowed() {
		return false;
	}

	protected void loadModel() {
		Document structuredDocument = null;

		try {
			IDocument doc = this.fTextEditor.getDocumentProvider().getDocument(getEditorInput());
			if (doc instanceof IStructuredDocument) {
				IStructuredModel model = StructuredModelManager.getModelManager().getExistingModelForEdit(doc);
				if (model == null) {
					model = StructuredModelManager.getModelManager().getModelForEdit((IStructuredDocument) doc);
				}
				if (model != null) {
					structuredDocument = ((IDOMModel) model).getDocument();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		HashMap<String, Document> loadOptions = null;
		if (structuredDocument != null) {
			loadOptions = new HashMap<String, Document> (1);
			loadOptions.put("DOMDocument", structuredDocument);
		}

		//FIXME WSDLEditor has gef command stack; in order to have gef command stack we need to add design page first

		// Bug # 209341 - starting patch
		// By Vincent Zurczak
		IFile fileToOpen = getFileInput();
		BPELEditModelClient editModelClient = new BPELEditModelClient(this, fileToOpen, this, loadOptions);
		this.fDesignViewer.setEditModelClient(editModelClient);
		getEditDomain().setCommandStack(editModelClient.getCommandStack());

		Resource bpelResource = editModelClient.getPrimaryResourceInfo().getResource();
		BPELReader reader = new BPELReader();
		reader.read(bpelResource, fileToOpen, this.fDesignViewer.getResourceSet());
		// End of patch

		this.process = reader.getProcess();
		this.bpelModelReconcileAdapter = new BPELModelReconcileAdapter (structuredDocument, this.process, bpelResource, this.fDesignViewer);

		if (getEditDomain() != null) {
			((BPELEditDomain)getEditDomain()).setProcess(getProcess());
		}
		this.extensionsResource = reader.getExtensionsResource();
		this.extensionMap = reader.getExtensionMap();

		this.modelListenerAdapter = new ModelListenerAdapter();
		this.modelListenerAdapter.setExtensionMap(this.extensionMap);
	}

	public void modelDeleted(ResourceInfo resourceInfo) {
		if (!isDirty()) {
			getSite().getPage().closeEditor(this, false);
		}
	}

	public void modelDirtyStateChanged(ResourceInfo resourceInfo) {
		firePropertyChange(PROP_DIRTY);
	}

	public void modelLocationChanged(ResourceInfo resourceInfo, IFile movedToFile) {
		// TODO!
		//updateInputFile(movedToFile.getFullPath());
	}

	public void modelReloaded(ResourceInfo resourceInfo) {
		Resource bpelResource = this.fDesignViewer.getEditModelClient().getPrimaryResourceInfo().getResource();

		IFile file = getFileInput();
		BPELReader reader = new BPELReader();
		reader.read(bpelResource, file, this.fDesignViewer.getResourceSet());

		this.process = reader.getProcess();
		if (getEditDomain() != null) {
			((BPELEditDomain)getEditDomain()).setProcess(getProcess());
		}
		this.extensionMap = reader.getExtensionMap();

		this.modelListenerAdapter.setExtensionMap(this.fDesignViewer.getExtensionMap());

		this.fDesignViewer.getGraphicalViewer().setContents(getProcess());

		// The ProcessTrayEditPart tries to remove its selection listener on deactivate.
		// In this case, it will fail because the edit part can't find the editor because
		// the process no longer belongs to a resource. Help it out and remove the
		// listener manually.
		ProcessTrayEditPart processTrayEditPart = (ProcessTrayEditPart)this.fDesignViewer.getTrayViewer().getContents();
		this.fDesignViewer.getGraphicalViewer().removeSelectionChangedListener(processTrayEditPart.getSelectionChangedListener());

		this.fDesignViewer.getTrayViewer().setContents(getProcess());

		//Bugzilla 294501 - When markers are added on the BPEL file, the meta-model 
		//objects are notified about the marker change. But the display of the markers 
		//on the diagram fails because of several invalid thread access exceptions.
		//Thus, encapsulating the marker update into a separate thread
		//Note: supposedly only happens on Galileo (== Eclipse 3.5)
		Display.getDefault().asyncExec( new Runnable() {
		    public void run() {
		    	updateMarkersHard();
		    }
		});

	}

	protected void updateMarkersHard () {

		for(EObject obj : this.fMarkers2EObject.values()) {
			obj.eNotify(this.fMarkersStale);
		}

		this.fMarkers2EObject.clear();

		IMarker[] markers = null;
		IFile file = getFileInput();
		Resource resource = getProcess().eResource();

		try {
			markers = file.findMarkers(null, true, IResource.DEPTH_ZERO);
		} catch (CoreException ex) {
			BPELUIPlugin.log(ex);
			return;
		}

		for (IMarker m : markers) {

			String href = null;
			EObject target = null;
			try {
				href = (String) m.getAttribute( "address.model" ); //$NON-NLS-1$
				if (href == null) {
					continue;
				}
				target = resource.getEObject(href);
			} catch (CoreException ex) {
				continue;
			}

			if (target == null) {
				continue;
			}

			this.fMarkers2EObject.put(m.getId(), target);
			target.eNotify( new NotificationImpl (AdapterNotification.NOTIFICATION_MARKER_ADDED , null, m ));
		}

	}


	@Override
	protected void pageChange(int newPageIndex) {
		this.currentPage = newPageIndex;
		super.pageChange(newPageIndex);
	}


	/**
	 * Sets the EditDomain for this EditorPart.
	 * @param ed the domain
	 */
	protected void setEditDomain(DefaultEditDomain ed) {
		this.editDomain = ed;
	}

	protected void showPropertiesView() {
		IWorkbench workbench = PlatformUI.getWorkbench();
		IWorkbenchPage page = workbench.getActiveWorkbenchWindow().getActivePage();
		try {
			page.showView(IBPELUIConstants.PROPERTY_VIEW_ID);
		} catch (PartInitException e) {
			BPELUIPlugin.log(e);
		}
	}

	/**
	 * The editor part name should be the same as the one appearing in the logical view.
	 */
	protected void updateTitle() {
		setPartName(getProcess().getName());
	}

	public void modelMarkersChanged ( ResourceInfo resourceInfo , IMarkerDelta [] markerDelta ) {

		Resource resource = resourceInfo.getResource();

		for ( IMarkerDelta delta : markerDelta ) {

			String href = (String) delta.getAttribute( "address.model" ); //$NON-NLS-1$
			if (href == null) {
				continue;
			}

			EObject target = null;

			switch (delta.getKind()) {
			case IResourceDelta.ADDED :
				target = resource.getEObject(href);
				if (target != null) {
					this.fMarkers2EObject.put(delta.getId(),target);
					target.eNotify( new NotificationImpl(AdapterNotification.NOTIFICATION_MARKER_ADDED,null,delta.getMarker() ));
				}
				break;
			case IResourceDelta.CHANGED :
				target = this.fMarkers2EObject.remove(delta.getId());
				if (target != null) {
					target.eNotify( new NotificationImpl(AdapterNotification.NOTIFICATION_MARKER_CHANGED,delta.getMarker(),null));
				}
				break;
			case IResourceDelta.REMOVED :
				target = this.fMarkers2EObject.remove(delta.getId());
				if (target != null) {
					target.eNotify( new NotificationImpl(AdapterNotification.NOTIFICATION_MARKER_DELETED,delta.getMarker(),null));
				}
				break;
			}

		}
	}

	@Override
	public boolean isDirty() {
		return this.fTextEditor.isDirty();
	}

	@Override
	public IEditorPart getActiveEditor() {
		return super.getActiveEditor();
	}
}
