/*******************************************************************************
 * 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
 *     Matt Chapman, mpchapman@gmail.com - 89977 Make JDT .java agnostic
 *******************************************************************************/

package org.eclipse.wst.jsdt.internal.ui.text.correction;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspaceRunnable;
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.Path;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.text.IDocument;
import org.eclipse.ltk.core.refactoring.CompositeChange;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.PreferencesUtil;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.progress.IProgressService;
import org.eclipse.wst.jsdt.core.IIncludePathEntry;
import org.eclipse.wst.jsdt.core.IJavaScriptUnit;
import org.eclipse.wst.jsdt.core.IJavaScriptElement;
import org.eclipse.wst.jsdt.core.IJavaScriptProject;
import org.eclipse.wst.jsdt.core.IPackageDeclaration;
import org.eclipse.wst.jsdt.core.IPackageFragment;
import org.eclipse.wst.jsdt.core.IPackageFragmentRoot;
import org.eclipse.wst.jsdt.core.IType;
import org.eclipse.wst.jsdt.core.JavaScriptConventions;
import org.eclipse.wst.jsdt.core.JavaScriptCore;
import org.eclipse.wst.jsdt.core.JavaScriptModelException;
import org.eclipse.wst.jsdt.core.Signature;
import org.eclipse.wst.jsdt.core.dom.ASTNode;
import org.eclipse.wst.jsdt.core.dom.AbstractTypeDeclaration;
import org.eclipse.wst.jsdt.core.dom.JavaScriptUnit;
import org.eclipse.wst.jsdt.core.dom.IBinding;
import org.eclipse.wst.jsdt.core.dom.ImportDeclaration;
import org.eclipse.wst.jsdt.core.dom.Modifier;
import org.eclipse.wst.jsdt.core.dom.Name;
import org.eclipse.wst.jsdt.core.dom.SimpleName;
import org.eclipse.wst.jsdt.core.dom.Type;
import org.eclipse.wst.jsdt.core.search.IJavaScriptSearchConstants;
import org.eclipse.wst.jsdt.core.search.IJavaScriptSearchScope;
import org.eclipse.wst.jsdt.core.search.SearchEngine;
import org.eclipse.wst.jsdt.core.search.SearchPattern;
import org.eclipse.wst.jsdt.core.search.TypeNameMatch;
import org.eclipse.wst.jsdt.internal.corext.dom.ASTNodes;
import org.eclipse.wst.jsdt.internal.corext.fix.CleanUpConstants;
import org.eclipse.wst.jsdt.internal.corext.fix.IFix;
import org.eclipse.wst.jsdt.internal.corext.fix.UnusedCodeFix;
import org.eclipse.wst.jsdt.internal.corext.refactoring.changes.AddToClasspathChange;
import org.eclipse.wst.jsdt.internal.corext.refactoring.changes.CreatePackageChange;
import org.eclipse.wst.jsdt.internal.corext.refactoring.changes.MoveCompilationUnitChange;
import org.eclipse.wst.jsdt.internal.corext.refactoring.changes.RenameCompilationUnitChange;
import org.eclipse.wst.jsdt.internal.corext.util.JavaModelUtil;
import org.eclipse.wst.jsdt.internal.corext.util.Messages;
import org.eclipse.wst.jsdt.internal.corext.util.TypeNameMatchCollector;
import org.eclipse.wst.jsdt.internal.ui.JavaScriptPlugin;
import org.eclipse.wst.jsdt.internal.ui.JavaPluginImages;
import org.eclipse.wst.jsdt.internal.ui.actions.WorkbenchRunnableAdapter;
import org.eclipse.wst.jsdt.internal.ui.fix.UnusedCodeCleanUp;
import org.eclipse.wst.jsdt.internal.ui.javaeditor.JavaEditor;
import org.eclipse.wst.jsdt.internal.ui.preferences.BuildPathsPropertyPage;
import org.eclipse.wst.jsdt.internal.ui.util.CoreUtility;
import org.eclipse.wst.jsdt.internal.ui.wizards.buildpaths.CPListElement;
import org.eclipse.wst.jsdt.launching.IVMInstall;
import org.eclipse.wst.jsdt.launching.IVMInstall2;
import org.eclipse.wst.jsdt.launching.IVMInstallType;
import org.eclipse.wst.jsdt.launching.JavaRuntime;
import org.eclipse.wst.jsdt.ui.JavaScriptElementLabels;
import org.eclipse.wst.jsdt.ui.actions.OrganizeImportsAction;
import org.eclipse.wst.jsdt.ui.text.java.IInvocationContext;
import org.eclipse.wst.jsdt.ui.text.java.IProblemLocation;

