content: /*******************************************************************************
   * Copyright (c) 2000, 2008 IBM Corporation and others.
   * 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:
   *     IBM Corporation - initial API and implementation
   *******************************************************************************/
  package org.eclipse.wst.jsdt.internal.ui.compare;
  
  import java.lang.reflect.InvocationTargetException;
  import java.util.List;
  import java.util.Map;
  import java.util.ResourceBundle;
  
  import org.eclipse.compare.EditionSelectionDialog;
  import org.eclipse.compare.IStreamContentAccessor;
  import org.eclipse.compare.ITypedElement;
  import org.eclipse.compare.structuremergeviewer.DocumentRangeNode;
  import org.eclipse.core.filebuffers.FileBuffers;
  import org.eclipse.core.filebuffers.ITextFileBuffer;
  import org.eclipse.core.filebuffers.ITextFileBufferManager;
  import org.eclipse.core.filebuffers.LocationKind;
  import org.eclipse.core.resources.IFile;
  import org.eclipse.core.runtime.Assert;
  import org.eclipse.core.runtime.CoreException;
  import org.eclipse.core.runtime.IPath;
  import org.eclipse.core.runtime.IStatus;
  import org.eclipse.jface.dialogs.MessageDialog;
  import org.eclipse.jface.text.IDocument;
  import org.eclipse.jface.text.TextUtilities;
  import org.eclipse.jface.viewers.ISelection;
  import org.eclipse.jface.viewers.IStructuredSelection;
  import org.eclipse.swt.widgets.Shell;
  import org.eclipse.ui.IEditorInput;
  import org.eclipse.wst.jsdt.core.IJavaScriptProject;
  import org.eclipse.wst.jsdt.core.IJavaScriptUnit;
  import org.eclipse.wst.jsdt.core.IMember;
  import org.eclipse.wst.jsdt.core.IParent;
  import org.eclipse.wst.jsdt.core.IType;
  import org.eclipse.wst.jsdt.core.dom.ASTNode;
  import org.eclipse.wst.jsdt.core.dom.BodyDeclaration;
  import org.eclipse.wst.jsdt.core.dom.ImportDeclaration;
  import org.eclipse.wst.jsdt.core.dom.JavaScriptUnit;
  import org.eclipse.wst.jsdt.core.dom.PackageDeclaration;
  import org.eclipse.wst.jsdt.core.dom.TypeDeclaration;
  import org.eclipse.wst.jsdt.core.dom.rewrite.ASTRewrite;
  import org.eclipse.wst.jsdt.core.dom.rewrite.ListRewrite;
  import org.eclipse.wst.jsdt.internal.corext.dom.ASTNodes;
  import org.eclipse.wst.jsdt.internal.corext.util.Resources;
  import org.eclipse.wst.jsdt.internal.ui.IJavaHelpContextIds;
  import org.eclipse.wst.jsdt.internal.ui.JavaScriptPlugin;
  import org.eclipse.wst.jsdt.internal.ui.javaeditor.JavaEditor;
  import org.eclipse.wst.jsdt.internal.ui.util.ExceptionHandler;
  import org.eclipse.wst.jsdt.ui.IWorkingCopyManager;
  
  
  class JavaAddElementFromHistoryImpl extends JavaHistoryActionImpl {
  	
  	private static final String BUNDLE_NAME= "org.eclipse.wst.jsdt.internal.ui.compare.AddFromHistoryAction"; //$NON-NLS-1$
  	
  	JavaAddElementFromHistoryImpl() {
  		super(true);
  	}
  	
  	public void run(ISelection selection) {
  		
  		String errorTitle= CompareMessages.AddFromHistory_title; 
  		String errorMessage= CompareMessages.AddFromHistory_internalErrorMessage; 
  		Shell shell= getShell();
  		
  		IJavaScriptUnit cu= null;
  		IParent parent= null;
  		IMember input= null;
  		
  		// analyze selection
  		if (selection.isEmpty()) {
  			// no selection: we try to use the editor's input
  			JavaEditor editor= getEditor();
  			if (editor != null) {
  				IEditorInput editorInput= editor.getEditorInput();
  				IWorkingCopyManager manager= JavaScriptPlugin.getDefault().getWorkingCopyManager();
  				if (manager != null) {
  					cu= manager.getWorkingCopy(editorInput);
  					parent= cu;
  				}
  			}
  		} else {
  			input= getEditionElement(selection);
  			if (input != null) {
  				cu= input.getJavaScriptUnit();
  				parent= input;
  				input= null;
  
  			} else {
  				if (selection instanceof IStructuredSelection) {
  					Object o= ((IStructuredSelection)selection).getFirstElement();
  					if (o instanceof IJavaScriptUnit) {
  						cu= (IJavaScriptUnit) o;
  						parent= cu;
  					}
  				}
  			}
  		}
  		
  		if (parent == null || cu == null) {
  			String invalidSelectionMessage= CompareMessages.AddFromHistory_invalidSelectionMessage; 
  			MessageDialog.openInformation(shell, errorTitle, invalidSelectionMessage);
  			return;
  		}
  		
  		IFile file= getFile(parent);
  		if (file == null) {
  			MessageDialog.openError(shell, errorTitle, errorMessage);
  			return;
  		}
  				
  		boolean inEditor= beingEdited(file);
  
  		IStatus status= Resources.makeCommittable(file, shell);
  		if (!status.isOK()) {
  			return;
  		}
  		
  		// get the document where to insert the text
  		IPath path= file.getFullPath();
  		ITextFileBufferManager bufferManager= FileBuffers.getTextFileBufferManager();
  		ITextFileBuffer textFileBuffer= null;
  		try {
  			bufferManager.connect(path, LocationKind.IFILE, null);
  			textFileBuffer= bufferManager.getTextFileBuffer(path, LocationKind.IFILE);
  			IDocument document= textFileBuffer.getDocument();
  			
  			// configure EditionSelectionDialog and let user select an edition
  			ITypedElement target= new JavaTextBufferNode(file, document, inEditor);
  			ITypedElement[] editions= buildEditions(target, file);
  											
  			ResourceBundle bundle= ResourceBundle.getBundle(BUNDLE_NAME);
  			EditionSelectionDialog d= new EditionSelectionDialog(shell, bundle);
  			d.setAddMode(true);
  			d.setHelpContextId(IJavaHelpContextIds.ADD_ELEMENT_FROM_HISTORY_DIALOG);
  			ITypedElement selected= d.selectEdition(target, editions, parent);
  			if (selected == null)
  				return;	// user cancel
  								
  			IJavaScriptUnit cu2= cu;
  			if (parent instanceof IMember)
  				cu2= ((IMember)parent).getJavaScriptUnit();
  			
  			JavaScriptUnit root= parsePartialCompilationUnit(cu2);
  			ASTRewrite rewriter= ASTRewrite.create(root.getAST());
  			
  			ITypedElement[] results= d.getSelection();
  			for (int i= 0; i < results.length; i++) {
  				
  			    // create an AST node
  				ASTNode newNode= createASTNode(rewriter, results[i], TextUtilities.getDefaultLineDelimiter(document), cu.getJavaScriptProject());
  				if (newNode == null) {
  					MessageDialog.openError(shell, errorTitle, errorMessage);
  					return;	
  				}
  				
  				// now determine where to put the new node
  				if (newNode instanceof PackageDeclaration) {
  				    rewriter.set(root, JavaScriptUnit.PACKAGE_PROPERTY, newNode, null);
  				    
  				} else if (newNode instanceof ImportDeclaration) {
  					ListRewrite lw= rewriter.getListRewrite(root, JavaScriptUnit.IMPORTS_PROPERTY);
  					lw.insertFirst(newNode, null);
  					
  				} else {	// class, interface, enum, annotation, method, field
  					
  					if (parent instanceof IJavaScriptUnit) {	// top level
  						ListRewrite lw= rewriter.getListRewrite(root, JavaScriptUnit.TYPES_PROPERTY);
  						int index= ASTNodes.getInsertionIndex((BodyDeclaration)newNode, root.types());
  						lw.insertAt(newNode, index, null);
  						
  					} else if (parent instanceof IType) {
  						ASTNode declaration= getBodyContainer(root, (IType)parent);
  						if (declaration instanceof TypeDeclaration) {
  							List container= ASTNodes.getBodyDeclarations(declaration);
  							int index= ASTNodes.getInsertionIndex((BodyDeclaration)newNode, container);
  							ListRewrite lw= rewriter.getListRewrite(declaration, ASTNodes.getBodyDeclarationsProperty(declaration));
  							lw.insertAt(newNode, index, null);
  						}
  					} else {
  						JavaScriptPlugin.logErrorMessage("JavaAddElementFromHistoryImpl: unknown container " + parent); //$NON-NLS-1$
  					}
  					
  				}
  			}
  			
  			Map options= null;
  			IJavaScriptProject javaProject= cu2.getJavaScriptProject();
  			if (javaProject != null)
  				options= javaProject.getOptions(true);
  			applyChanges(rewriter, document, textFileBuffer, shell, inEditor, options);
  
  	 	} catch(InvocationTargetException ex) {
  			ExceptionHandler.handle(ex, shell, errorTitle, errorMessage);
  			
  		} catch(InterruptedException ex) {
  			// shouldn't be called because is not cancelable
  			Assert.isTrue(false);
  			
  		} catch(CoreException ex) {
  			ExceptionHandler.handle(ex, shell, errorTitle, errorMessage);
  			
  		} finally {
  			try {
  				if (textFileBuffer != null)
  					bufferManager.disconnect(path, LocationKind.IFILE, null);
  			} catch (CoreException e) {
  				JavaScriptPlugin.log(e);
  			}
  		}
  	}
  	
  	/**
  	 * Creates a place holder ASTNode for the given element.
  	 * @param rewriter
  	 * @param element
  	 * @param delimiter the line delimiter
  	 * @param project 
  	 * @return a ASTNode or null
  	 * @throws CoreException
  	 */
  	private ASTNode createASTNode(ASTRewrite rewriter, ITypedElement element, String delimiter, IJavaScriptProject project) throws CoreException {
  		if (element instanceof IStreamContentAccessor) {
  			String content= JavaCompareUtilities.readString((IStreamContentAccessor)element);
  			if (content != null) {
  				content= trimTextBlock(content, delimiter, project);
  				if (content != null) {
  				    int type= getPlaceHolderType(element);
  				    if (type != -1)
  				        return rewriter.createStringPlaceholder(content, type);
  				}
  			}
  		}
  		return null;
  	}
  	
  	/**
  	 * Returns the corresponding place holder type for the given element.
  	 * @return a place holder type (see ASTRewrite) or -1 if there is no corresponding placeholder
  	 */
  	private int getPlaceHolderType(ITypedElement element) {
  		
  		if (element instanceof DocumentRangeNode) {
  			JavaNode jn= (JavaNode) element;
  			switch (jn.getTypeCode()) {
  				
  			case JavaNode.PACKAGE:
  			    return ASTNode.PACKAGE_DECLARATION;
  
  			case JavaNode.CLASS:
  			case JavaNode.INTERFACE:
  				return ASTNode.TYPE_DECLARATION;
  				
  			case JavaNode.CONSTRUCTOR:
  			case JavaNode.METHOD:
  				return ASTNode.FUNCTION_DECLARATION;
  				
  			case JavaNode.FIELD:
  				return ASTNode.FIELD_DECLARATION;
  				
  			case JavaNode.INIT:
  				return ASTNode.INITIALIZER;
  
  			case JavaNode.IMPORT:
  			case JavaNode.IMPORT_CONTAINER:
  				return ASTNode.IMPORT_DECLARATION;
  
  			case JavaNode.CU:
  			    return ASTNode.JAVASCRIPT_UNIT;
  			}
  		}
  		return -1;
  	}
  
  	protected boolean isEnabled(ISelection selection) {
  		
  		if (selection.isEmpty()) {
  			JavaEditor editor= getEditor();
  			if (editor != null) {
  				// we check whether editor shows JavaScriptUnit
  				IEditorInput editorInput= editor.getEditorInput();
  				IWorkingCopyManager manager= JavaScriptPlugin.getDefault().getWorkingCopyManager();
  				return manager.getWorkingCopy(editorInput) != null;
  			}
  			return false;
  		}
  		
  		if (selection instanceof IStructuredSelection) {
  			Object o= ((IStructuredSelection)selection).getFirstElement();
  			if (o instanceof IJavaScriptUnit)
  				return true;
  		}
  		
  		return super.isEnabled(selection);
  	}
  }
  