private void addNLS(NLSSubstitution sub, TextChange change, String accessorName) {
    if (sub.getState() == NLSSubstitution.INTERNALIZED) return;

    NLSElement element = sub.getNLSElement();

    addAccessor(sub, change, accessorName);

    if (!fIsEclipseNLS || sub.getState() == NLSSubstitution.IGNORED) {
      // Add $NON-NLS-n tag
      String arg =
          sub.getState() == NLSSubstitution.EXTERNALIZED ? sub.getKey() : sub.getValueNonEmpty();
      String name = Messages.format(NLSMessages.NLSSourceModifier_add_tag, arg);
      TextChangeCompatibility.addTextEdit(change, name, createAddTagChange(element));
    }
  }
  private void deleteAccessor(NLSSubstitution substitution, TextChange change, ICompilationUnit cu)
      throws CoreException {
    AccessorClassReference accessorClassRef = substitution.getAccessorClassReference();
    if (accessorClassRef != null) {
      Region region = accessorClassRef.getRegion();
      String[] args = {
        substitution.getValueNonEmpty(),
        BasicElementLabels.getJavaElementName(substitution.getKey())
      };
      String label = Messages.format(NLSMessages.NLSSourceModifier_remove_accessor, args);
      String replaceString = '\"' + unwindEscapeChars(substitution.getValueNonEmpty()) + '\"';
      TextChangeCompatibility.addTextEdit(
          change, label, new ReplaceEdit(region.getOffset(), region.getLength(), replaceString));
      if (fIsEclipseNLS && substitution.getState() != NLSSubstitution.INTERNALIZED) {

        Region position = substitution.getNLSElement().getPosition();
        int lineStart = getLineStart(cu.getBuffer(), position.getOffset());
        int lineEnd = getLineEnd(cu.getBuffer(), position.getOffset());
        String cuLine = cu.getBuffer().getText(lineStart, lineEnd - lineStart);
        StringBuffer buf = new StringBuffer(cuLine);
        buf.replace(
            region.getOffset() - lineStart,
            region.getOffset() + region.getLength() - lineStart,
            replaceString);
        try {
          NLSLine[] allLines = NLSScanner.scan(buf.toString());

          NLSLine nlsLine = allLines[0];
          NLSElement element =
              findElement(
                  nlsLine,
                  position.getOffset() - lineStart - accessorClassRef.getName().length() - 1);
          if (element == null || element.hasTag()) return;

          NLSElement[] elements = nlsLine.getElements();
          int indexInElementList = Arrays.asList(elements).indexOf(element);
          String editText =
              ' ' + NLSElement.createTagText(indexInElementList + 1); // tags are 1-based
          TextChangeCompatibility.addTextEdit(change, label, new InsertEdit(lineEnd, editText));

        } catch (InvalidInputException e) {
        } catch (BadLocationException e) {
        }
      }
    }
  }
  private void addAccessor(NLSSubstitution sub, TextChange change, String accessorName) {
    if (sub.getState() == NLSSubstitution.EXTERNALIZED) {
      NLSElement element = sub.getNLSElement();
      Region position = element.getPosition();
      String[] args = {sub.getValueNonEmpty(), BasicElementLabels.getJavaElementName(sub.getKey())};
      String text = Messages.format(NLSMessages.NLSSourceModifier_externalize, args);

      String resourceGetter = createResourceGetter(sub.getKey(), accessorName);

      TextEdit edit = new ReplaceEdit(position.getOffset(), position.getLength(), resourceGetter);
      if (fIsEclipseNLS && element.getTagPosition() != null) {
        MultiTextEdit multiEdit = new MultiTextEdit();
        multiEdit.addChild(edit);
        Region tagPosition = element.getTagPosition();
        multiEdit.addChild(new DeleteEdit(tagPosition.getOffset(), tagPosition.getLength()));
        edit = multiEdit;
      }
      TextChangeCompatibility.addTextEdit(change, text, edit);
    }
  }
  public static Change create(
      ICompilationUnit cu,
      NLSSubstitution[] subs,
      String substitutionPattern,
      IPackageFragment accessorPackage,
      String accessorClassName,
      boolean isEclipseNLS)
      throws CoreException {

    NLSSourceModifier sourceModification = new NLSSourceModifier(substitutionPattern, isEclipseNLS);

    String message =
        Messages.format(
            NLSMessages.NLSSourceModifier_change_description, BasicElementLabels.getFileName(cu));

    TextChange change = new CompilationUnitChange(message, cu);
    MultiTextEdit multiTextEdit = new MultiTextEdit();
    change.setEdit(multiTextEdit);

    accessorClassName =
        sourceModification.createImportForAccessor(
            multiTextEdit, accessorClassName, accessorPackage, cu);

    for (int i = 0; i < subs.length; i++) {
      NLSSubstitution substitution = subs[i];
      int newState = substitution.getState();
      if (substitution.hasStateChanged()) {
        if (newState == NLSSubstitution.EXTERNALIZED) {
          if (substitution.getInitialState() == NLSSubstitution.INTERNALIZED) {
            sourceModification.addNLS(substitution, change, accessorClassName);
          } else if (substitution.getInitialState() == NLSSubstitution.IGNORED) {
            sourceModification.addAccessor(substitution, change, accessorClassName);
          }
        } else if (newState == NLSSubstitution.INTERNALIZED) {
          if (substitution.getInitialState() == NLSSubstitution.IGNORED) {
            sourceModification.deleteTag(substitution, change);
            if (substitution.isValueRename()) {
              sourceModification.replaceValue(substitution, change);
            }
          } else if (substitution.getInitialState() == NLSSubstitution.EXTERNALIZED) {
            sourceModification.deleteAccessor(substitution, change, cu);
            if (!isEclipseNLS) sourceModification.deleteTag(substitution, change);
          }
        } else if (newState == NLSSubstitution.IGNORED) {
          if (substitution.getInitialState() == NLSSubstitution.INTERNALIZED) {
            sourceModification.addNLS(substitution, change, accessorClassName);
            if (substitution.isValueRename()) {
              sourceModification.replaceValue(substitution, change);
            }
          } else {
            if (substitution.getInitialState() == NLSSubstitution.EXTERNALIZED) {
              sourceModification.deleteAccessor(substitution, change, cu);
            }
          }
        }
      } else {
        if (newState == NLSSubstitution.EXTERNALIZED) {
          if (substitution.isKeyRename()) {
            sourceModification.replaceKey(substitution, change);
          }
          if (substitution.isAccessorRename()) {
            sourceModification.replaceAccessor(substitution, change);
          }
        } else {
          if (substitution.isValueRename()) {
            sourceModification.replaceValue(substitution, change);
          }
        }
      }
    }

    return change;
  }