content: /*******************************************************************************
   * Copyright (c) 2000, 2009 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.corext.codemanipulation;
  
  import org.eclipse.core.filebuffers.FileBuffers;
  import org.eclipse.core.filebuffers.ITextFileBufferManager;
  import org.eclipse.core.filebuffers.LocationKind;
  import org.eclipse.core.resources.IWorkspaceRunnable;
  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.IStatus;
  import org.eclipse.core.runtime.NullProgressMonitor;
  import org.eclipse.core.runtime.OperationCanceledException;
  import org.eclipse.core.runtime.SubProgressMonitor;
  import org.eclipse.core.runtime.jobs.ISchedulingRule;
  import org.eclipse.jface.text.BadLocationException;
  import org.eclipse.jface.text.IDocument;
  import org.eclipse.jface.text.IRegion;
  import org.eclipse.jface.text.TextUtilities;
  import org.eclipse.text.edits.InsertEdit;
  import org.eclipse.text.edits.MultiTextEdit;
  import org.eclipse.wst.jsdt.core.IJavaScriptUnit;
  import org.eclipse.wst.jsdt.core.IField;
  import org.eclipse.wst.jsdt.core.IJavaScriptElement;
  import org.eclipse.wst.jsdt.core.IJavaScriptProject;
  import org.eclipse.wst.jsdt.core.IMember;
  import org.eclipse.wst.jsdt.core.IFunction;
  import org.eclipse.wst.jsdt.core.IType;
  import org.eclipse.wst.jsdt.core.ITypeHierarchy;
  import org.eclipse.wst.jsdt.core.JavaScriptModelException;
  import org.eclipse.wst.jsdt.core.Signature;
  import org.eclipse.wst.jsdt.internal.corext.dom.TokenScanner;
  import org.eclipse.wst.jsdt.internal.corext.util.MethodOverrideTester;
  import org.eclipse.wst.jsdt.internal.corext.util.Strings;
  import org.eclipse.wst.jsdt.internal.corext.util.SuperTypeHierarchyCache;
  import org.eclipse.wst.jsdt.internal.ui.JavaUIStatus;
  import org.eclipse.wst.jsdt.ui.CodeGeneration;
  
  /**
  *
  * Provisional API: This class/interface is part of an interim API that is still under development and expected to
  * change significantly before reaching stability. It is being made available at this early stage to solicit feedback
  * from pioneering adopters on the understanding that any code that uses this API will almost certainly be broken
  * (repeatedly) as the API evolves.
  */
  public class AddJavaDocStubOperation implements IWorkspaceRunnable {
  	
  	private IMember[] fMembers;
  	
  	public AddJavaDocStubOperation(IMember[] members) {
  		super();
  		fMembers= members;
  	}
  
  	private String createTypeComment(IType type, String lineDelimiter) throws CoreException {
  		return CodeGeneration.getTypeComment(type.getJavaScriptUnit(), type.getTypeQualifiedName('.'), lineDelimiter);
  	}		
  	
  	private String createMethodComment(IFunction meth, String lineDelimiter) throws CoreException {
  		IType declaringType= meth.getDeclaringType();
  		
  		IFunction overridden= null;
  		if (!meth.isConstructor() && declaringType!=null) {
  			ITypeHierarchy hierarchy= SuperTypeHierarchyCache.getTypeHierarchy(declaringType);
  			MethodOverrideTester tester= new MethodOverrideTester(declaringType, hierarchy);
  			overridden= tester.findOverriddenMethod(meth, true);
  		}
  		return CodeGeneration.getMethodComment(meth, overridden, lineDelimiter);
  	}
  	
  	private String createFieldComment(IField field, String lineDelimiter) throws JavaScriptModelException, CoreException {
  		String typeName= Signature.toString(field.getTypeSignature());
  		String fieldName= field.getElementName();
  		return CodeGeneration.getFieldComment(field.getJavaScriptUnit(), typeName, fieldName, lineDelimiter);
  	}		
  		
  	/**
  	 * @return Returns the scheduling rule for this operation
  	 */
  	public ISchedulingRule getScheduleRule() {
  		return ResourcesPlugin.getWorkspace().getRoot();
  	}
  
  	/**
  	 * Runs the operation.
  	 * @throws OperationCanceledException Runtime error thrown when operation is cancelled.
  	 */	
  	public void run(IProgressMonitor monitor) throws CoreException, OperationCanceledException {
  		if (monitor == null) {
  			monitor= new NullProgressMonitor();
  		}
  		if (fMembers.length == 0) {
  			return;
  		}
  		try {
  			monitor.beginTask(CodeGenerationMessages.AddJavaDocStubOperation_description, fMembers.length + 2); 
  
  			addJavadocComments(monitor);
  		} finally {
  			monitor.done();
  		}
  	}
  	/* moved this so we this can be re-used in web component */
  	
  	protected IDocument getDocument(IJavaScriptUnit cu, IProgressMonitor monitor) throws CoreException  {
  		ITextFileBufferManager manager= FileBuffers.getTextFileBufferManager();
  		IPath path= cu.getPath();
  		try {
  		manager.connect(path, LocationKind.IFILE, new SubProgressMonitor(monitor, 1));
  			return manager.getTextFileBuffer(path).getDocument();
  		
  			
  		}finally {
  			manager.disconnect(path, LocationKind.IFILE,new SubProgressMonitor(monitor, 1));
  		}
  	}
  	
  	private void addJavadocComments(IProgressMonitor monitor) throws CoreException {
  		IJavaScriptUnit cu= fMembers[0].getJavaScriptUnit();
  		
  		
  		try {
  			IDocument document= getDocument(cu,monitor);
  			
  			String lineDelim= TextUtilities.getDefaultLineDelimiter(document);
  			MultiTextEdit edit= new MultiTextEdit();
  			
  			for (int i= 0; i < fMembers.length; i++) {
  				IMember curr= fMembers[i];
  				int memberStartOffset= getMemberStartOffset(curr, document);
  				
  				String comment= null;
  				switch (curr.getElementType()) {
  					case IJavaScriptElement.TYPE:
  						comment= createTypeComment((IType) curr, lineDelim);
  						break;
  					case IJavaScriptElement.FIELD:
  						comment= createFieldComment((IField) curr, lineDelim);	
  						break;
  					case IJavaScriptElement.METHOD:
  						comment= createMethodComment((IFunction) curr, lineDelim);
  						break;
  				}
  				if (comment == null) {
  					StringBuffer buf= new StringBuffer();
  					buf.append("/**").append(lineDelim); //$NON-NLS-1$
  					buf.append(" *").append(lineDelim); //$NON-NLS-1$
  					buf.append(" */").append(lineDelim); //$NON-NLS-1$
  					comment= buf.toString();						
  				} else {
  					if (!comment.endsWith(lineDelim)) {
  						comment= comment + lineDelim;
  					}
  				}
  				
  				final IJavaScriptProject project= cu.getJavaScriptProject();
  				IRegion region= document.getLineInformationOfOffset(memberStartOffset);
  				
  				String line= document.get(region.getOffset(), region.getLength());
  				String indentString= Strings.getIndentString(line, project);
  				
  				String indentedComment= Strings.changeIndent(comment, 0, project, indentString, lineDelim);
  
  				edit.addChild(new InsertEdit(memberStartOffset, indentedComment));
  
  				monitor.worked(1);
  			}
  			edit.apply(document); // apply all edits
  		} catch (BadLocationException e) {
  			throw new CoreException(JavaUIStatus.createError(IStatus.ERROR, e));
  		} finally {
  			
  		}
  	}
  
  	private int getMemberStartOffset(IMember curr, IDocument document) throws JavaScriptModelException {
  		int offset= curr.getSourceRange().getOffset();
  		TokenScanner scanner= new TokenScanner(document, curr.getJavaScriptProject());
  		try {
  			return scanner.getNextStartOffset(offset, true); // read to the first real non comment token
  		} catch (CoreException e) {
  			// ignore
  		}
  		return offset;
  	}
  		
  }
  