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.text.correction;
  
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.Collections;
  import java.util.Comparator;
  
  import org.eclipse.core.resources.IFile;
  import org.eclipse.core.runtime.CoreException;
  import org.eclipse.core.runtime.IStatus;
  import org.eclipse.jface.text.BadLocationException;
  import org.eclipse.jface.text.Document;
  import org.eclipse.jface.text.DocumentEvent;
  import org.eclipse.jface.text.IDocument;
  import org.eclipse.jface.text.IRegion;
  import org.eclipse.jface.text.Region;
  import org.eclipse.jface.text.templates.GlobalTemplateVariables;
  import org.eclipse.jface.text.templates.Template;
  import org.eclipse.swt.graphics.Image;
  import org.eclipse.ui.part.FileEditorInput;
  import org.eclipse.wst.jsdt.core.IJavaScriptUnit;
  import org.eclipse.wst.jsdt.core.JavaScriptModelException;
  import org.eclipse.wst.jsdt.core.dom.Statement;
  import org.eclipse.wst.jsdt.internal.corext.template.java.CompilationUnitContext;
  import org.eclipse.wst.jsdt.internal.corext.template.java.CompilationUnitContextType;
  import org.eclipse.wst.jsdt.internal.corext.template.java.JavaContextType;
  import org.eclipse.wst.jsdt.internal.corext.util.Messages;
  import org.eclipse.wst.jsdt.internal.ui.JavaScriptPlugin;
  import org.eclipse.wst.jsdt.internal.ui.JavaPluginImages;
  import org.eclipse.wst.jsdt.internal.ui.JavaUIStatus;
  import org.eclipse.wst.jsdt.internal.ui.text.template.contentassist.SurroundWithTemplateProposal;
  import org.eclipse.wst.jsdt.internal.ui.text.template.contentassist.TemplateProposal;
  import org.eclipse.wst.jsdt.ui.JavaScriptUI;
  import org.eclipse.wst.jsdt.ui.text.java.IInvocationContext;
  import org.eclipse.wst.jsdt.ui.text.java.IJavaCompletionProposal;
  import org.eclipse.wst.jsdt.ui.text.java.IProblemLocation;
  import org.eclipse.wst.jsdt.ui.text.java.IQuickAssistProcessor;
  
  import com.ibm.icu.text.Collator;
  
  
  /**
   * Quick template processor.
   */
  public class QuickTemplateProcessor implements IQuickAssistProcessor {
  
  	private static final String $_LINE_SELECTION= "${" + GlobalTemplateVariables.LineSelection.NAME + "}"; //$NON-NLS-1$ //$NON-NLS-2$
  
  	public QuickTemplateProcessor() {
  	}
  
  	/* (non-Javadoc)
  	 * @see org.eclipse.wst.jsdt.internal.ui.text.correction.IAssistProcessor#hasAssists(org.eclipse.wst.jsdt.internal.ui.text.correction.IAssistContext)
  	 */
  	public boolean hasAssists(IInvocationContext context) throws CoreException {
  		IJavaScriptUnit cu= context.getCompilationUnit();
  		IDocument document= getDocument(cu);
  
  		int offset= context.getSelectionOffset();
  		int length= context.getSelectionLength();
  		if (length == 0) {
  			return false;
  		}
  
  		try {
  			int startLine= document.getLineOfOffset(offset);
  			int endLine= document.getLineOfOffset(offset + length);
  			IRegion region= document.getLineInformation(endLine);
  			return startLine  < endLine || length > 0 && offset == region.getOffset() && length == region.getLength();
  		} catch (BadLocationException e) {
  			return false;
  		}
  	}
  
  	/* (non-Javadoc)
  	 * @see org.eclipse.wst.jsdt.internal.ui.text.correction.IAssistProcessor#getAssists(org.eclipse.wst.jsdt.internal.ui.text.correction.IAssistContext, org.eclipse.wst.jsdt.internal.ui.text.correction.IProblemLocation[])
  	 */
  	public IJavaCompletionProposal[] getAssists(IInvocationContext context, IProblemLocation[] locations) throws CoreException {
  		if (locations != null && locations.length > 0) {
  			return new IJavaCompletionProposal[0];
  		}
  
  		try {
  			int offset= context.getSelectionOffset();
  			int length= context.getSelectionLength();
  			if (length == 0) {
  				return null;
  			}
  
  			IJavaScriptUnit cu= context.getCompilationUnit();
  			IDocument document= getDocument(cu);
  
  			// test if selection is either a full line or spans over multiple lines
  			int startLine= document.getLineOfOffset(offset);
  			int endLine= document.getLineOfOffset(offset + length);
  			IRegion endLineRegion= document.getLineInformation(endLine);
  			//if end position is at start of line, set it back to the previous line's end
  			if (endLine > startLine && endLineRegion.getOffset() == offset + length) {
  				endLine--;
  				endLineRegion= document.getLineInformation(endLine);
  				length= endLineRegion.getOffset() + endLineRegion.getLength() - offset;
  			}
  			if (startLine  == endLine) {
  				if (length == 0 || offset != endLineRegion.getOffset() || length != endLineRegion.getLength()) {
  					AssistContext invocationContext= new AssistContext(cu, offset, length);
  					if (!SurroundWith.isApplicable(invocationContext))
  						return null;
  				}
  			} else {
  				// expand selection
  				offset= document.getLineOffset(startLine);
  				length= endLineRegion.getOffset() + endLineRegion.getLength() - offset;
  			}
  
  			ArrayList resultingCollections= new ArrayList();
  			collectSurroundTemplates(document, cu, offset, length, resultingCollections);
  			sort(resultingCollections);
  			return (IJavaCompletionProposal[]) resultingCollections.toArray(new IJavaCompletionProposal[resultingCollections.size()]);
  		} catch (BadLocationException e) {
  			throw new CoreException(JavaUIStatus.createError(IStatus.ERROR, "", e)); //$NON-NLS-1$
  		}
  	}
  
  	private void sort(ArrayList proposals) {
  		Collections.sort(proposals, new Comparator() {
  			public int compare(Object o1, Object o2) {
  				IJavaCompletionProposal p1= (IJavaCompletionProposal)o1;
  				IJavaCompletionProposal p2= (IJavaCompletionProposal)o2;
  				return Collator.getInstance().compare(p1.getDisplayString(), p2.getDisplayString());
  			}
  		});
  	}
  
  	private IDocument getDocument(IJavaScriptUnit cu) throws JavaScriptModelException {
  		IFile file= (IFile) cu.getResource();
  		IDocument document= JavaScriptUI.getDocumentProvider().getDocument(new FileEditorInput(file));
  		if (document == null) {
  			return new Document(cu.getSource()); // only used by test cases
  		}
  		return document;
  	}
  
  	private void collectSurroundTemplates(IDocument document, IJavaScriptUnit cu, int offset, int length, Collection result) throws BadLocationException, CoreException {
  		CompilationUnitContextType contextType= (CompilationUnitContextType) JavaScriptPlugin.getDefault().getTemplateContextRegistry().getContextType(JavaContextType.NAME);
  		CompilationUnitContext context= contextType.createContext(document, offset, length, cu);
  		context.setVariable("selection", document.get(offset, length)); //$NON-NLS-1$
  		context.setForceEvaluation(true);
  
  		int start= context.getStart();
  		int end= context.getEnd();
  		IRegion region= new Region(start, end - start);
  
  		AssistContext invocationContext= new AssistContext(cu, start, end - start);
  		Statement[] selectedStatements= SurroundWith.getSelectedStatements(invocationContext);
  		
  		Template[] templates= JavaScriptPlugin.getDefault().getTemplateStore().getTemplates();
  		for (int i= 0; i != templates.length; i++) {
  			Template currentTemplate= templates[i];
  			if (context.canEvaluate(currentTemplate) && currentTemplate.getContextTypeId().equals(JavaContextType.NAME) && currentTemplate.getPattern().indexOf($_LINE_SELECTION) != -1) {
  				// TODO using jdt proposals for the moment, as jdt expects IJavaCompletionProposals
  				
  				if (selectedStatements != null) {
  					Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
  					TemplateProposal proposal= new SurroundWithTemplateProposal(cu, currentTemplate, context, region, image, selectedStatements);
  					String[] arg= new String[] { currentTemplate.getName(), currentTemplate.getDescription() };
  					proposal.setDisplayString(Messages.format(CorrectionMessages.QuickTemplateProcessor_surround_label, arg));
  					result.add(proposal);
  				} else {
  					TemplateProposal proposal= new TemplateProposal(currentTemplate, context, region, JavaPluginImages.get(JavaPluginImages.IMG_OBJS_TEMPLATE)) {
  						/**
  						 * {@inheritDoc}
  						 */
  						public boolean validate(IDocument doc, int off, DocumentEvent event) {
  							return false;
  						}
  					};
  					String[] arg= new String[] { currentTemplate.getName(), currentTemplate.getDescription() };
  					proposal.setDisplayString(Messages.format(CorrectionMessages.QuickTemplateProcessor_surround_label, arg));
  					result.add(proposal);
  				}
  			}
  		}
  	}
  
  }
  