private Map.Entry<OIdentifiable, Integer> nextChangedNotRemovedSBTreeEntry(
      Iterator<Map.Entry<OIdentifiable, Integer>> iterator) {
    while (iterator.hasNext()) {
      final Map.Entry<OIdentifiable, Integer> entry = iterator.next();
      final Change change = changes.get(entry.getKey());
      if (change == null) return entry;

      final int newValue = change.applyTo(entry.getValue());

      if (newValue > 0)
        return new Map.Entry<OIdentifiable, Integer>() {
          @Override
          public OIdentifiable getKey() {
            return entry.getKey();
          }

          @Override
          public Integer getValue() {
            return newValue;
          }

          @Override
          public Integer setValue(Integer value) {
            throw new UnsupportedOperationException();
          }
        };
    }

    return null;
  }
  /*
   * Generates rollback statements from the inverse changes returned by createInverses().
   * Throws RollbackImpossibleException if the changes created by createInverses() is not supported for the passed database.
   *
   */
  private SqlStatement[] generateRollbackStatementsFromInverse(Database database)
      throws RollbackImpossibleException {
    Change[] inverses = createInverses();
    if (inverses == null) {
      throw new RollbackImpossibleException("No inverse to " + getClass().getName() + " created");
    }

    List<SqlStatement> statements = new ArrayList<SqlStatement>();

    try {
      for (Change inverse : inverses) {
        if (!inverse.supports(database)) {
          throw new RollbackImpossibleException(
              ChangeFactory.getInstance().getChangeMetaData(inverse).getName()
                  + " is not supported on "
                  + database.getShortName());
        }
        statements.addAll(Arrays.asList(inverse.generateStatements(database)));
      }
    } catch (LiquibaseException e) {
      throw new RollbackImpossibleException(e);
    }

    return statements.toArray(new SqlStatement[statements.size()]);
  }
  public void add(final OIdentifiable identifiable) {
    if (identifiable == null)
      throw new NullPointerException("Impossible to add a null identifiable in a ridbag");
    if (identifiable.getIdentity().isValid()) {
      Change counter = changes.get(identifiable);
      if (counter == null) changes.put(identifiable, new DiffChange(1));
      else {
        if (counter.isUndefined()) {
          counter = getAbsoluteValue(identifiable);
          changes.put(identifiable, counter);
        }
        counter.increment();
      }
    } else {
      final OModifiableInteger counter = newEntries.get(identifiable);
      if (counter == null) newEntries.put(identifiable, new OModifiableInteger(1));
      else counter.increment();
    }

    if (size >= 0) size++;

    if (this.owner != null) ORecordInternal.track(this.owner, identifiable);

    if (updateOwner)
      fireCollectionChangedEvent(
          new OMultiValueChangeEvent<OIdentifiable, OIdentifiable>(
              OMultiValueChangeEvent.OChangeType.ADD, identifiable, identifiable, null, false));
  }
 protected static boolean canShowDiff(Change[] changes) {
   if (changes == null || changes.length == 0) return false;
   for (Change change : changes) {
     if (!ChangesUtil.getFilePath(change).isDirectory() || change.hasOtherLayers()) return true;
   }
   return false;
 }
  public void remove(OIdentifiable identifiable) {
    if (removeFromNewEntries(identifiable)) {
      if (size >= 0) size--;
    } else {
      final Change counter = changes.get(identifiable);
      if (counter == null) {
        // Not persistent keys can only be in changes or newEntries
        if (identifiable.getIdentity().isPersistent()) {
          changes.put(identifiable, new DiffChange(-1));
          size = -1;
        } else
          // Return immediately to prevent firing of event
          return;
      } else {
        counter.decrement();

        if (size >= 0)
          if (counter.isUndefined()) size = -1;
          else size--;
      }
    }

    if (this.owner != null) ORecordInternal.unTrack(this.owner, identifiable);

    if (updateOwner)
      fireCollectionChangedEvent(
          new OMultiValueChangeEvent<OIdentifiable, OIdentifiable>(
              OMultiValueChangeEvent.OChangeType.REMOVE, identifiable, null, identifiable, false));
  }
 public void processChangeLists(final List<LocalChangeList> lists) {
   final ProjectLevelVcsManager plVcsManager =
       ProjectLevelVcsManager.getInstanceChecked(myProject);
   plVcsManager.startBackgroundVcsOperation();
   try {
     final SVNChangelistClient client = createChangelistClient();
     for (LocalChangeList list : lists) {
       if (!list.isDefault()) {
         final Collection<Change> changes = list.getChanges();
         for (Change change : changes) {
           correctListForRevision(
               plVcsManager, change.getBeforeRevision(), client, list.getName());
           correctListForRevision(plVcsManager, change.getAfterRevision(), client, list.getName());
         }
       }
     }
   } finally {
     final Application appManager = ApplicationManager.getApplication();
     if (appManager.isDispatchThread()) {
       appManager.executeOnPooledThread(
           new Runnable() {
             @Override
             public void run() {
               plVcsManager.stopBackgroundVcsOperation();
             }
           });
     } else {
       plVcsManager.stopBackgroundVcsOperation();
     }
   }
 }
 @Override
 public void run(ContinuationContext context) {
   final List<Change> changesForPatch;
   try {
     final List<CommittedChangeList> lst = loadSvnChangeListsForPatch(myDescription);
     changesForPatch = CommittedChangesTreeBrowser.collectChanges(lst, true);
     for (Change change : changesForPatch) {
       if (change.getBeforeRevision() != null) {
         preloadRevisionContents(change.getBeforeRevision());
       }
       if (change.getAfterRevision() != null) {
         preloadRevisionContents(change.getAfterRevision());
       }
     }
   } catch (VcsException e) {
     context.handleException(e, true);
     return;
   }
   final List<Change> binaryChanges = filterOutBinary(changesForPatch);
   if (binaryChanges != null && !binaryChanges.isEmpty()) {
     myTheirsBinaryChanges.addAll(binaryChanges);
   }
   if (!changesForPatch.isEmpty()) {
     myTheirsChanges.addAll(changesForPatch);
   }
 }
 /**
  * Sort changes by roots
  *
  * @param changes a change list
  * @param exceptions exceptions to collect
  * @return sorted changes
  */
 private static Map<VirtualFile, Collection<Change>> sortChangesByGitRoot(
     @NotNull List<Change> changes, List<VcsException> exceptions) {
   Map<VirtualFile, Collection<Change>> result = new HashMap<VirtualFile, Collection<Change>>();
   for (Change change : changes) {
     final ContentRevision afterRevision = change.getAfterRevision();
     final ContentRevision beforeRevision = change.getBeforeRevision();
     // nothing-to-nothing change cannot happen.
     assert beforeRevision != null || afterRevision != null;
     // note that any path will work, because changes could happen within single vcs root
     final FilePath filePath =
         afterRevision != null ? afterRevision.getFile() : beforeRevision.getFile();
     final VirtualFile vcsRoot;
     try {
       // the parent paths for calculating roots in order to account for submodules that contribute
       // to the parent change. The path "." is never is valid change, so there should be no
       // problem
       // with it.
       vcsRoot = GitUtil.getGitRoot(filePath.getParentPath());
     } catch (VcsException e) {
       exceptions.add(e);
       continue;
     }
     Collection<Change> changeList = result.get(vcsRoot);
     if (changeList == null) {
       changeList = new ArrayList<Change>();
       result.put(vcsRoot, changeList);
     }
     changeList.add(change);
   }
   return result;
 }
  public static boolean isBinaryChange(Change change) {
    if (change.hasOtherLayers()) return false; // +-
    final ContentRevision bRev = change.getBeforeRevision();
    final ContentRevision aRev = change.getAfterRevision();

    return (aRev == null || aRev instanceof BinaryContentRevision)
        && (bRev == null || bRev instanceof BinaryContentRevision);
  }
 public void remove(@NotNull Change change) {
   if (change.getType().isApplied()) {
     LOG.assertTrue(myAppliedChanges.remove(change), change);
   } else {
     LOG.assertTrue(myChanges.remove(change), change);
   }
   change.onRemovedFromList();
   fireOnChangeRemoved();
 }
 private boolean containAdditions(final List<Change> changes) {
   boolean addFound = false;
   for (Change change : changes) {
     if (change.getBeforeRevision() == null || change.isMoved() || change.isRenamed()) {
       addFound = true;
       break;
     }
   }
   return addFound;
 }
 private void correctScopeForMoves(
     final VcsModifiableDirtyScope scope, final Collection<Change> changes) {
   if (scope == null) return;
   for (Change change : changes) {
     if (change.isMoved() || change.isRenamed()) {
       scope.addDirtyFile(change.getBeforeRevision().getFile());
       scope.addDirtyFile(change.getAfterRevision().getFile());
     }
   }
 }
 public static BeforeAfter<DiffContent> createBinaryDiffContents(
     final Project project, final Change change) throws VcsException {
   final FilePath filePath = ChangesUtil.getFilePath(change);
   try {
     return new BeforeAfter<DiffContent>(
         createBinaryFileContent(project, change.getBeforeRevision(), filePath.getName()),
         createBinaryFileContent(project, change.getAfterRevision(), filePath.getName()));
   } catch (IOException e) {
     throw new VcsException(e);
   }
 }
  public ShelvedChangeList shelveChanges(
      final Collection<Change> changes, final String commitMessage, final boolean rollback)
      throws IOException, VcsException {
    final List<Change> textChanges = new ArrayList<Change>();
    final List<ShelvedBinaryFile> binaryFiles = new ArrayList<ShelvedBinaryFile>();
    for (Change change : changes) {
      if (ChangesUtil.getFilePath(change).isDirectory()) {
        continue;
      }
      if (change.getBeforeRevision() instanceof BinaryContentRevision
          || change.getAfterRevision() instanceof BinaryContentRevision) {
        binaryFiles.add(shelveBinaryFile(change));
      } else {
        textChanges.add(change);
      }
    }

    final ShelvedChangeList changeList;
    try {
      File patchPath = getPatchPath(commitMessage);
      ProgressManager.checkCanceled();
      final List<FilePatch> patches =
          IdeaTextPatchBuilder.buildPatch(
              myProject, textChanges, myProject.getBaseDir().getPresentableUrl(), false);
      ProgressManager.checkCanceled();

      CommitContext commitContext = new CommitContext();
      baseRevisionsOfDvcsIntoContext(textChanges, commitContext);
      myFileProcessor.savePathFile(
          new CompoundShelfFileProcessor.ContentProvider() {
            public void writeContentTo(final Writer writer, CommitContext commitContext)
                throws IOException {
              UnifiedDiffWriter.write(myProject, patches, writer, "\n", commitContext);
            }
          },
          patchPath,
          commitContext);

      changeList =
          new ShelvedChangeList(
              patchPath.toString(), commitMessage.replace('\n', ' '), binaryFiles);
      myShelvedChangeLists.add(changeList);
      ProgressManager.checkCanceled();

      if (rollback) {
        new RollbackWorker(myProject, false)
            .doRollback(changes, true, null, VcsBundle.message("shelve.changes.action"));
      }
    } finally {
      notifyStateChanged();
    }

    return changeList;
  }
 private File[] getSelectedIoFiles() {
   final List<Change> changes = getSelectedChanges();
   final List<File> files = new ArrayList<>();
   for (Change change : changes) {
     final ContentRevision afterRevision = change.getAfterRevision();
     if (afterRevision != null) {
       final FilePath file = afterRevision.getFile();
       final File ioFile = file.getIOFile();
       files.add(ioFile);
     }
   }
   return files.toArray(new File[files.size()]);
 }
 private static SimpleDiffRequest createBinaryDiffRequest(
     final Project project, final Change change) throws VcsException {
   final FilePath filePath = ChangesUtil.getFilePath(change);
   final SimpleDiffRequest request = new SimpleDiffRequest(project, filePath.getPath());
   try {
     request.setContents(
         createBinaryFileContent(project, change.getBeforeRevision(), filePath.getName()),
         createBinaryFileContent(project, change.getAfterRevision(), filePath.getName()));
     return request;
   } catch (IOException e) {
     throw new VcsException(e);
   }
 }
 public LocalChangeList getListCopy(@NotNull final VirtualFile file) {
   for (LocalChangeList list : myMap.values()) {
     for (Change change : list.getChanges()) {
       if (change.getAfterRevision() != null
           && Comparing.equal(change.getAfterRevision().getFile().getVirtualFile(), file)) {
         return list.copy();
       }
       if (change.getBeforeRevision() != null
           && Comparing.equal(change.getBeforeRevision().getFile().getVirtualFile(), file)) {
         return list.copy();
       }
     }
   }
   return null;
 }
 private boolean checkIfThereAreFakeRevisions(final Project project, final Change[] changes) {
   boolean needsConvertion = false;
   for (Change change : changes) {
     final ContentRevision beforeRevision = change.getBeforeRevision();
     final ContentRevision afterRevision = change.getAfterRevision();
     if (beforeRevision instanceof FakeRevision) {
       VcsDirtyScopeManager.getInstance(project).fileDirty(beforeRevision.getFile());
       needsConvertion = true;
     }
     if (afterRevision instanceof FakeRevision) {
       VcsDirtyScopeManager.getInstance(project).fileDirty(afterRevision.getFile());
       needsConvertion = true;
     }
   }
   return needsConvertion;
 }
 @Nullable
 public Change getChangeForPath(final FilePath file) {
   for (LocalChangeList list : myMap.values()) {
     for (Change change : list.getChanges()) {
       final ContentRevision afterRevision = change.getAfterRevision();
       if (afterRevision != null && afterRevision.getFile().equals(file)) {
         return change;
       }
       final ContentRevision beforeRevision = change.getBeforeRevision();
       if (beforeRevision != null && beforeRevision.getFile().equals(file)) {
         return change;
       }
     }
   }
   return null;
 }
  protected VirtualFile[] getSelectedFiles() {
    final Change[] changes = getSelectedChanges();
    Collection<VirtualFile> files = new HashSet<VirtualFile>();
    for (Change change : changes) {
      final ContentRevision afterRevision = change.getAfterRevision();
      if (afterRevision != null) {
        final VirtualFile file = afterRevision.getFile().getVirtualFile();
        if (file != null && file.isValid()) {
          files.add(file);
        }
      }
    }

    files.addAll(getSelectedVirtualFiles(null));

    return VfsUtilCore.toVirtualFileArray(files);
  }
  private AbsoluteChange getAbsoluteValue(OIdentifiable identifiable) {
    final OSBTreeBonsai<OIdentifiable, Integer> tree = loadTree();
    try {
      Integer oldValue;

      if (tree == null) oldValue = 0;
      else oldValue = tree.get(identifiable);

      if (oldValue == null) oldValue = 0;

      final Change change = changes.get(identifiable);

      return new AbsoluteChange(change == null ? oldValue : change.applyTo(oldValue));
    } finally {
      releaseTree();
    }
  }
  public MergeFromTheirsResolver(
      SvnVcs vcs, TreeConflictDescription description, Change change, SvnRevisionNumber revision) {
    myVcs = vcs;
    myDescription = description;
    myChange = change;
    myCommittedRevision = revision;
    myOldFilePath = myChange.getBeforeRevision().getFile();
    myNewFilePath = myChange.getAfterRevision().getFile();
    myBaseForPatch = ChangesUtil.findValidParentAccurately(myNewFilePath);
    myOldPresentation = TreeConflictRefreshablePanel.filePath(myOldFilePath);
    myNewPresentation = TreeConflictRefreshablePanel.filePath(myNewFilePath);

    myTheirsChanges = new ArrayList<Change>();
    myTheirsBinaryChanges = new ArrayList<Change>();
    myWarnings = new ArrayList<VcsException>();
    myTextPatches = Collections.emptyList();
  }
 public void setChanges(@NotNull ArrayList<Change> changes) {
   if (myChanges != null) {
     HashSet<Change> newChanges = new HashSet<>(changes);
     LOG.assertTrue(newChanges.size() == changes.size());
     for (Iterator<Change> iterator = myChanges.iterator(); iterator.hasNext(); ) {
       Change oldChange = iterator.next();
       if (!newChanges.contains(oldChange)) {
         iterator.remove();
         oldChange.onRemovedFromList();
       }
     }
   }
   for (Change change : changes) {
     LOG.assertTrue(change.isValid());
   }
   myChanges = new ArrayList<>(changes);
   myAppliedChanges = new ArrayList<>();
 }
  public void removeRegisteredChangeFor(FilePath path) {
    myIdx.remove(path);

    for (LocalChangeList list : myMap.values()) {
      for (Change change : list.getChanges()) {
        final ContentRevision afterRevision = change.getAfterRevision();
        if (afterRevision != null && afterRevision.getFile().equals(path)) {
          ((LocalChangeListImpl) list).removeChange(change);
          return;
        }
        final ContentRevision beforeRevision = change.getBeforeRevision();
        if (beforeRevision != null && beforeRevision.getFile().equals(path)) {
          ((LocalChangeListImpl) list).removeChange(change);
          return;
        }
      }
    }
  }
    @Override
    public void remove() {
      if (currentRemoved)
        throw new IllegalStateException("Current element has already been removed");

      if (currentValue == null)
        throw new IllegalStateException("Next method was not called for given iterator");

      if (removeFromNewEntries(currentValue)) {
        if (size >= 0) size--;
      } else {
        Change counter = changedValues.get(currentValue);
        if (counter != null) {
          counter.decrement();
          if (size >= 0)
            if (counter.isUndefined()) size = -1;
            else size--;
        } else {
          if (nextChange != null) {
            changedValues.put(currentValue, new DiffChange(-1));
            changedValuesIterator =
                changedValues.tailMap(nextChange.getKey(), false).entrySet().iterator();
          } else {
            changedValues.put(currentValue, new DiffChange(-1));
          }

          size = -1;
        }
      }

      if (OSBTreeRidBag.this.owner != null)
        ORecordInternal.unTrack(OSBTreeRidBag.this.owner, currentValue);

      if (updateOwner)
        fireCollectionChangedEvent(
            new OMultiValueChangeEvent<OIdentifiable, OIdentifiable>(
                OMultiValueChangeEvent.OChangeType.REMOVE,
                currentValue,
                null,
                currentValue,
                false));
      currentRemoved = true;
    }
  @NotNull
  public Collection<Change> getChangesIn(final FilePath dirPath) {
    List<Change> changes = new ArrayList<Change>();
    for (ChangeList list : myMap.values()) {
      for (Change change : list.getChanges()) {
        final ContentRevision afterRevision = change.getAfterRevision();
        if (afterRevision != null && afterRevision.getFile().isUnder(dirPath, false)) {
          changes.add(change);
          continue;
        }

        final ContentRevision beforeRevision = change.getBeforeRevision();
        if (beforeRevision != null && beforeRevision.getFile().isUnder(dirPath, false)) {
          changes.add(change);
        }
      }
    }
    return changes;
  }
 private boolean isUnderOldDir(Change change, FilePath path) {
   if (change.getBeforeRevision() != null) {
     final boolean isUnder =
         FileUtil.isAncestor(
             path.getIOFile(), change.getBeforeRevision().getFile().getIOFile(), true);
     if (isUnder) {
       return true;
     }
   }
   if (change.getAfterRevision() != null) {
     final boolean isUnder =
         FileUtil.isAncestor(
             path.getIOFile(), change.getAfterRevision().getFile().getIOFile(), true);
     if (isUnder) {
       return isUnder;
     }
   }
   return false;
 }
    @Nullable
    private Intersection checkIntersection(
        @Nullable final List<CommittedChangeList> lists, List<LocalChangeList> localChangeLists) {
      if (lists == null || lists.isEmpty()) {
        return null;
      }
      final Set<FilePath> mergePaths = new HashSet<FilePath>();
      for (CommittedChangeList list : lists) {
        final SvnChangeList svnList = (SvnChangeList) list;
        final List<String> paths = new ArrayList<String>(svnList.getAddedPaths());
        paths.addAll(svnList.getChangedPaths());
        paths.addAll(svnList.getDeletedPaths());
        for (String path : paths) {
          final File localPath = getLocalPath(path);
          if (localPath != null) {
            mergePaths.add(new FilePathImpl(localPath, false));
          }
        }
      }

      final Intersection intersection = new Intersection();
      for (LocalChangeList localChangeList : localChangeLists) {
        final Collection<Change> localChanges = localChangeList.getChanges();

        for (Change localChange : localChanges) {
          final FilePath before =
              localChange.getBeforeRevision() == null
                  ? null
                  : localChange.getBeforeRevision().getFile();
          final FilePath after =
              localChange.getAfterRevision() == null
                  ? null
                  : localChange.getAfterRevision().getFile();

          if ((before != null && mergePaths.contains(before))
              || (after != null && mergePaths.contains(after))) {
            intersection.add(localChangeList.getName(), localChangeList.getComment(), localChange);
          }
        }
      }
      return intersection;
    }
  @Override
  public boolean contains(OIdentifiable identifiable) {
    if (newEntries.containsKey(identifiable)) return true;

    Change counter = changes.get(identifiable);

    if (counter != null) {
      AbsoluteChange absoluteValue = getAbsoluteValue(identifiable);

      if (counter.isUndefined()) {
        changes.put(identifiable, absoluteValue);
      }

      counter = absoluteValue;
    } else {
      counter = getAbsoluteValue(identifiable);
    }

    return counter.applyTo(0) > 0;
  }
 private void baseRevisionsOfDvcsIntoContext(
     List<Change> textChanges, CommitContext commitContext) {
   ProjectLevelVcsManager vcsManager = ProjectLevelVcsManager.getInstance(myProject);
   if (vcsManager.dvcsUsedInProject()
       && VcsConfiguration.getInstance(myProject).INCLUDE_TEXT_INTO_SHELF) {
     final Set<Change> big = SelectFilesToAddTextsToPatchPanel.getBig(textChanges);
     final ArrayList<FilePath> toKeep = new ArrayList<FilePath>();
     for (Change change : textChanges) {
       if (change.getBeforeRevision() == null || change.getAfterRevision() == null) continue;
       if (big.contains(change)) continue;
       FilePath filePath = ChangesUtil.getFilePath(change);
       final AbstractVcs vcs = vcsManager.getVcsFor(filePath);
       if (vcs != null && VcsType.distibuted.equals(vcs.getType())) {
         toKeep.add(filePath);
       }
     }
     commitContext.putUserData(BaseRevisionTextPatchEP.ourPutBaseRevisionTextKey, true);
     commitContext.putUserData(BaseRevisionTextPatchEP.ourBaseRevisionPaths, toKeep);
   }
 }