content: /*******************************************************************************
   * Copyright (c) 2006, 2009 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.corext.refactoring.structure;
  
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.Collection;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.Iterator;
  import java.util.LinkedList;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  
  import org.eclipse.core.resources.IFile;
  import org.eclipse.core.runtime.Assert;
  import org.eclipse.core.runtime.CoreException;
  import org.eclipse.core.runtime.IProgressMonitor;
  import org.eclipse.core.runtime.NullProgressMonitor;
  import org.eclipse.core.runtime.OperationCanceledException;
  import org.eclipse.core.runtime.SubProgressMonitor;
  import org.eclipse.jface.text.BadLocationException;
  import org.eclipse.jface.text.Document;
  import org.eclipse.jface.text.IDocument;
  import org.eclipse.ltk.core.refactoring.Change;
  import org.eclipse.ltk.core.refactoring.GroupCategory;
  import org.eclipse.ltk.core.refactoring.GroupCategorySet;
  import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
  import org.eclipse.ltk.core.refactoring.RefactoringStatus;
  import org.eclipse.ltk.core.refactoring.TextChange;
  import org.eclipse.ltk.core.refactoring.TextEditBasedChange;
  import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
  import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments;
  import org.eclipse.text.edits.MalformedTreeException;
  import org.eclipse.text.edits.TextEdit;
  import org.eclipse.text.edits.TextEditCopier;
  import org.eclipse.wst.jsdt.core.Flags;
  import org.eclipse.wst.jsdt.core.IFunction;
  import org.eclipse.wst.jsdt.core.IJavaScriptElement;
  import org.eclipse.wst.jsdt.core.IJavaScriptProject;
  import org.eclipse.wst.jsdt.core.IJavaScriptUnit;
  import org.eclipse.wst.jsdt.core.IMember;
  import org.eclipse.wst.jsdt.core.IType;
  import org.eclipse.wst.jsdt.core.JavaScriptModelException;
  import org.eclipse.wst.jsdt.core.dom.AST;
  import org.eclipse.wst.jsdt.core.dom.ASTParser;
  import org.eclipse.wst.jsdt.core.dom.ASTRequestor;
  import org.eclipse.wst.jsdt.core.dom.AbstractTypeDeclaration;
  import org.eclipse.wst.jsdt.core.dom.FunctionDeclaration;
  import org.eclipse.wst.jsdt.core.dom.IBinding;
  import org.eclipse.wst.jsdt.core.dom.IFunctionBinding;
  import org.eclipse.wst.jsdt.core.dom.ITypeBinding;
  import org.eclipse.wst.jsdt.core.dom.JavaScriptUnit;
  import org.eclipse.wst.jsdt.core.dom.Modifier;
  import org.eclipse.wst.jsdt.core.dom.Type;
  import org.eclipse.wst.jsdt.core.dom.TypeDeclaration;
  import org.eclipse.wst.jsdt.core.dom.rewrite.ASTRewrite;
  import org.eclipse.wst.jsdt.core.dom.rewrite.ListRewrite;
  import org.eclipse.wst.jsdt.core.formatter.CodeFormatter;
  import org.eclipse.wst.jsdt.core.refactoring.IJavaScriptRefactorings;
  import org.eclipse.wst.jsdt.core.refactoring.descriptors.JavaScriptRefactoringDescriptor;
  import org.eclipse.wst.jsdt.internal.corext.codemanipulation.CodeGenerationSettings;
  import org.eclipse.wst.jsdt.internal.corext.codemanipulation.StubUtility;
  import org.eclipse.wst.jsdt.internal.corext.codemanipulation.StubUtility2;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.Checks;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.JDTRefactoringDescriptor;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.JDTRefactoringDescriptorComment;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.JavaRefactoringArguments;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.RefactoringCoreMessages;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.changes.CompilationUnitChange;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.changes.CreateCompilationUnitChange;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.changes.DynamicValidationRefactoringChange;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.changes.MultiStateCompilationUnitChange;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.code.ScriptableRefactoring;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.util.RefactoringASTParser;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.util.ResourceUtil;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.util.TextEditBasedChangeManager;
  import org.eclipse.wst.jsdt.internal.corext.util.CodeFormatterUtil;
  import org.eclipse.wst.jsdt.internal.corext.util.JavaModelUtil;
  import org.eclipse.wst.jsdt.internal.corext.util.JdtFlags;
  import org.eclipse.wst.jsdt.internal.corext.util.Messages;
  import org.eclipse.wst.jsdt.internal.ui.JavaScriptPlugin;
  import org.eclipse.wst.jsdt.internal.ui.preferences.JavaPreferencesSettings;
  import org.eclipse.wst.jsdt.ui.CodeGeneration;
  import org.eclipse.wst.jsdt.ui.JavaScriptElementLabels;
  
  /**
   * Refactoring processor for the extract supertype refactoring.
   * 
   * 
   */
  public final class ExtractSupertypeProcessor extends PullUpRefactoringProcessor {
  
  	/** The extract attribute */
  	private static final String ATTRIBUTE_EXTRACT= "extract"; //$NON-NLS-1$
  
  	/** The types attribute */
  	private static final String ATTRIBUTE_TYPES= "types"; //$NON-NLS-1$
  
  	/** The extract supertype group category set */
  	private static final GroupCategorySet SET_EXTRACT_SUPERTYPE= new GroupCategorySet(new GroupCategory("org.eclipse.wst.jsdt.internal.corext.extractSupertype", //$NON-NLS-1$
  			RefactoringCoreMessages.ExtractSupertypeProcessor_category_name, RefactoringCoreMessages.ExtractSupertypeProcessor_category_description));
  
  	/**
  	 * The changes of the working copy layer (element type:
  	 * &lt;IJavaScriptUnit, TextEditBasedChange&gt;)
  	 * <p>
  	 * The compilation units are all primary working copies or normal
  	 * compilation units.
  	 * </p>
  	 */
  	private final Map fLayerChanges= new HashMap();
  
  	/** The possible extract supertype candidates, or the empty array */
  	private IType[] fPossibleCandidates= {};
  
  	/** The source of the supertype */
  	private String fSuperSource;
  
  	/** The name of the extracted type */
  	private String fTypeName= ""; //$NON-NLS-1$
  
  	/** The types where to extract the supertype */
  	private IType[] fTypesToExtract= {};
  
  	/**
  	 * Creates a new extract supertype refactoring processor.
  	 * 
  	 * @param members
  	 *            the members to extract, or <code>null</code> if invoked by
  	 *            scripting
  	 * @param settings
  	 *            the code generation settings, or <code>null</code> if
  	 *            invoked by scripting
  	 */
  	public ExtractSupertypeProcessor(final IMember[] members, final CodeGenerationSettings settings) {
  		super(members, settings, true);
  		if (members != null) {
  			final IType declaring= getDeclaringType();
  			if (declaring != null)
  				fTypesToExtract= new IType[] { declaring};
  		}
  	}
  
  	/**
  	 * {@inheritDoc}
  	 */
  	protected final RefactoringStatus checkDeclaringSuperTypes(final IProgressMonitor monitor) throws JavaScriptModelException {
  		return new RefactoringStatus();
  	}
  	
  	protected CompilationUnitRewrite getCompilationUnitRewrite(final Map rewrites, final IJavaScriptUnit unit) {
  		Assert.isNotNull(rewrites);
  		Assert.isNotNull(unit);
  		CompilationUnitRewrite rewrite= (CompilationUnitRewrite) rewrites.get(unit);
  		if (rewrite == null) {
  			rewrite= new CompilationUnitRewrite(fOwner, unit);
  			rewrite.rememberContent();
  			rewrites.put(unit, rewrite);
  		}
  		return rewrite;
  	}
  
  	/**
  	 * Checks whether the compilation unit to be extracted is valid.
  	 * 
  	 * @return a status describing the outcome of the
  	 */
  	public RefactoringStatus checkExtractedCompilationUnit() {
  		final RefactoringStatus status= new RefactoringStatus();
  		final IJavaScriptUnit cu= getDeclaringType().getJavaScriptUnit();
  		if (fTypeName == null || "".equals(fTypeName)) //$NON-NLS-1$
  			return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.Checks_Choose_name);
  		status.merge(Checks.checkTypeName(fTypeName));
  		if (status.hasFatalError())
  			return status;
  		status.merge(Checks.checkCompilationUnitName(JavaModelUtil.getRenamedCUName(cu, fTypeName)));
  		if (status.hasFatalError())
  			return status;
  		status.merge(Checks.checkCompilationUnitNewName(cu, fTypeName));
  		return status;
  	}
  
  	/**
  	 * {@inheritDoc}
  	 */
  	public RefactoringStatus checkFinalConditions(final IProgressMonitor monitor, final CheckConditionsContext context) throws CoreException, OperationCanceledException {
  		final RefactoringStatus status= new RefactoringStatus();
  		try {
  			monitor.beginTask("", 1); //$NON-NLS-1$
  			monitor.setTaskName(RefactoringCoreMessages.ExtractSupertypeProcessor_checking);
  			status.merge(checkExtractedCompilationUnit());
  			if (status.hasFatalError())
  				return status;
  			return super.checkFinalConditions(new SubProgressMonitor(monitor, 1), context);
  		} finally {
  			monitor.done();
  		}
  	}
  
  	/**
  	 * Computes the destination type based on the new name.
  	 * 
  	 * @param name the new name
  	 * @return the destination type
  	 */
  	public IType computeExtractedType(final String name) {
  		if (name != null && !name.equals("")) {//$NON-NLS-1$
  			final IType declaring= getDeclaringType();
  			try {
  				final IJavaScriptUnit[] units= declaring.getPackageFragment().getJavaScriptUnits(fOwner);
  				final String newName= JavaModelUtil.getRenamedCUName(declaring.getJavaScriptUnit(), name);
  				IJavaScriptUnit result= null;
  				for (int index= 0; index < units.length; index++) {
  					if (units[index].getElementName().equals(newName))
  						result= units[index];
  				}
  				if (result != null) {
  					final IType type= result.getType(name);
  					setDestinationType(type);
  					return type;
  				}
  			} catch (JavaScriptModelException exception) {
  				JavaScriptPlugin.log(exception);
  			}
  		}
  		return null;
  	}
  
  	/**
  	 * {@inheritDoc}
  	 */
  	public Change createChange(final IProgressMonitor monitor) throws CoreException, OperationCanceledException {
  		try {
  			final Map arguments= new HashMap();
  			String project= null;
  			final IType declaring= getDeclaringType();
  			final IJavaScriptProject javaProject= declaring.getJavaScriptProject();
  			if (javaProject != null)
  				project= javaProject.getElementName();
  			int flags= JavaScriptRefactoringDescriptor.JAR_MIGRATION | JavaScriptRefactoringDescriptor.JAR_REFACTORING | RefactoringDescriptor.STRUCTURAL_CHANGE | RefactoringDescriptor.MULTI_CHANGE;
  			try {
  				if (declaring.isLocal() || declaring.isAnonymous())
  					flags|= JavaScriptRefactoringDescriptor.JAR_SOURCE_ATTACHMENT;
  			} catch (JavaScriptModelException exception) {
  				JavaScriptPlugin.log(exception);
  			}
  			final String description= Messages.format(RefactoringCoreMessages.ExtractSupertypeProcessor_descriptor_description_short, fTypeName);
  			final String header= Messages.format(RefactoringCoreMessages.ExtractSupertypeProcessor_descriptor_description, new String[] { JavaScriptElementLabels.getElementLabel(fDestinationType, JavaScriptElementLabels.ALL_FULLY_QUALIFIED), JavaScriptElementLabels.getElementLabel(fCachedDeclaringType, JavaScriptElementLabels.ALL_FULLY_QUALIFIED)});
  			final JDTRefactoringDescriptorComment comment= new JDTRefactoringDescriptorComment(project, this, header);
  			final IType[] types= getTypesToExtract();
  			String[] settings= new String[types.length];
  			for (int index= 0; index < settings.length; index++)
  				settings[index]= JavaScriptElementLabels.getElementLabel(types[index], JavaScriptElementLabels.ALL_FULLY_QUALIFIED);
  			comment.addSetting(JDTRefactoringDescriptorComment.createCompositeSetting(RefactoringCoreMessages.ExtractSupertypeProcessor_subtypes_pattern, settings));
  			comment.addSetting(Messages.format(RefactoringCoreMessages.ExtractSupertypeProcessor_refactored_element_pattern, JavaScriptElementLabels.getElementLabel(fDestinationType, JavaScriptElementLabels.ALL_FULLY_QUALIFIED)));
  			settings= new String[fMembersToMove.length];
  			for (int index= 0; index < settings.length; index++)
  				settings[index]= JavaScriptElementLabels.getElementLabel(fMembersToMove[index], JavaScriptElementLabels.ALL_FULLY_QUALIFIED);
  			comment.addSetting(JDTRefactoringDescriptorComment.createCompositeSetting(RefactoringCoreMessages.ExtractInterfaceProcessor_extracted_members_pattern, settings));
  			addSuperTypeSettings(comment, true);
  			final JDTRefactoringDescriptor descriptor= new JDTRefactoringDescriptor(IJavaScriptRefactorings.EXTRACT_SUPERCLASS, project, description, comment.asString(), arguments, flags);
  			arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_NAME, fTypeName);
  			arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_INPUT, descriptor.elementToHandle(getDeclaringType()));
  			arguments.put(ATTRIBUTE_REPLACE, Boolean.valueOf(fReplace).toString());
  			arguments.put(ATTRIBUTE_INSTANCEOF, Boolean.valueOf(fInstanceOf).toString());
  			arguments.put(ATTRIBUTE_STUBS, Boolean.valueOf(fCreateMethodStubs).toString());
  			arguments.put(ATTRIBUTE_EXTRACT, Integer.valueOf(fMembersToMove.length).toString());
  			for (int offset= 0; offset < fMembersToMove.length; offset++)
  				arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_ELEMENT + (offset + 1), descriptor.elementToHandle(fMembersToMove[offset]));
  			arguments.put(ATTRIBUTE_DELETE, Integer.valueOf(fDeletedMethods.length).toString());
  			for (int offset= 0; offset < fDeletedMethods.length; offset++)
  				arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_ELEMENT + (offset + fMembersToMove.length + 1), descriptor.elementToHandle(fDeletedMethods[offset]));
  			arguments.put(ATTRIBUTE_ABSTRACT, Integer.valueOf(fAbstractMethods.length).toString());
  			for (int offset= 0; offset < fAbstractMethods.length; offset++)
  				arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_ELEMENT + (offset + fMembersToMove.length + fDeletedMethods.length + 1), descriptor.elementToHandle(fAbstractMethods[offset]));
  			arguments.put(ATTRIBUTE_TYPES, Integer.valueOf(fTypesToExtract.length).toString());
  			for (int offset= 0; offset < fTypesToExtract.length; offset++)
  				arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_ELEMENT + (offset + fMembersToMove.length + fDeletedMethods.length + fAbstractMethods.length + 1), descriptor.elementToHandle(fTypesToExtract[offset]));
  			final DynamicValidationRefactoringChange change= new DynamicValidationRefactoringChange(descriptor, RefactoringCoreMessages.ExtractSupertypeProcessor_extract_supertype, fChangeManager.getAllChanges());
  			final IFile file= ResourceUtil.getFile(declaring.getJavaScriptUnit());
  			if (fSuperSource != null && fSuperSource.length() > 0)
  				change.add(new CreateCompilationUnitChange(declaring.getPackageFragment().getJavaScriptUnit(JavaModelUtil.getRenamedCUName(declaring.getJavaScriptUnit(), fTypeName)), fSuperSource, file.getCharset(false)));
  			return change;
  		} finally {
  			monitor.done();
  			clearCaches();
  		}
  	}
  
  	/**
  	 * Creates the new extracted supertype.
  	 * 
  	 * @param superType
  	 *            the super type, or <code>null</code> if no super type (ie.
  	 *            <code>java.lang.Object</code>) is available
  	 * @param monitor
  	 *            the progress monitor
  	 * @return a status describing the outcome of the operation
  	 * @throws CoreException
  	 *             if an error occurs
  	 */
  	protected final RefactoringStatus createExtractedSuperType(final IType superType, final IProgressMonitor monitor) throws CoreException {
  		Assert.isNotNull(monitor);
  		fSuperSource= null;
  		final RefactoringStatus status= new RefactoringStatus();
  		try {
  			monitor.beginTask(RefactoringCoreMessages.ExtractSupertypeProcessor_preparing, 20);
  			final IType declaring= getDeclaringType();
  			final CompilationUnitRewrite declaringRewrite= new CompilationUnitRewrite(fOwner, declaring.getJavaScriptUnit());
  			final AbstractTypeDeclaration declaringDeclaration= ASTNodeSearchUtil.getAbstractTypeDeclarationNode(declaring, declaringRewrite.getRoot());
  			if (declaringDeclaration != null) {
  				final String name= JavaModelUtil.getRenamedCUName(declaring.getJavaScriptUnit(), fTypeName);
  				final IJavaScriptUnit original= declaring.getPackageFragment().getJavaScriptUnit(name);
  				final IJavaScriptUnit copy= getSharedWorkingCopy(original.getPrimary(), new SubProgressMonitor(monitor, 10));
  				fSuperSource= createSuperTypeSource(copy, superType, declaringDeclaration, status, new SubProgressMonitor(monitor, 10));
  				if (fSuperSource != null) {
  					copy.getBuffer().setContents(fSuperSource);
  					JavaModelUtil.reconcile(copy);
  				}
  			}
  		} finally {
  			monitor.done();
  		}
  		return status;
  	}
  
  	/**
  	 * Creates a working copy for the modified subtype.
  	 * 
  	 * @param unit
  	 *            the compilation unit
  	 * @param root
  	 *            the compilation unit node
  	 * @param subDeclaration
  	 *            the declaration of the subtype to modify
  	 * @param extractedType
  	 *            the extracted super type
  	 * @param extractedBinding
  	 *            the binding of the extracted super type
  	 * @param status
  	 *            the refactoring status
  	 */
  	protected final void createModifiedSubType(final IJavaScriptUnit unit, final JavaScriptUnit root, final IType extractedType, final ITypeBinding extractedBinding, final AbstractTypeDeclaration subDeclaration, final RefactoringStatus status) {
  		Assert.isNotNull(unit);
  		Assert.isNotNull(subDeclaration);
  		Assert.isNotNull(extractedType);
  		try {
  			final CompilationUnitRewrite rewrite= new CompilationUnitRewrite(fOwner, unit, root);
  			createTypeSignature(rewrite, subDeclaration, extractedType, extractedBinding, new NullProgressMonitor());
  			final Document document= new Document(unit.getBuffer().getContents());
  			final CompilationUnitChange change= rewrite.createChange();
  			if (change != null) {
  				fLayerChanges.put(unit.getPrimary(), change);
  				final TextEdit edit= change.getEdit();
  				if (edit != null) {
  					final TextEditCopier copier= new TextEditCopier(edit);
  					final TextEdit copy= copier.perform();
  					copy.apply(document, TextEdit.NONE);
  				}
  			}
  			final IJavaScriptUnit copy= getSharedWorkingCopy(unit, new NullProgressMonitor());
  			copy.getBuffer().setContents(document.get());
  			JavaModelUtil.reconcile(copy);
  		} catch (CoreException exception) {
  			JavaScriptPlugin.log(exception);
  			status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractSupertypeProcessor_unexpected_exception_on_layer));
  		} catch (MalformedTreeException exception) {
  			JavaScriptPlugin.log(exception);
  			status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractSupertypeProcessor_unexpected_exception_on_layer));
  		} catch (BadLocationException exception) {
  			JavaScriptPlugin.log(exception);
  			status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractSupertypeProcessor_unexpected_exception_on_layer));
  		}
  	}
  
  	/**
  	 * Creates the necessary constructors for the extracted supertype.
  	 * 
  	 * @param targetRewrite
  	 *            the target compilation unit rewrite
  	 * @param superType
  	 *            the super type, or <code>null</code> if no super type (ie.
  	 *            <code>java.lang.Object</code>) is available
  	 * @param targetDeclaration
  	 *            the type declaration of the target type
  	 * @param status
  	 *            the refactoring status
  	 */
  	protected final void createNecessaryConstructors(final CompilationUnitRewrite targetRewrite, final IType superType, final AbstractTypeDeclaration targetDeclaration, final RefactoringStatus status) {
  		Assert.isNotNull(targetRewrite);
  		Assert.isNotNull(targetDeclaration);
  		if (superType != null) {
  			final ITypeBinding binding= targetDeclaration.resolveBinding();
  			if (binding != null && binding.isClass()) {
  				final IFunctionBinding[] bindings= StubUtility2.getVisibleConstructors(binding, true, true);
  				int deprecationCount= 0;
  				for (int i= 0; i < bindings.length; i++) {
  					if (bindings[i].isDeprecated())
  						deprecationCount++;
  				}
  				final ListRewrite rewrite= targetRewrite.getASTRewrite().getListRewrite(targetDeclaration, TypeDeclaration.BODY_DECLARATIONS_PROPERTY);
  				if (rewrite != null) {
  					boolean createDeprecated= deprecationCount == bindings.length;
  					for (int i= 0; i < bindings.length; i++) {
  						IFunctionBinding curr= bindings[i];
  						if (!curr.isDeprecated() || createDeprecated) {
  							FunctionDeclaration stub;
  							try {
  								stub= StubUtility2.createConstructorStub(targetRewrite.getCu(), targetRewrite.getASTRewrite(), targetRewrite.getImportRewrite(), curr, binding.getName(), Modifier.PUBLIC, false, false, fSettings);
  								if (stub != null)
  									rewrite.insertLast(stub, null);
  							} catch (CoreException exception) {
  								JavaScriptPlugin.log(exception);
  								status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractSupertypeProcessor_unexpected_exception_on_layer));
  							}
  						}
  					}
  				}
  			}
  		}
  	}
  
  	/**
  	 * Creates the source for the new compilation unit containing the supertype.
  	 * 
  	 * @param extractedWorkingCopy
  	 *            the working copy of the new extracted supertype
  	 * @param superType
  	 *            the super type, or <code>null</code> if no super type (ie.
  	 *            <code>java.lang.Object</code>) is available
  	 * @param declaringDeclaration
  	 *            the declaration of the declaring type
  	 * @param status
  	 *            the refactoring status
  	 * @param monitor
  	 *            the progress monitor to display progress
  	 * @return the source of the new compilation unit, or <code>null</code>
  	 * @throws CoreException
  	 *             if an error occurs
  	 */
  	protected final String createSuperTypeSource(final IJavaScriptUnit extractedWorkingCopy, final IType superType, final AbstractTypeDeclaration declaringDeclaration, final RefactoringStatus status, final IProgressMonitor monitor) throws CoreException {
  		Assert.isNotNull(extractedWorkingCopy);
  		Assert.isNotNull(declaringDeclaration);
  		Assert.isNotNull(status);
  		Assert.isNotNull(monitor);
  		String source= null;
  		try {
  			monitor.beginTask("", 2); //$NON-NLS-1$
  			monitor.setTaskName(RefactoringCoreMessages.ExtractSupertypeProcessor_preparing);
  			final IType declaring= getDeclaringType();
  			final String delimiter= StubUtility.getLineDelimiterUsed(extractedWorkingCopy.getJavaScriptProject());
  			String typeComment= null;
  			String fileComment= null;
  			if (fSettings.createComments) {
  				typeComment= CodeGeneration.getTypeComment(extractedWorkingCopy, fTypeName, delimiter);
  				fileComment= CodeGeneration.getFileComment(extractedWorkingCopy, delimiter);
  			}
  			final StringBuffer buffer= new StringBuffer(64);
  			final ITypeBinding binding= declaringDeclaration.resolveBinding();
  			if (binding != null) {
  				final ITypeBinding superBinding= binding.getSuperclass();
  				if (superBinding != null)
  					fTypeBindings.add(superBinding);
  			}
  			final String imports= createTypeImports(extractedWorkingCopy, monitor);
  			if (imports != null && !"".equals(imports)) { //$NON-NLS-1$
  				buffer.append(imports);
  			}
  			createTypeDeclaration(extractedWorkingCopy, superType, declaringDeclaration, typeComment, buffer, status, new SubProgressMonitor(monitor, 1));
  			source= createTypeTemplate(extractedWorkingCopy, "", fileComment, "", buffer.toString()); //$NON-NLS-1$ //$NON-NLS-2$
  			if (source == null) {
  				if (!declaring.getPackageFragment().isDefaultPackage()) {
  					if (imports.length() > 0)
  						buffer.insert(0, imports);
  					buffer.insert(0, "package " + declaring.getPackageFragment().getElementName() + ";"); //$NON-NLS-1$//$NON-NLS-2$
  				}
  				source= buffer.toString();
  			}
  			final IDocument document= new Document(source);
  			final TextEdit edit= CodeFormatterUtil.format2(CodeFormatter.K_JAVASCRIPT_UNIT, source, 0, delimiter, extractedWorkingCopy.getJavaScriptProject().getOptions(true));
  			if (edit != null) {
  				try {
  					edit.apply(document, TextEdit.UPDATE_REGIONS);
  				} catch (MalformedTreeException exception) {
  					JavaScriptPlugin.log(exception);
  					status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractSupertypeProcessor_unexpected_exception_on_layer));
  				} catch (BadLocationException exception) {
  					JavaScriptPlugin.log(exception);
  					status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractSupertypeProcessor_unexpected_exception_on_layer));
  				}
  				source= document.get();
  			}
  		} finally {
  			monitor.done();
  		}
  		return source;
  	}
  
  	/**
  	 * Creates the declaration of the new supertype, excluding any comments or
  	 * package declaration.
  	 * 
  	 * @param extractedWorkingCopy
  	 *            the working copy of the new extracted supertype
  	 * @param superType
  	 *            the super type, or <code>null</code> if no super type (ie.
  	 *            <code>java.lang.Object</code>) is available
  	 * @param declaringDeclaration
  	 *            the declaration of the declaring type
  	 * @param comment
  	 *            the comment of the new type declaration
  	 * @param buffer
  	 *            the string buffer containing the declaration
  	 * @param status
  	 *            the refactoring status
  	 * @param monitor
  	 *            the progress monitor to use
  	 * @throws CoreException
  	 *             if an error occurs
  	 */
  	protected final void createTypeDeclaration(final IJavaScriptUnit extractedWorkingCopy, final IType superType, final AbstractTypeDeclaration declaringDeclaration, final String comment, final StringBuffer buffer, final RefactoringStatus status, final IProgressMonitor monitor) throws CoreException {
  		Assert.isNotNull(extractedWorkingCopy);
  		Assert.isNotNull(declaringDeclaration);
  		Assert.isNotNull(buffer);
  		Assert.isNotNull(status);
  		Assert.isNotNull(monitor);
  		try {
  			monitor.beginTask("", 1); //$NON-NLS-1$
  			monitor.setTaskName(RefactoringCoreMessages.ExtractSupertypeProcessor_preparing);
  			final IJavaScriptProject project= extractedWorkingCopy.getJavaScriptProject();
  			final String delimiter= StubUtility.getLineDelimiterUsed(project);
  			if (comment != null && !"".equals(comment)) { //$NON-NLS-1$
  				buffer.append(comment);
  				buffer.append(delimiter);
  			}
  			buffer.append(JdtFlags.VISIBILITY_STRING_PUBLIC);
  			if (superType != null && Flags.isAbstract(superType.getFlags())) {
  				buffer.append(' ');
  				buffer.append("abstract "); //$NON-NLS-1$
  			}
  			buffer.append(' ');
  			buffer.append("class "); //$NON-NLS-1$
  			buffer.append(fTypeName);
  			if (superType != null && !"java.lang.Object".equals(superType.getFullyQualifiedName())) { //$NON-NLS-1$
  				buffer.append(' ');
  				buffer.append("extends "); //$NON-NLS-1$
  				buffer.append(superType.getElementName());
  			}
  			buffer.append(" {"); //$NON-NLS-1$
  			buffer.append(delimiter);
  			buffer.append(delimiter);
  			buffer.append('}');
  			final String string= buffer.toString();
  			extractedWorkingCopy.getBuffer().setContents(string);
  			final IDocument document= new Document(string);
  			final CompilationUnitRewrite targetRewrite= new CompilationUnitRewrite(fOwner, extractedWorkingCopy);
  			final AbstractTypeDeclaration targetDeclaration= (AbstractTypeDeclaration) targetRewrite.getRoot().types().get(0);
  			createTypeSignature(targetRewrite, superType, declaringDeclaration, targetDeclaration);
  			createNecessaryConstructors(targetRewrite, superType, targetDeclaration, status);
  			final TextEdit edit= targetRewrite.createChange().getEdit();
  			try {
  				edit.apply(document, TextEdit.UPDATE_REGIONS);
  			} catch (MalformedTreeException exception) {
  				JavaScriptPlugin.log(exception);
  				status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractSupertypeProcessor_unexpected_exception_on_layer));
  			} catch (BadLocationException exception) {
  				JavaScriptPlugin.log(exception);
  				status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractSupertypeProcessor_unexpected_exception_on_layer));
  			}
  			buffer.setLength(0);
  			buffer.append(document.get());
  		} finally {
  			monitor.done();
  		}
  	}
  
  	/**
  	 * Creates a new type signature of a subtype.
  	 * 
  	 * @param subRewrite
  	 *            the compilation unit rewrite of a subtype
  	 * @param declaration
  	 *            the type declaration of a subtype
  	 * @param extractedType
  	 *            the extracted super type
  	 * @param extractedBinding
  	 *            the binding of the extracted super type
  	 * @param monitor
  	 *            the progress monitor to use
  	 * @throws JavaScriptModelException
  	 *             if the type parameters cannot be retrieved
  	 */
  	protected final void createTypeSignature(final CompilationUnitRewrite subRewrite, final AbstractTypeDeclaration declaration, final IType extractedType, final ITypeBinding extractedBinding, final IProgressMonitor monitor) throws JavaScriptModelException {
  		Assert.isNotNull(subRewrite);
  		Assert.isNotNull(declaration);
  		Assert.isNotNull(extractedType);
  		Assert.isNotNull(monitor);
  		try {
  			monitor.beginTask(RefactoringCoreMessages.ExtractSupertypeProcessor_preparing, 10);
  			final AST ast= subRewrite.getAST();
  			Type type= null;
  			if (extractedBinding != null) {
  				type= subRewrite.getImportRewrite().addImport(extractedBinding, ast);
  			} else {
  				subRewrite.getImportRewrite().addImport(extractedType.getFullyQualifiedName('.'));
  				type= ast.newSimpleType(ast.newSimpleName(extractedType.getElementName()));
  			}
  			subRewrite.getImportRemover().registerAddedImport(extractedType.getFullyQualifiedName('.'));
  			final ASTRewrite rewriter= subRewrite.getASTRewrite();
  			if (type != null && declaration instanceof TypeDeclaration) {
  				final TypeDeclaration extended= (TypeDeclaration) declaration;
  				final Type superClass= extended.getSuperclassType();
  				if (superClass != null) {
  					rewriter.replace(superClass, type, subRewrite.createCategorizedGroupDescription(RefactoringCoreMessages.ExtractSupertypeProcessor_add_supertype, SET_EXTRACT_SUPERTYPE));
  					subRewrite.getImportRemover().registerRemovedNode(superClass);
  				} else
  					rewriter.set(extended, TypeDeclaration.SUPERCLASS_TYPE_PROPERTY, type, subRewrite.createCategorizedGroupDescription(RefactoringCoreMessages.ExtractSupertypeProcessor_add_supertype, SET_EXTRACT_SUPERTYPE));
  			}
  		} finally {
  			monitor.done();
  		}
  	}
  
  	/**
  	 * Creates the type signature of the extracted supertype.
  	 * 
  	 * @param targetRewrite
  	 *            the target compilation unit rewrite
  	 * @param superType
  	 *            the super type, or <code>null</code> if no super type (ie.
  	 *            <code>java.lang.Object</code>) is available
  	 * @param declaringDeclaration
  	 *            the declaration of the declaring type
  	 * @param targetDeclaration
  	 *            the type declaration of the target type
  	 */
  	protected final void createTypeSignature(final CompilationUnitRewrite targetRewrite, final IType superType, final AbstractTypeDeclaration declaringDeclaration, final AbstractTypeDeclaration targetDeclaration) {
  		Assert.isNotNull(targetRewrite);
  		Assert.isNotNull(declaringDeclaration);
  		Assert.isNotNull(targetDeclaration);
  		if (declaringDeclaration instanceof TypeDeclaration) {
  			final TypeDeclaration declaration= (TypeDeclaration) declaringDeclaration;
  			final Type superclassType= declaration.getSuperclassType();
  			if (superclassType != null) {
  				Type type= null;
  				final ITypeBinding binding= superclassType.resolveBinding();
  				if (binding != null) {
  					type= targetRewrite.getImportRewrite().addImport(binding, targetRewrite.getAST());
  					targetRewrite.getImportRemover().registerAddedImports(type);
  				}
  				if (type != null && targetDeclaration instanceof TypeDeclaration) {
  					final TypeDeclaration extended= (TypeDeclaration) targetDeclaration;
  					final Type targetSuperType= extended.getSuperclassType();
  					if (targetSuperType != null) {
  						targetRewrite.getASTRewrite().replace(targetSuperType, type, null);
  					} else {
  						targetRewrite.getASTRewrite().set(extended, TypeDeclaration.SUPERCLASS_TYPE_PROPERTY, type, null);
  					}
  				}
  			}
  		}
  	}
  
  	/**
  	 * {@inheritDoc}
  	 */
  	public final RefactoringStatus createWorkingCopyLayer(final IProgressMonitor monitor) {
  		Assert.isNotNull(monitor);
  		final RefactoringStatus status= new RefactoringStatus();
  		try {
  			monitor.beginTask(RefactoringCoreMessages.ExtractSupertypeProcessor_preparing, 70);
  			status.merge(super.createWorkingCopyLayer(new SubProgressMonitor(monitor, 10)));
  			final IType declaring= getDeclaringType();
  			status.merge(createExtractedSuperType(getDeclaringSuperTypeHierarchy(new SubProgressMonitor(monitor, 10)).getSuperclass(declaring), new SubProgressMonitor(monitor, 10)));
  			if (status.hasFatalError())
  				return status;
  			final IType extractedType= computeExtractedType(fTypeName);
  			setDestinationType(extractedType);
  			final List subTypes= new ArrayList(Arrays.asList(fTypesToExtract));
  			if (!subTypes.contains(declaring))
  				subTypes.add(declaring);
  			final Map unitToTypes= new HashMap(subTypes.size());
  			final Set units= new HashSet(subTypes.size());
  			for (int index= 0; index < subTypes.size(); index++) {
  				final IType type= (IType) subTypes.get(index);
  				final IJavaScriptUnit unit= type.getJavaScriptUnit();
  				units.add(unit);
  				Collection collection= (Collection) unitToTypes.get(unit);
  				if (collection == null) {
  					collection= new ArrayList(2);
  					unitToTypes.put(unit, collection);
  				}
  				collection.add(type);
  			}
  			final Map projectToUnits= new HashMap();
  			Collection collection= null;
  			IJavaScriptProject project= null;
  			IJavaScriptUnit current= null;
  			for (final Iterator iterator= units.iterator(); iterator.hasNext();) {
  				current= (IJavaScriptUnit) iterator.next();
  				project= current.getJavaScriptProject();
  				collection= (Collection) projectToUnits.get(project);
  				if (collection == null) {
  					collection= new ArrayList();
  					projectToUnits.put(project, collection);
  				}
  				collection.add(current);
  			}
  			final ITypeBinding[] extractBindings= { null};
  			final ASTParser extractParser= ASTParser.newParser(AST.JLS3);
  			extractParser.setWorkingCopyOwner(fOwner);
  			extractParser.setResolveBindings(true);
  			extractParser.setProject(project);
  			extractParser.setSource(extractedType.getJavaScriptUnit());
  			final JavaScriptUnit extractUnit= (JavaScriptUnit) extractParser.createAST(new SubProgressMonitor(monitor, 10));
  			if (extractUnit != null) {
  				final AbstractTypeDeclaration extractDeclaration= ASTNodeSearchUtil.getAbstractTypeDeclarationNode(extractedType, extractUnit);
  				if (extractDeclaration != null)
  					extractBindings[0]= extractDeclaration.resolveBinding();
  			}
  			final ASTParser parser= ASTParser.newParser(AST.JLS3);
  			final IProgressMonitor subMonitor= new SubProgressMonitor(monitor, 30);
  			try {
  				final Set keySet= projectToUnits.keySet();
  				subMonitor.beginTask("", keySet.size()); //$NON-NLS-1$
  				subMonitor.setTaskName(RefactoringCoreMessages.ExtractSupertypeProcessor_preparing);
  				for (final Iterator iterator= keySet.iterator(); iterator.hasNext();) {
  					project= (IJavaScriptProject) iterator.next();
  					collection= (Collection) projectToUnits.get(project);
  					parser.setWorkingCopyOwner(fOwner);
  					parser.setResolveBindings(true);
  					parser.setProject(project);
  					parser.setCompilerOptions(RefactoringASTParser.getCompilerOptions(project));
  					final IProgressMonitor subsubMonitor= new SubProgressMonitor(subMonitor, 1);
  					try {
  						subsubMonitor.beginTask("", collection.size()); //$NON-NLS-1$
  						subsubMonitor.setTaskName(RefactoringCoreMessages.ExtractSupertypeProcessor_preparing);
  						parser.createASTs((IJavaScriptUnit[]) collection.toArray(new IJavaScriptUnit[collection.size()]), new String[0], new ASTRequestor() {
  
  							public final void acceptAST(final IJavaScriptUnit unit, final JavaScriptUnit node) {
  								try {
  									final Collection types= (Collection) unitToTypes.get(unit);
  									if (types != null) {
  										for (final Iterator innerIterator= types.iterator(); innerIterator.hasNext();) {
  											final IType currentType= (IType) innerIterator.next();
  											final AbstractTypeDeclaration currentDeclaration= ASTNodeSearchUtil.getAbstractTypeDeclarationNode(currentType, node);
  											if (currentDeclaration != null)
  												createModifiedSubType(unit, node, extractedType, extractBindings[0], currentDeclaration, status);
  										}
  									}
  								} catch (CoreException exception) {
  									JavaScriptPlugin.log(exception);
  									status.merge(RefactoringStatus.createFatalErrorStatus(exception.getLocalizedMessage()));
  								} finally {
  									subsubMonitor.worked(1);
  								}
  							}
  
  							public final void acceptBinding(final String key, final IBinding binding) {
  								// Do nothing
  							}
  						}, subsubMonitor);
  					} finally {
  						subsubMonitor.done();
  					}
  				}
  			} finally {
  				subMonitor.done();
  			}
  		} catch (CoreException exception) {
  			JavaScriptPlugin.log(exception);
  			status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractSupertypeProcessor_unexpected_exception_on_layer));
  		} finally {
  			monitor.done();
  		}
  		return status;
  	}
  
  	/**
  	 * {@inheritDoc}
  	 */
  	public IType[] getCandidateTypes(final RefactoringStatus status, final IProgressMonitor monitor) {
  		Assert.isNotNull(monitor);
  		if (fPossibleCandidates == null || fPossibleCandidates.length == 0) {
  			final IType declaring= getDeclaringType();
  			if (declaring != null) {
  				try {
  					monitor.beginTask(RefactoringCoreMessages.ExtractSupertypeProcessor_computing_possible_types, 10);
  					final IType superType= getDeclaringSuperTypeHierarchy(new SubProgressMonitor(monitor, 1, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL)).getSuperclass(declaring);
  					if (superType != null) {
  						fPossibleCandidates= superType.newTypeHierarchy(fOwner, new SubProgressMonitor(monitor, 9, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL)).getSubclasses(superType);
  						final LinkedList list= new LinkedList(Arrays.asList(fPossibleCandidates));
  						final Set names= new HashSet();
  						for (final Iterator iterator= list.iterator(); iterator.hasNext();) {
  							final IType type= (IType) iterator.next();
  							if (type.isReadOnly() || type.isBinary() || type.isAnonymous() || !type.isClass() || names.contains(type.getFullyQualifiedName()))
  								iterator.remove();
  							else
  								names.add(type.getFullyQualifiedName());
  						}
  						fPossibleCandidates= (IType[]) list.toArray(new IType[list.size()]);
  					}
  				} catch (JavaScriptModelException exception) {
  					JavaScriptPlugin.log(exception);
  				} finally {
  					monitor.done();
  				}
  			}
  		}
  		return fPossibleCandidates;
  	}
  
  	/**
  	 * {@inheritDoc}
  	 */
  	public Object[] getElements() {
  		return new Object[] { getDeclaringType()};
  	}
  
  	/**
  	 * Returns the extracted type.
  	 * 
  	 * @return the extracted type, or <code>null</code>
  	 */
  	public IType getExtractedType() {
  		return getDestinationType();
  	}
  
  	/**
  	 * Returns the type name.
  	 * 
  	 * @return the type name
  	 */
  	public String getTypeName() {
  		return fTypeName;
  	}
  
  	/**
  	 * Returns the types to extract. The declaring type may or may not be
  	 * contained in the result.
  	 * 
  	 * @return the types to extract
  	 */
  	public IType[] getTypesToExtract() {
  		return fTypesToExtract;
  	}
  
  	/**
  	 * {@inheritDoc}
  	 */
  	public RefactoringStatus initialize(final RefactoringArguments arguments) {
  		if (arguments instanceof JavaRefactoringArguments) {
  			final JavaRefactoringArguments extended= (JavaRefactoringArguments) arguments;
  			final String name= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_NAME);
  			if (name != null && !"".equals(name)) //$NON-NLS-1$
  				fTypeName= name;
  			else
  				return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_NAME));
  			String handle= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_INPUT);
  			if (handle != null) {
  				final IJavaScriptElement element= JDTRefactoringDescriptor.handleToElement(extended.getProject(), handle, false);
  				if (element == null || element.getElementType() != IJavaScriptElement.TYPE)
  					return ScriptableRefactoring.createInputFatalStatus(element, getRefactoring().getName(), IJavaScriptRefactorings.EXTRACT_SUPERCLASS);
  				IType type= null;
  				final IJavaScriptUnit unit= ((IType) element).getJavaScriptUnit();
  				if (unit != null && unit.exists()) {
  					try {
  						final IJavaScriptUnit copy= getSharedWorkingCopy(unit, new NullProgressMonitor());
  						final IJavaScriptElement[] elements= copy.findElements(element);
  						if (elements != null && elements.length == 1 && elements[0] instanceof IType && elements[0].exists())
  							type= (IType) elements[0];
  					} catch (JavaScriptModelException exception) {
  						// TODO: log exception
  					}
  				}
  				if (type != null)
  					fCachedDeclaringType= type;
  				else
  					return ScriptableRefactoring.createInputFatalStatus(element, getRefactoring().getName(), IJavaScriptRefactorings.EXTRACT_SUPERCLASS);
  			} else
  				return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_INPUT));
  			final String stubs= extended.getAttribute(ATTRIBUTE_STUBS);
  			if (stubs != null) {
  				fCreateMethodStubs= Boolean.valueOf(stubs).booleanValue();
  			} else
  				return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_STUBS));
  			final String instance= extended.getAttribute(ATTRIBUTE_INSTANCEOF);
  			if (instance != null) {
  				fInstanceOf= Boolean.valueOf(instance).booleanValue();
  			} else
  				return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_INSTANCEOF));
  			final String replace= extended.getAttribute(ATTRIBUTE_REPLACE);
  			if (replace != null) {
  				fReplace= Boolean.valueOf(replace).booleanValue();
  			} else
  				return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_REPLACE));
  			int extractCount= 0;
  			int abstractCount= 0;
  			int deleteCount= 0;
  			int typeCount= 0;
  			String value= extended.getAttribute(ATTRIBUTE_ABSTRACT);
  			if (value != null && !"".equals(value)) {//$NON-NLS-1$
  				try {
  					abstractCount= Integer.parseInt(value);
  				} catch (NumberFormatException exception) {
  					return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_ABSTRACT));
  				}
  			} else
  				return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_ABSTRACT));
  			value= extended.getAttribute(ATTRIBUTE_DELETE);
  			if (value != null && !"".equals(value)) {//$NON-NLS-1$
  				try {
  					deleteCount= Integer.parseInt(value);
  				} catch (NumberFormatException exception) {
  					return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_DELETE));
  				}
  			} else
  				return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_DELETE));
  			value= extended.getAttribute(ATTRIBUTE_EXTRACT);
  			if (value != null && !"".equals(value)) {//$NON-NLS-1$
  				try {
  					extractCount= Integer.parseInt(value);
  				} catch (NumberFormatException exception) {
  					return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_EXTRACT));
  				}
  			} else
  				return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_EXTRACT));
  			value= extended.getAttribute(ATTRIBUTE_TYPES);
  			if (value != null && !"".equals(value)) {//$NON-NLS-1$
  				try {
  					typeCount= Integer.parseInt(value);
  				} catch (NumberFormatException exception) {
  					return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_TYPES));
  				}
  			} else
  				return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_TYPES));
  			final RefactoringStatus status= new RefactoringStatus();
  			List elements= new ArrayList();
  			for (int index= 0; index < extractCount; index++) {
  				final String attribute= JDTRefactoringDescriptor.ATTRIBUTE_ELEMENT + (index + 1);
  				handle= extended.getAttribute(attribute);
  				if (handle != null && !"".equals(handle)) { //$NON-NLS-1$
  					final IJavaScriptElement element= JDTRefactoringDescriptor.handleToElement(fOwner, extended.getProject(), handle, false);
  					if (element == null || !element.exists())
  						status.merge(ScriptableRefactoring.createInputWarningStatus(element, getRefactoring().getName(), IJavaScriptRefactorings.EXTRACT_SUPERCLASS));
  					else
  						elements.add(element);
  				} else
  					return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, attribute));
  			}
  			fMembersToMove= (IMember[]) elements.toArray(new IMember[elements.size()]);
  			elements= new ArrayList();
  			for (int index= 0; index < deleteCount; index++) {
  				final String attribute= JDTRefactoringDescriptor.ATTRIBUTE_ELEMENT + (extractCount + index + 1);
  				handle= extended.getAttribute(attribute);
  				if (handle != null && !"".equals(handle)) { //$NON-NLS-1$
  					final IJavaScriptElement element= JDTRefactoringDescriptor.handleToElement(fOwner, extended.getProject(), handle, false);
  					if (element == null || !element.exists())
  						status.merge(ScriptableRefactoring.createInputWarningStatus(element, getRefactoring().getName(), IJavaScriptRefactorings.EXTRACT_SUPERCLASS));
  					else
  						elements.add(element);
  				} else
  					return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, attribute));
  			}
  			fDeletedMethods= (IFunction[]) elements.toArray(new IFunction[elements.size()]);
  			elements= new ArrayList();
  			for (int index= 0; index < abstractCount; index++) {
  				final String attribute= JDTRefactoringDescriptor.ATTRIBUTE_ELEMENT + (extractCount + abstractCount + index + 1);
  				handle= extended.getAttribute(attribute);
  				if (handle != null && !"".equals(handle)) { //$NON-NLS-1$
  					final IJavaScriptElement element= JDTRefactoringDescriptor.handleToElement(fOwner, extended.getProject(), handle, false);
  					if (element == null || !element.exists())
  						status.merge(ScriptableRefactoring.createInputWarningStatus(element, getRefactoring().getName(), IJavaScriptRefactorings.EXTRACT_SUPERCLASS));
  					else
  						elements.add(element);
  				} else
  					return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, attribute));
  			}
  			fAbstractMethods= (IFunction[]) elements.toArray(new IFunction[elements.size()]);
  			elements= new ArrayList();
  			for (int index= 0; index < typeCount; index++) {
  				final String attribute= JDTRefactoringDescriptor.ATTRIBUTE_ELEMENT + (extractCount + abstractCount + deleteCount + index + 1);
  				handle= extended.getAttribute(attribute);
  				if (handle != null && !"".equals(handle)) { //$NON-NLS-1$
  					final IJavaScriptElement element= JDTRefactoringDescriptor.handleToElement(fOwner, extended.getProject(), handle, false);
  					if (element == null || !element.exists())
  						status.merge(ScriptableRefactoring.createInputFatalStatus(element, getRefactoring().getName(), IJavaScriptRefactorings.EXTRACT_SUPERCLASS));
  					else
  						elements.add(element);
  				} else
  					return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, attribute));
  			}
  			fTypesToExtract= (IType[]) elements.toArray(new IType[elements.size()]);
  			IJavaScriptProject project= null;
  			if (fMembersToMove.length > 0)
  				project= fMembersToMove[0].getJavaScriptProject();
  			fSettings= JavaPreferencesSettings.getCodeGenerationSettings(project);
  			if (!status.isOK())
  				return status;
  		} else
  			return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InitializableRefactoring_inacceptable_arguments);
  		return new RefactoringStatus();
  	}
  
  	/**
  	 * {@inheritDoc}
  	 */
  	protected void registerChanges(final TextEditBasedChangeManager manager) throws CoreException {
  		try {
  			final IJavaScriptUnit extractedUnit= getExtractedType().getJavaScriptUnit();
  			IJavaScriptUnit unit= null;
  			CompilationUnitRewrite rewrite= null;
  			for (final Iterator iterator= fCompilationUnitRewrites.keySet().iterator(); iterator.hasNext();) {
  				unit= (IJavaScriptUnit) iterator.next();
  				if (unit.equals(extractedUnit)) {
  					rewrite= (CompilationUnitRewrite) fCompilationUnitRewrites.get(unit);
  					if (rewrite != null) {
  						CompilationUnitChange change= rewrite.createChange();
  
  						if (change != null) {
  							final TextEdit edit= ((TextChange) change).getEdit();
  							if (edit != null) {
  								final IDocument document= new Document(fSuperSource);
  								try {
  									edit.apply(document, TextEdit.UPDATE_REGIONS);
  								} catch (MalformedTreeException exception) {
  									JavaScriptPlugin.log(exception);
  								} catch (BadLocationException exception) {
  									JavaScriptPlugin.log(exception);
  								}
  								fSuperSource= document.get();
  								manager.remove(extractedUnit);
  							}
  						}
  					}
  				} else {
  					rewrite= (CompilationUnitRewrite) fCompilationUnitRewrites.get(unit);
  					if (rewrite != null) {
  						final CompilationUnitChange layerChange= (CompilationUnitChange) fLayerChanges.get(unit.getPrimary());
  						final CompilationUnitChange rewriteChange= rewrite.createChange();
  						if (rewriteChange != null && layerChange != null) {
  							final MultiStateCompilationUnitChange change= new MultiStateCompilationUnitChange(rewriteChange.getName(), unit);
  							change.addChange(layerChange);
  							change.addChange(rewriteChange);
  							fLayerChanges.remove(unit.getPrimary());
  							manager.manage(unit, change);
  						} else if (layerChange != null) {
  							manager.manage(unit, layerChange);
  							fLayerChanges.remove(unit.getPrimary());
  						} else if (rewriteChange != null) {
  							manager.manage(unit, rewriteChange);
  						}
  					}
  				}
  			}
  			for (Iterator iterator= fLayerChanges.entrySet().iterator(); iterator.hasNext();) {
  				final Map.Entry entry= (Map.Entry) iterator.next();
  				manager.manage((IJavaScriptUnit) entry.getKey(), (TextEditBasedChange) entry.getValue());
  			}
  			IJavaScriptUnit[] units= manager.getAllCompilationUnits();
  			for (int index= 0; index < units.length; index++) {
  				if (units[index].getPath().equals(extractedUnit.getPath()))
  					manager.remove(units[index]);
  			}
  		} finally {
  			fLayerChanges.clear();
  		}
  	}
  
  	/**
  	 * Resets the changes necessary for the working copy layer.
  	 */
  	public void resetChanges() {
  		fLayerChanges.clear();
  	}
  
  	/**
  	 * Sets the type name.
  	 * 
  	 * @param name
  	 *            the type name
  	 */
  	public void setTypeName(final String name) {
  		Assert.isNotNull(name);
  		fTypeName= name;
  	}
  
  	/**
  	 * Sets the types to extract. Must be a subset of
  	 * <code>getPossibleCandidates()</code>. If the declaring type is not
  	 * contained, it will automatically be added.
  	 * 
  	 * @param types
  	 *            the types to extract
  	 */
  	public void setTypesToExtract(final IType[] types) {
  		Assert.isNotNull(types);
  		fTypesToExtract= types;
  	}
  }
  