content: /**
   *  Copyright (c) 2013-2016 Angelo ZERR.
   *  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
   */
  package tern.eclipse.ide.linter.internal.core.validation;
  
  import org.eclipse.core.resources.IProject;
  import org.eclipse.core.resources.IResource;
  import org.eclipse.core.runtime.CoreException;
  import org.eclipse.core.runtime.IProgressMonitor;
  import org.eclipse.core.runtime.IStatus;
  import org.eclipse.core.runtime.Status;
  import org.eclipse.core.runtime.jobs.ISchedulingRule;
  import org.eclipse.wst.validation.AbstractValidator;
  import org.eclipse.wst.validation.ValidationResult;
  import org.eclipse.wst.validation.ValidationState;
  import org.eclipse.wst.validation.internal.core.ValidationException;
  import org.eclipse.wst.validation.internal.provisional.core.IReporter;
  import org.eclipse.wst.validation.internal.provisional.core.IValidationContext;
  import org.eclipse.wst.validation.internal.provisional.core.IValidatorJob;
  
  import tern.TernResourcesManager;
  import tern.eclipse.ide.core.IIDETernProject;
  import tern.eclipse.ide.core.IIDETernScriptPathReporter;
  import tern.eclipse.ide.core.IScopeContext;
  import tern.eclipse.ide.core.TernCorePlugin;
  import tern.eclipse.ide.linter.core.validation.TernValidationHelper;
  import tern.eclipse.ide.linter.internal.core.Trace;
  
  /**
   * WTP Tern Validator V2 to validate JavaScript (HTML, JSP, JS etc files). This
   * validator can be called when project is Build or Validate at hand (with
   * Validate context menu).
   *
   */
  public class TernValidator extends AbstractValidator implements IValidatorJob {
  
  	private static final String TERN_VALIDATOR_CONTEXT = "tern.eclipse.ide.linter.core.validatorContext"; //$NON-NLS-1$
  
  	/**
  	 * Perform the validation using version 2 of the validation framework.
  	 */
  	@Override
  	public ValidationResult validate(IResource resource, int kind, ValidationState state, IProgressMonitor monitor) {
  		ValidationResult result = new ValidationResult();
  		TernValidatorContext context = getTernContext(state, false);
  		if (context != null) {
  			// It's a tern project
  			IIDETernProject ternProject = context.getTernProject();
  			if (isInScope(resource, ternProject, context)) {
  				IReporter reporter = result.getReporter(monitor);
  				// Validate is called for each file, the synchronization of tern
  				// file must be done for :
  				// 1) the first JavaScript file which must be validated.
  				// 2) for any HTML file because it is deleted from the tern
  				// server.
  				boolean jsFile = TernResourcesManager.isJSFile(resource);
  				boolean synch = !jsFile || context.isSynch();
  				TernValidationHelper.validate(resource, ternProject, true, synch, false, reporter, this);
  				if (jsFile) {
  					context.setSynch(false);
  				}
  			}
  		}
  		return result;
  	}
  
  	private boolean isInScope(IResource resource, IIDETernProject ternProject, IScopeContext context) {
  		boolean inScope = ternProject.isInScope(resource, context);
  		IIDETernScriptPathReporter reporter = ternProject.getScriptPathReporter();
  		if (reporter != null) {
  			reporter.validate(resource.getFullPath(), inScope);
  		}
  		return inScope;
  	}
  
  	@Override
  	public void validationStarting(IProject project, ValidationState state, IProgressMonitor monitor) {
  		if (project != null && TernCorePlugin.hasTernNature(project)) {
  			try {
  				IIDETernProject ternProject = TernCorePlugin.getTernProject(project, false);
  				if (ternProject.getLinters().length > 0) {
  					TernValidatorContext context = getTernContext(state, true);
  					setupValidation(context, ternProject);
  					state.put(TERN_VALIDATOR_CONTEXT, context);
  					super.validationStarting(project, state, monitor);
  				}
  			} catch (CoreException e) {
  				Trace.trace(Trace.SEVERE, "Error while tern start validation.", e);
  			}
  		}
  	}
  
  	@Override
  	public void validationFinishing(IProject project, ValidationState state, IProgressMonitor monitor) {
  		if (project != null && TernCorePlugin.hasTernNature(project)) {
  			super.validationFinishing(project, state, monitor);
  			TernValidatorContext context = getTernContext(state, false);
  			if (context != null) {
  				state.put(TERN_VALIDATOR_CONTEXT, null);
  			}
  		}
  	}
  
  	@Override
  	public void cleanup(IReporter reporter) {
  		// do nothing
  	}
  
  	@Override
  	public void validate(IValidationContext context, IReporter reporter) throws ValidationException {
  		// It seems that it is never called?
  	}
  
  	@Override
  	public ISchedulingRule getSchedulingRule(IValidationContext context) {
  		return null;
  	}
  
  	@Override
  	public IStatus validateInJob(IValidationContext helper, IReporter reporter) throws ValidationException {
  		IStatus status = Status.OK_STATUS;
  		validate(helper, reporter);
  		return status;
  	}
  
  	protected void setupValidation(TernValidatorContext context, IIDETernProject ternProject) {
  		context.setTernProject(ternProject);
  	}
  
  	/**
  	 * Get the nested validation context.
  	 * 
  	 * @param state
  	 *            the validation state.
  	 * @param create
  	 *            when true, a new context will be created if one is not found
  	 * @return the nested validation context.
  	 */
  	protected TernValidatorContext getTernContext(ValidationState state, boolean create) {
  		TernValidatorContext context = (TernValidatorContext) state.get(TERN_VALIDATOR_CONTEXT);
  		if (context != null) {
  			return context;
  		}
  		if (create) {
  			return new TernValidatorContext();
  		}
  		return null;
  	}
  
  }
  