public class ReorgCorrectionsSubProcessor {

	public static void getWrongTypeNameProposals(IInvocationContext context, IProblemLocation problem, Collection proposals) throws CoreException {
		IJavaScriptUnit cu= context.getCompilationUnit();
		boolean isLinked= cu.getResource().isLinked();

		IJavaScriptProject javaProject= cu.getJavaScriptProject();
		String sourceLevel= javaProject.getOption(JavaScriptCore.COMPILER_SOURCE, true);
		String compliance= javaProject.getOption(JavaScriptCore.COMPILER_COMPLIANCE, true);
		
		JavaScriptUnit root= context.getASTRoot();
		
		ASTNode coveredNode= problem.getCoveredNode(root);
		if (!(coveredNode instanceof SimpleName))
			return;		
		
		ASTNode parentType= coveredNode.getParent();
		if (!(parentType instanceof AbstractTypeDeclaration))
			return;
		
		String currTypeName= ((SimpleName) coveredNode).getIdentifier();
		String newTypeName= JavaScriptCore.removeJavaScriptLikeExtension(cu.getElementName());
				
		boolean hasOtherPublicTypeBefore= false;
		
		boolean found= false;
		List types= root.types();
		for (int i= 0; i < types.size(); i++) {
			 AbstractTypeDeclaration curr= (AbstractTypeDeclaration) types.get(i);
			 if (parentType != curr) {
				 if (newTypeName.equals(curr.getName().getIdentifier())) {
					 return;
				 }
				 if (!found && Modifier.isPublic(curr.getModifiers())) {
					 hasOtherPublicTypeBefore= true;
				 }
			 } else {
				 found= true;
			 }
		 }
		if (!JavaScriptConventions.validateJavaScriptTypeName(newTypeName, sourceLevel, compliance).matches(IStatus.ERROR)) {
			proposals.add(new CorrectMainTypeNameProposal(cu, context, currTypeName, newTypeName, 5));
		}
		
		if (!hasOtherPublicTypeBefore) {
			String newCUName= JavaModelUtil.getRenamedCUName(cu, currTypeName);
			IJavaScriptUnit newCU= ((IPackageFragment) (cu.getParent())).getJavaScriptUnit(newCUName);
			if (!newCU.exists() && !isLinked && !JavaScriptConventions.validateCompilationUnitName(newCUName, sourceLevel, compliance).matches(IStatus.ERROR)) {
				RenameCompilationUnitChange change= new RenameCompilationUnitChange(cu, newCUName);
	
				// rename CU
				String label= Messages.format(CorrectionMessages.ReorgCorrectionsSubProcessor_renamecu_description, newCUName);
				proposals.add(new ChangeCorrectionProposal(label, change, 6, JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_RENAME)));
			}
		}
	}

	public static void getWrongPackageDeclNameProposals(IInvocationContext context, IProblemLocation problem, Collection proposals) throws CoreException {
		IJavaScriptUnit cu= context.getCompilationUnit();
		boolean isLinked= cu.getResource().isLinked();

		// correct package declaration
		int relevance= cu.getPackageDeclarations().length == 0 ? 7 : 5; // bug 38357
		proposals.add(new CorrectPackageDeclarationProposal(cu, problem, relevance));

		// move to package
		IPackageDeclaration[] packDecls= cu.getPackageDeclarations();
		String newPackName= packDecls.length > 0 ? packDecls[0].getElementName() : ""; //$NON-NLS-1$

		IPackageFragmentRoot root= JavaModelUtil.getPackageFragmentRoot(cu);
		IPackageFragment newPack= root.getPackageFragment(newPackName);

		IJavaScriptUnit newCU= newPack.getJavaScriptUnit(cu.getElementName());
		if (!newCU.exists() && !isLinked) {
			String label;
			if (newPack.isDefaultPackage()) {
				label= Messages.format(CorrectionMessages.ReorgCorrectionsSubProcessor_movecu_default_description, cu.getElementName());
			} else {
				label= Messages.format(CorrectionMessages.ReorgCorrectionsSubProcessor_movecu_description, new Object[] { cu.getElementName(), newPack.getElementName() });
			}
			CompositeChange composite= new CompositeChange(label);
			composite.add(new CreatePackageChange(newPack));
			composite.add(new MoveCompilationUnitChange(cu, newPack));

			proposals.add(new ChangeCorrectionProposal(label, composite, 6, JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_MOVE)));
		}
	}

	public static void removeImportStatementProposals(IInvocationContext context, IProblemLocation problem, Collection proposals) throws CoreException {
		IFix fix= UnusedCodeFix.createRemoveUnusedImportFix(context.getASTRoot(), problem);
		if (fix != null) {
			Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_DELETE_IMPORT);
			Map options= new Hashtable();
			options.put(CleanUpConstants.REMOVE_UNUSED_CODE_IMPORTS, CleanUpConstants.TRUE);
			FixCorrectionProposal proposal= new FixCorrectionProposal(fix, new UnusedCodeCleanUp(options), 6, image, context);
			proposals.add(proposal);
		}
		
		final IJavaScriptUnit cu= context.getCompilationUnit();
		String name= CorrectionMessages.ReorgCorrectionsSubProcessor_organizeimports_description;
		ChangeCorrectionProposal proposal= new ChangeCorrectionProposal(name, null, 5, JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE)) {
			public void apply(IDocument document) {
				IEditorInput input= new FileEditorInput((IFile) cu.getResource());
				IWorkbenchPage p= JavaScriptPlugin.getActivePage();
				if (p == null) {
					return;
				}
				IEditorPart part= p.findEditor(input);
				if (part instanceof JavaEditor) {
					OrganizeImportsAction action= new OrganizeImportsAction((JavaEditor) part);
					action.run(cu);
				}
			}
		};
		proposals.add(proposal);
	}

	public static void importNotFoundProposals(IInvocationContext context, IProblemLocation problem, Collection proposals) throws CoreException {
		IJavaScriptUnit cu= context.getCompilationUnit();
		IJavaScriptProject project= cu.getJavaScriptProject();

		ASTNode selectedNode= problem.getCoveringNode(context.getASTRoot());
		if (selectedNode != null) {
			ImportDeclaration importDeclaration= (ImportDeclaration) ASTNodes.getParent(selectedNode, ASTNode.IMPORT_DECLARATION);
			if (importDeclaration == null) {
				return;
			}
			if (!importDeclaration.isOnDemand()) {
				int kind= JavaModelUtil.is50OrHigher(cu.getJavaScriptProject()) ? SimilarElementsRequestor.REF_TYPES : SimilarElementsRequestor.CLASSES | SimilarElementsRequestor.INTERFACES;
				UnresolvedElementsSubProcessor.addNewTypeProposals(cu, importDeclaration.getName(), kind, 5, proposals);
			}
			
			
			String name= ASTNodes.asString(importDeclaration.getName());
			char[] packageName;
			char[] typeName= null;
			if (importDeclaration.isOnDemand()) {
				packageName= name.toCharArray();
			} else {
				packageName= Signature.getQualifier(name).toCharArray();
				typeName= Signature.getSimpleName(name).toCharArray();
			}
			IJavaScriptSearchScope scope= SearchEngine.createWorkspaceScope();
			ArrayList res= new ArrayList();
			TypeNameMatchCollector requestor= new TypeNameMatchCollector(res);
			int matchMode= SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE;
			new SearchEngine().searchAllTypeNames(packageName, matchMode, typeName,
					matchMode, IJavaScriptSearchConstants.TYPE, scope, requestor,
					IJavaScriptSearchConstants.WAIT_UNTIL_READY_TO_SEARCH, null);

			if (res.isEmpty()) {
				return;
			}
			HashSet addedClaspaths= new HashSet();
			for (int i= 0; i < res.size(); i++) {
				TypeNameMatch curr= (TypeNameMatch) res.get(i);
				IType type= curr.getType();
				if (type != null) {
					IPackageFragmentRoot root= (IPackageFragmentRoot) type.getAncestor(IJavaScriptElement.PACKAGE_FRAGMENT_ROOT);
					IIncludePathEntry entry= root.getRawIncludepathEntry();
					if (entry == null) {
						continue;
					}
					IJavaScriptProject other= root.getJavaScriptProject();
					int entryKind= entry.getEntryKind();
					if ((entry.isExported() || entryKind == IIncludePathEntry.CPE_SOURCE) && addedClaspaths.add(other)) {
						String[] args= { other.getElementName(), project.getElementName() };
						String label= Messages.format(CorrectionMessages.ReorgCorrectionsSubProcessor_addcp_project_description, args);
						IIncludePathEntry newEntry= JavaScriptCore.newProjectEntry(other.getPath());
						AddToClasspathChange change= new AddToClasspathChange(project, newEntry);
						if (change.validateClasspath()) {
							ChangeCorrectionProposal proposal= new ChangeCorrectionProposal(label, change, 8, JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE));
							proposals.add(proposal);
						}
					}
					if ((entryKind == IIncludePathEntry.CPE_LIBRARY || entryKind == IIncludePathEntry.CPE_VARIABLE || entryKind == IIncludePathEntry.CPE_CONTAINER) && addedClaspaths.add(entry)) {
						String label= getAddClasspathLabel(entry, root, project);
						if (label != null) {
							AddToClasspathChange change= new AddToClasspathChange(project, entry);
							if (change.validateClasspath()) {
								ChangeCorrectionProposal proposal= new ChangeCorrectionProposal(label, change, 7, JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE));
								proposals.add(proposal);
							}
						}
					}
				}
			}
		}
	}

	private static String getAddClasspathLabel(IIncludePathEntry entry, IPackageFragmentRoot root, IJavaScriptProject project) {
		switch (entry.getEntryKind()) {
			case IIncludePathEntry.CPE_LIBRARY:
				if (root.isArchive()) {
					String[] args= { JavaScriptElementLabels.getElementLabel(root, JavaScriptElementLabels.REFERENCED_ROOT_POST_QUALIFIED), project.getElementName() };
					return Messages.format(CorrectionMessages.ReorgCorrectionsSubProcessor_addcp_archive_description, args);
				} else {
					String[] args= { JavaScriptElementLabels.getElementLabel(root, JavaScriptElementLabels.REFERENCED_ROOT_POST_QUALIFIED), project.getElementName() };
					return Messages.format(CorrectionMessages.ReorgCorrectionsSubProcessor_addcp_classfolder_description, args);
				}
			case IIncludePathEntry.CPE_VARIABLE: {
					String[] args= { JavaScriptElementLabels.getElementLabel(root, 0), project.getElementName() };
					return Messages.format(CorrectionMessages.ReorgCorrectionsSubProcessor_addcp_variable_description, args);
				}
			case IIncludePathEntry.CPE_CONTAINER:
				try {
					String[] args= { JavaScriptElementLabels.getContainerEntryLabel(entry.getPath(), root.getJavaScriptProject()), project.getElementName() };
					return Messages.format(CorrectionMessages.ReorgCorrectionsSubProcessor_addcp_library_description, args);
				} catch (JavaScriptModelException e) {
					// ignore
				}
				break;
			}
		return null;
	}

	private static final class OpenBuildPathCorrectionProposal extends ChangeCorrectionProposal {
		private final IProject fProject;
		private final IBinding fReferencedType;
		private OpenBuildPathCorrectionProposal(IProject project, String label, int relevance, IBinding referencedType) {
			super(label, null, relevance, null);
			fProject= project;
			fReferencedType= referencedType;
			setImage(JavaPluginImages.get(JavaPluginImages.IMG_OBJS_ACCESSRULES_ATTRIB));
		}
		public void apply(IDocument document) {
			Map data= null;
			if (fReferencedType != null) {
				IJavaScriptElement elem= fReferencedType.getJavaElement();
				if (elem != null) {
					IPackageFragmentRoot root= (IPackageFragmentRoot) elem.getAncestor(IJavaScriptElement.PACKAGE_FRAGMENT_ROOT);
					if (root != null) {
						try {
							IIncludePathEntry entry= root.getRawIncludepathEntry();
							if (entry != null) {
								data= new HashMap(1);
								data.put(BuildPathsPropertyPage.DATA_REVEAL_ENTRY, entry);
								if (entry.getEntryKind() != IIncludePathEntry.CPE_CONTAINER) {
									data.put(BuildPathsPropertyPage.DATA_REVEAL_ATTRIBUTE_KEY, CPListElement.ACCESSRULES);
								}
							}
						} catch (JavaScriptModelException e) {
							// ignore
						}
					}
				}
			}
			PreferencesUtil.createPropertyDialogOn(JavaScriptPlugin.getActiveWorkbenchShell(), fProject, BuildPathsPropertyPage.PROP_ID, null, data).open();
		}
		public String getAdditionalProposalInfo() {
			return Messages.format(CorrectionMessages.ReorgCorrectionsSubProcessor_configure_buildpath_description, fProject.getName());
		}
	}

	private static final class ChangeTo50Compliance extends ChangeCorrectionProposal implements IWorkspaceRunnable {
		
		private final IJavaScriptProject fProject;
		private final boolean fChangeOnWorkspace;
		
		private Job fUpdateJob;
		private boolean f50JREFound;
		
		public ChangeTo50Compliance(String name, IJavaScriptProject project, boolean changeOnWorkspace, int relevance) {
			super(name, null, relevance, JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE));
			fProject= project;
			fChangeOnWorkspace= changeOnWorkspace;
			fUpdateJob= null;
			f50JREFound= false;
		}
		
		private boolean is50orGreaterVMInstall(IVMInstall install) {
			if (install instanceof IVMInstall2) {
				String compliance= JavaModelUtil.getCompilerCompliance((IVMInstall2) install, JavaScriptCore.VERSION_1_3);
				return JavaModelUtil.is50OrHigher(compliance);
			}
			return false;
		}
		
		private IVMInstall find50OrGreaterVMInstall() {
			IVMInstallType[] installTypes= JavaRuntime.getVMInstallTypes();
			for (int i= 0; i < installTypes.length; i++) {
				IVMInstall[] installs= installTypes[i].getVMInstalls();
				for (int k= 0; k < installs.length; k++) {
					if (is50orGreaterVMInstall(installs[k])) {
						return installs[k];
					}
				}
			}
			return null;
		}
		
		public void run(IProgressMonitor monitor) throws CoreException {
			boolean needsBuild= updateJRE(monitor);
			if (needsBuild) {
				fUpdateJob= CoreUtility.getBuildJob(fChangeOnWorkspace ? null : fProject.getProject());
			}
		}
		
		private boolean updateJRE( IProgressMonitor monitor) throws CoreException, JavaScriptModelException {
			try {
				IVMInstall vm50Install= find50OrGreaterVMInstall();
				f50JREFound= vm50Install != null;
				if (vm50Install != null) {
					IVMInstall install= JavaRuntime.getVMInstall(fProject); // can be null
					if (fChangeOnWorkspace) {
						monitor.beginTask(CorrectionMessages.ReorgCorrectionsSubProcessor_50_compliance_operation, 4);
						IVMInstall defaultVM= JavaRuntime.getDefaultVMInstall(); // can be null
						if (defaultVM != null && !defaultVM.equals(install)) {
							IPath newPath= new Path(JavaRuntime.JRE_CONTAINER);
							updateClasspath(newPath, new SubProgressMonitor(monitor, 1));
						} else {
							monitor.worked(1);
						}
						if (defaultVM == null || !is50orGreaterVMInstall(defaultVM)) {
							JavaRuntime.setDefaultVMInstall(vm50Install, new SubProgressMonitor(monitor, 3), true);
							return false;
						}
						return true;
					} else {
						if (install == null || !is50orGreaterVMInstall(install)) {
							IPath newPath= new Path(JavaRuntime.JRE_CONTAINER).append(vm50Install.getVMInstallType().getId()).append(vm50Install.getName());
							updateClasspath(newPath, monitor);
							return false;
						}
					}
				}
			} finally {
				monitor.done();
			}
			return true;
		}

		private void updateClasspath(IPath newPath, IProgressMonitor monitor) throws JavaScriptModelException {
			IIncludePathEntry[] classpath= fProject.getRawIncludepath();
			IPath jreContainerPath= new Path(JavaRuntime.JRE_CONTAINER);
			for (int i= 0; i < classpath.length; i++) {
				IIncludePathEntry curr= classpath[i];
				if (curr.getEntryKind() == IIncludePathEntry.CPE_CONTAINER && curr.getPath().matchingFirstSegments(jreContainerPath) > 0) {
					classpath[i]= JavaScriptCore.newContainerEntry(newPath, curr.getAccessRules(), curr.getExtraAttributes(), curr.isExported());
				}
			}
			fProject.setRawIncludepath(classpath, monitor);
		}
		
		/* (non-Javadoc)
		 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getAdditionalProposalInfo()
		 */
		public String getAdditionalProposalInfo() {
			StringBuffer message= new StringBuffer();
			if (fChangeOnWorkspace) {
				message.append(CorrectionMessages.ReorgCorrectionsSubProcessor_50_compliance_changeworkspace_description);
			} else {
				message.append(CorrectionMessages.ReorgCorrectionsSubProcessor_50_compliance_changeproject_description);
			}
			
			IVMInstall vm50Install= find50OrGreaterVMInstall();
			if (vm50Install != null) {
				try {
					IVMInstall install= JavaRuntime.getVMInstall(fProject); // can be null
					if (fChangeOnWorkspace) {
						IVMInstall defaultVM= JavaRuntime.getDefaultVMInstall(); // can be null
						if (defaultVM != null && !defaultVM.equals(install)) {
							message.append(CorrectionMessages.ReorgCorrectionsSubProcessor_50_compliance_changeProjectJREToDefault_description);
						}
						if (defaultVM == null || !is50orGreaterVMInstall(defaultVM)) {
							message.append(Messages.format(CorrectionMessages.ReorgCorrectionsSubProcessor_50_compliance_changeWorkspaceJRE_description, vm50Install.getName()));
						}
					} else {
						if (install == null || !is50orGreaterVMInstall(install)) {
							message.append(Messages.format(CorrectionMessages.ReorgCorrectionsSubProcessor_50_compliance_changeProjectJRE_description, vm50Install.getName()));
						}
					}
				} catch (CoreException e) {
					// ignore
				}
			}
			return message.toString();
		}
		
		/* (non-Javadoc)
		 * @see org.eclipse.jface.text.contentassist.ICompletionProposal#apply(IDocument)
		 */
		public void apply(IDocument document) {
			if (fChangeOnWorkspace) {
				Hashtable map= JavaScriptCore.getOptions();
				JavaModelUtil.set50CompilanceOptions(map);
				JavaScriptCore.setOptions(map);
			} else {
				Map map= fProject.getOptions(false);
				int optionsCount= map.size();
				JavaModelUtil.set50CompilanceOptions(map);
				if (map.size() > optionsCount) {
					// options have been added -> ensure that all compliance options from preference page set
					JavaModelUtil.setDefaultClassfileOptions(map, JavaScriptCore.VERSION_1_5);
				}
				fProject.setOptions(map);
			}
			try {
				IProgressService progressService= PlatformUI.getWorkbench().getProgressService();
				progressService.run(true, true, new WorkbenchRunnableAdapter(this));
			} catch (InvocationTargetException e) {
				JavaScriptPlugin.log(e);
			} catch (InterruptedException e) {
				return;
			}
			
			if (fUpdateJob != null) {
				fUpdateJob.schedule();
			}
			
			if (!f50JREFound) {
				MessageDialog.openInformation(JavaScriptPlugin.getActiveWorkbenchShell(), CorrectionMessages.ReorgCorrectionsSubProcessor_no_50jre_title, CorrectionMessages.ReorgCorrectionsSubProcessor_no_50jre_message);
			}
		}
	}

	public static void getNeed50ComplianceProposals(IInvocationContext context, IProblemLocation problem, Collection proposals) {
		IJavaScriptProject project= context.getCompilationUnit().getJavaScriptProject();
		
		String label1= CorrectionMessages.ReorgCorrectionsSubProcessor_50_project_compliance_description;
		proposals.add(new ChangeTo50Compliance(label1, project, false, 5));

		if (project.getOption(JavaScriptCore.COMPILER_COMPLIANCE, false) == null) {
			String label2= CorrectionMessages.ReorgCorrectionsSubProcessor_50_workspace_compliance_description;
			proposals.add(new ChangeTo50Compliance(label2, project, true, 6));
		}
	}

	public static void getIncorrectBuildPathProposals(IInvocationContext context, IProblemLocation problem, Collection proposals) {
		IProject project= context.getCompilationUnit().getJavaScriptProject().getProject();
		String label= CorrectionMessages.ReorgCorrectionsSubProcessor_configure_buildpath_label;
		OpenBuildPathCorrectionProposal proposal= new OpenBuildPathCorrectionProposal(project, label, 5, null);
		proposals.add(proposal);
	}

	public static void getAccessRulesProposals(IInvocationContext context, IProblemLocation problem, Collection proposals) {
		IBinding referencedElement= null;
		ASTNode node= problem.getCoveredNode(context.getASTRoot());
		if (node instanceof Type) {
			referencedElement= ((Type) node).resolveBinding();
		} else if (node instanceof Name) {
			referencedElement= ((Name) node).resolveBinding();
		}
		IProject project= context.getCompilationUnit().getJavaScriptProject().getProject();
		String label= CorrectionMessages.ReorgCorrectionsSubProcessor_accessrules_description;
		OpenBuildPathCorrectionProposal proposal= new OpenBuildPathCorrectionProposal(project, label, 5, referencedElement);
		proposals.add(proposal);
	}
}
