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> - refactoring of file management API
   *  								  - asynchronous file upload
   *                                    - partial file upload
   */
  package tern.eclipse.ide.internal.core.resources;
  
  import java.io.IOException;
  
  import org.eclipse.core.resources.IFile;
  import org.eclipse.jface.text.IDocument;
  
  import com.eclipsesource.json.JsonValue;
  
  import tern.ITernFile;
  import tern.ITernProject;
  import tern.resources.ITernFileUploader;
  import tern.resources.TernFileSynchronizer;
  import tern.server.protocol.TernDoc;
  import tern.server.protocol.TernFile;
  import tern.server.protocol.TernQuery;
  
  /**
   * Extension of {@link TernFileManager} to works with Eclipse {@link IFile}
   * 
   */
  public class IDETernFileSynchronizer extends TernFileSynchronizer {
  
  	protected static final int BIG_FILE = 500;
  	
  	/**
  	 * Constructor of file manager with the owner Eclipse project.
  	 */
  	public IDETernFileSynchronizer(ITernProject project) {
  		super(project);
  	}
  
  	@Override
  	protected ITernFileUploader createTernFileUploader() {
  		return new IDETernFileUploader(getProject());
  	}
  
  	@Override
  	protected void addJSFile(TernDoc doc, ITernFile file) throws IOException {
  		TernQuery query = doc.getQuery();
  		String fileName = file.getFullName(getProject());
  		query.setFile(fileName);
  		IDocument document = (IDocument) file.getAdapter(IDocument.class);
  		//include file as a part of the tern doc
  		if (document != null) {
  			String text = document.get();
  			String oldText = getSentFileContent(fileName);
  			if (text.equals(oldText)) {
  				if (!getTernFileUploader().cancel(fileName)) {
  					//no need to synchronize as file has already been sent to the server
  					return;
  				}
  				//continue to include a whole file in the request
  			} else if (oldText != null &&
  					//do partial content assist only in big files
  					document.getNumberOfLines() > BIG_FILE) {
  				try {
  					int start;
  					for (start = 0; 
  							start < text.length() && start < oldText.length() &&
  							text.charAt(start) == oldText.charAt(start); 
  							start++);
  					int end;
  					int offset = oldText.length() - text.length();
  					for (end = text.length() - 1; 
  							end > 0 && end + offset > 0 &&
  							text.charAt(end) == oldText.charAt(end + offset);
  							end--);
  					int startLine = document.getLineOfOffset(start);
  					int endLine = document.getLineOfOffset(end);
  
  					int selEndLine;
  					if (query.get("end") != null) { //$NON-NLS-1$
  						selEndLine = document.getLineOfOffset(query.get("end").asInt()); //$NON-NLS-1$
  					} else {
  						selEndLine = -1;
  					}
  					int selStartLine;
  					if (query.get("start") != null) { //$NON-NLS-1$
  						selStartLine = document.getLineOfOffset(query.get("start").asInt()); //$NON-NLS-1$
  					} else {
  						selStartLine = selEndLine;
  					}
  					
  					if (startLine <= endLine && 
  							endLine - startLine < 100 &&
  							//Selection should be part of modified lines. 
  							//Tolerate 2 lines before and 2 lines after.
  							!(selStartLine-2 > endLine || selEndLine+2 < startLine)) {
  						startLine -= 50;
  						if (startLine < 0) {
  							startLine = 0;
  						}
  						endLine += 20;
  						if (endLine >= document.getNumberOfLines()) {
  							endLine = document.getNumberOfLines() - 1;
  						}
  						
  						start = document.getLineOffset(startLine);
  						end = document.getLineOffset(endLine);
  						
  						String textPart = document.get(start, end-start);
  						
  						doc.addFile(new TernFile(fileName, textPart, null, start));
  						query.setFile("#" + (doc.getFiles().size() - 1)); //$NON-NLS-1$
  						JsonValue val = query.get("end"); //$NON-NLS-1$
  						if (val != null) {
  							query.setEnd(val.asInt() - start);
  						}
  						val = query.get("start"); //$NON-NLS-1$
  						if (val != null) {
  							query.add("start", val.asInt() - start); //$NON-NLS-1$
  						}
  						//all's fine - return
  						return;
  					}
  				} catch (Exception e) {
  					getProject().handleException(e);
  				}
  			}
  		}
  		//fallback - include whole file in the request
  		TernFile tf = file.toTernServerFile(getProject());
  		doc.addFile(tf);
  	}
  	
  }
  