content: /**
   *  Copyright (c) 2013-2016 Angelo ZERR and Genuitec LLC.
   *  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:
   *  Angelo Zerr <angelo.zerr@gmail.com> - initial API and implementation
   *  Piotr Tomiak <piotr@genuitec.com> - unified completion proposals calculation
   */
  package tern.eclipse.ide.ui.contentassist;
  
  import java.util.List;
  
  import org.eclipse.core.resources.IProject;
  import org.eclipse.core.resources.ProjectScope;
  import org.eclipse.core.runtime.Platform;
  import org.eclipse.core.runtime.preferences.DefaultScope;
  import org.eclipse.core.runtime.preferences.IPreferencesService;
  import org.eclipse.core.runtime.preferences.IScopeContext;
  import org.eclipse.core.runtime.preferences.InstanceScope;
  import org.eclipse.jface.text.contentassist.ICompletionProposal;
  
  import tern.ITernFile;
  import tern.ITernProject;
  import tern.eclipse.ide.internal.ui.preferences.TernUIPreferenceConstants;
  import tern.eclipse.ide.ui.TernUIPlugin;
  import tern.server.protocol.IJSONObjectHelper;
  import tern.server.protocol.completions.ITernCompletionCollector;
  import tern.server.protocol.completions.TernCompletionProposalRec;
  
  /**
   * Tern collector which creates {@link JSTernCompletionProposal}.
   * 
   */
  public class JSTernCompletionCollector implements ITernCompletionCollector {
  
  	protected final List<ICompletionProposal> proposals;
  	private boolean generateAnonymousFunction;
  	private boolean expandFunction;
  	private String indentChars;
  	private final ITernFile ternFile;
  	private final ITernProject ternProject;
  
  	public JSTernCompletionCollector(List<ICompletionProposal> proposals,
  			int startOffset, ITernFile ternFile, ITernProject ternProject) {
  		this.proposals = proposals;
  		this.ternFile = ternFile;
  		this.ternProject = ternProject;
  
  		IPreferencesService preferencesService = Platform
  				.getPreferencesService();
  		
  		IProject project = (IProject) ternProject.getAdapter(IProject.class);
  		
  		IScopeContext[] lookupOrder;
  		
  		if (project != null) {
  			lookupOrder = new IScopeContext[] {
  					new ProjectScope(project),
  					InstanceScope.INSTANCE, 
  					DefaultScope.INSTANCE
  			};
  		} else {
  			lookupOrder = new IScopeContext[] {
  					InstanceScope.INSTANCE, 
  					DefaultScope.INSTANCE
  			};
  		}
  
  		generateAnonymousFunction = preferencesService
  				.getBoolean(
  						TernUIPlugin.getDefault().getBundle().getSymbolicName(),
  						TernUIPreferenceConstants.GENERATE_ANONYMOUS_FUNCTION_CONTENT_ASSIST,
  						true, lookupOrder);
  
  		int indentSize = preferencesService.getInt(TernUIPlugin.getDefault()
  				.getBundle().getSymbolicName(),
  				TernUIPreferenceConstants.INDENT_SIZE_CONTENT_ASSIST,
  				TernUIPreferenceConstants.INDENT_SIZE_CONTENT_ASSIST_DEFAULT,
  				lookupOrder);
  		boolean indentWithTabs = preferencesService.getBoolean(TernUIPlugin
  				.getDefault().getBundle().getSymbolicName(),
  				TernUIPreferenceConstants.INDENT_TABS_CONTENT_ASSIST,
  				TernUIPreferenceConstants.INDENT_TABS_CONTENT_ASSIST_DEFAULT,
  				lookupOrder);
  		indentChars = getIndentChars(indentWithTabs, indentSize);
  
  		expandFunction = preferencesService.getBoolean(TernUIPlugin
  				.getDefault().getBundle().getSymbolicName(),
  				TernUIPreferenceConstants.EXPAND_FUNCTION_CONTENT_ASSIST, true,
  				lookupOrder);
  	}
  
  	private String getIndentChars(boolean indentWithTabs, int indentSize) {
  		StringBuilder indent = new StringBuilder();
  		for (int i = 0; i < indentSize; i++) {
  			indent.append(indentWithTabs ? JSTernCompletionProposal.TAB
  					: JSTernCompletionProposal.SPACE);
  		}
  		return indent.toString();
  	}
  
  	@Override
  	public void addProposal(TernCompletionProposalRec proposalItem,
  			Object completion, IJSONObjectHelper jsonObjectHelper) {
  		JSTernCompletionProposal proposal = internalCreateProposal(proposalItem);
  		if (proposal.isFunction()) {
  			// Add the function reference
  			proposals
  					.add(internalCreateProposal(proposalItem.changeType("fn")));
  			if (!proposalItem.isSpecifier) {
  				proposals.add(proposal);
  			}
  		} else {
  			proposals.add(proposal);
  		}	
  		if (!proposalItem.isSpecifier && expandFunction) {
  			// expand functions if the functions contains several "optionnal"
  			// parameters.
  			// ex : the expansion of
  			// "fn(selector: string, context?: frameElement)"
  			// returns an array of functions
  			//
  			String[] functions = proposal.expand();
  			if (functions != null) {
  				for (int i = 0; i < functions.length; i++) {
  					proposals.add(internalCreateProposal(proposalItem
  							.changeType(functions[i])));
  				}
  			}
  		}		
  	}
  
  	private JSTernCompletionProposal internalCreateProposal(
  			TernCompletionProposalRec proposalItem) {
  		JSTernCompletionProposal proposal = createProposal(proposalItem);
  		proposal.setGenerateAnonymousFunction(generateAnonymousFunction);
  		proposal.setIndentChars(indentChars);
  		// TODO manage that with preferences
  		proposal.setGenerateObjectValue(true);
  
  		proposal.setTernFile(ternFile);
  		proposal.setTernProject(ternProject);
  		return proposal;
  	}
  
  	/**
  	 * Completion proposal factory.
  	 * 
  	 * @param proposalItem
  	 * 
  	 * @return
  	 */
  	protected JSTernCompletionProposal createProposal(
  			TernCompletionProposalRec proposalItem) {
  		return new JSTernCompletionProposal(proposalItem);
  	}
  }
  