/**
  * Creates any destination package fragment(s) which do not exists yet. Return true if a read-only
  * package fragment has been found among package fragments, false otherwise
  */
 private boolean createNeededPackageFragments(
     IContainer sourceFolder, PackageFragmentRoot root, String[] newFragName, boolean moveFolder)
     throws JavaModelException {
   boolean containsReadOnlyPackageFragment = false;
   IContainer parentFolder = (IContainer) root.resource();
   JavaElementDelta projectDelta = null;
   String[] sideEffectPackageName = null;
   char[][] inclusionPatterns = root.fullInclusionPatternChars();
   char[][] exclusionPatterns = root.fullExclusionPatternChars();
   for (int i = 0; i < newFragName.length; i++) {
     String subFolderName = newFragName[i];
     sideEffectPackageName = Util.arrayConcat(sideEffectPackageName, subFolderName);
     IResource subFolder = parentFolder.findMember(subFolderName);
     if (subFolder == null) {
       // create deepest folder only if not a move (folder will be moved in
       // processPackageFragmentResource)
       if (!(moveFolder && i == newFragName.length - 1)) {
         createFolder(parentFolder, subFolderName, this.force);
       }
       parentFolder = parentFolder.getFolder(new Path(subFolderName));
       sourceFolder = sourceFolder.getFolder(new Path(subFolderName));
       if (Util.isReadOnly(sourceFolder)) {
         containsReadOnlyPackageFragment = true;
       }
       IPackageFragment sideEffectPackage = root.getPackageFragment(sideEffectPackageName);
       if (i < newFragName.length - 1 // all but the last one are side effect packages
           && !Util.isExcluded(parentFolder, inclusionPatterns, exclusionPatterns)) {
         if (projectDelta == null) {
           projectDelta = getDeltaFor(root.getJavaProject());
         }
         projectDelta.added(sideEffectPackage);
       }
       this.createdElements.add(sideEffectPackage);
     } else {
       parentFolder = (IContainer) subFolder;
     }
   }
   return containsReadOnlyPackageFragment;
 }
  /**
   * Copies/moves a package fragment with the name <code>newName</code> to the destination package.
   * <br>
   *
   * @exception JavaModelException if the operation is unable to complete
   */
  private void processPackageFragmentResource(
      PackageFragment source, PackageFragmentRoot root, String newName) throws JavaModelException {
    try {
      String[] newFragName = (newName == null) ? source.names : Util.getTrimmedSimpleNames(newName);
      PackageFragment newFrag = root.getPackageFragment(newFragName);
      IResource[] resources = collectResourcesOfInterest(source);

      // if isMove() can we move the folder itself ? (see
      // http://bugs.eclipse.org/bugs/show_bug.cgi?id=22458)
      boolean shouldMoveFolder =
          isMove() && !newFrag.resource().exists(); // if new pkg fragment exists, it is an override
      IFolder srcFolder = (IFolder) source.resource();
      IPath destPath = newFrag.getPath();
      if (shouldMoveFolder) {
        // check if destination is not included in source
        if (srcFolder.getFullPath().isPrefixOf(destPath)) {
          shouldMoveFolder = false;
        } else {
          // check if there are no sub-packages
          IResource[] members = srcFolder.members();
          for (int i = 0; i < members.length; i++) {
            if (members[i] instanceof IFolder) {
              shouldMoveFolder = false;
              break;
            }
          }
        }
      }
      boolean containsReadOnlySubPackageFragments =
          createNeededPackageFragments(
              (IContainer) source.parent.resource(), root, newFragName, shouldMoveFolder);
      boolean sourceIsReadOnly = Util.isReadOnly(srcFolder);

      // Process resources
      if (shouldMoveFolder) {
        // move underlying resource
        // TODO Revisit once bug 43044 is fixed
        if (sourceIsReadOnly) {
          Util.setReadOnly(srcFolder, false);
        }
        srcFolder.move(destPath, this.force, true /* keep history */, getSubProgressMonitor(1));
        if (sourceIsReadOnly) {
          Util.setReadOnly(srcFolder, true);
        }
        setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);
      } else {
        // process the leaf resources
        if (resources.length > 0) {
          if (isRename()) {
            if (!destPath.equals(source.getPath())) {
              moveResources(resources, destPath);
            }
          } else if (isMove()) {
            // we need to delete this resource if this operation wants to override existing
            // resources
            for (int i = 0, max = resources.length; i < max; i++) {
              IResource destinationResource =
                  ResourcesPlugin.getWorkspace()
                      .getRoot()
                      .findMember(destPath.append(resources[i].getName()));
              if (destinationResource != null) {
                if (this.force) {
                  deleteResource(destinationResource, IResource.KEEP_HISTORY);
                } else {
                  throw new JavaModelException(
                      new JavaModelStatus(
                          IJavaModelStatusConstants.NAME_COLLISION,
                          Messages.bind(
                              Messages.status_nameCollision,
                              destinationResource.getFullPath().toString())));
                }
              }
            }
            moveResources(resources, destPath);
          } else {
            // we need to delete this resource if this operation wants to override existing
            // resources
            for (int i = 0, max = resources.length; i < max; i++) {
              IResource destinationResource =
                  ResourcesPlugin.getWorkspace()
                      .getRoot()
                      .findMember(destPath.append(resources[i].getName()));
              if (destinationResource != null) {
                if (this.force) {
                  // we need to delete this resource if this operation wants to override existing
                  // resources
                  deleteResource(destinationResource, IResource.KEEP_HISTORY);
                } else {
                  throw new JavaModelException(
                      new JavaModelStatus(
                          IJavaModelStatusConstants.NAME_COLLISION,
                          Messages.bind(
                              Messages.status_nameCollision,
                              destinationResource.getFullPath().toString())));
                }
              }
            }
            copyResources(resources, destPath);
          }
        }
      }

      // Update package statement in compilation unit if needed
      if (!Util.equalArraysOrNull(
          newFragName, source.names)) { // if package has been renamed, update the compilation units
        char[][] inclusionPatterns = root.fullInclusionPatternChars();
        char[][] exclusionPatterns = root.fullExclusionPatternChars();
        for (int i = 0; i < resources.length; i++) {
          String resourceName = resources[i].getName();
          if (Util.isJavaLikeFileName(resourceName)) {
            // we only consider potential compilation units
            ICompilationUnit cu = newFrag.getCompilationUnit(resourceName);
            if (Util.isExcluded(
                cu.getPath(), inclusionPatterns, exclusionPatterns, false /*not a folder*/))
              continue;
            this.parser.setSource(cu);
            CompilationUnit astCU = (CompilationUnit) this.parser.createAST(this.progressMonitor);
            AST ast = astCU.getAST();
            ASTRewrite rewrite = ASTRewrite.create(ast);
            updatePackageStatement(astCU, newFragName, rewrite, cu);
            TextEdit edits = rewrite.rewriteAST();
            applyTextEdit(cu, edits);
            cu.save(null, false);
          }
        }
      }

      // Discard empty old package (if still empty after the rename)
      boolean isEmpty = true;
      if (isMove()) {
        // delete remaining files in this package (.class file in the case where Proj=src=bin)
        // in case of a copy
        updateReadOnlyPackageFragmentsForMove(
            (IContainer) source.parent.resource(), root, newFragName, sourceIsReadOnly);
        if (srcFolder.exists()) {
          IResource[] remaining = srcFolder.members();
          for (int i = 0, length = remaining.length; i < length; i++) {
            IResource file = remaining[i];
            if (file instanceof IFile) {
              if (Util.isReadOnly(file)) {
                Util.setReadOnly(file, false);
              }
              deleteResource(file, IResource.FORCE | IResource.KEEP_HISTORY);
            } else {
              isEmpty = false;
            }
          }
        }
        if (isEmpty) {
          IResource rootResource;
          // check if source is included in destination
          if (destPath.isPrefixOf(srcFolder.getFullPath())) {
            rootResource = newFrag.resource();
          } else {
            rootResource = source.parent.resource();
          }

          // delete recursively empty folders
          deleteEmptyPackageFragment(source, false, rootResource);
        }
      } else if (containsReadOnlySubPackageFragments) {
        // in case of a copy
        updateReadOnlyPackageFragmentsForCopy(
            (IContainer) source.parent.resource(), root, newFragName);
      }
      // workaround for bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=24505
      if (isEmpty && isMove() && !(Util.isExcluded(source) || Util.isExcluded(newFrag))) {
        IJavaProject sourceProject = source.getJavaProject();
        getDeltaFor(sourceProject).movedFrom(source, newFrag);
        IJavaProject destProject = newFrag.getJavaProject();
        getDeltaFor(destProject).movedTo(newFrag, source);
      }
    } catch (JavaModelException e) {
      throw e;
    } catch (CoreException ce) {
      throw new JavaModelException(ce);
    }
  }