blob: a6cfd12f9b9d4a7fd6d5695457d9c3b064cd6d4b [file] [log] [blame]
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.vcs.changes.committed;
import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList;
import java.util.*;
public class SimiliarListsZipper {
private final LinkedList<SubSequence<CommittedChangeList>> myLists;
private final List<CommittedChangeList> myResult;
private final VcsCommittedListsZipper myZipper;
private final RepositoryLocationGroup myGroup;
/**
*
* @param lists - MUST be internally ordered in ??? ascending order
* @param zipper
*/
public SimiliarListsZipper(final Collection<List<CommittedChangeList>> lists,
final VcsCommittedListsZipper zipper, final RepositoryLocationGroup group) {
myZipper = zipper;
myGroup = group;
myLists = new LinkedList<SubSequence<CommittedChangeList>>();
myResult = new ArrayList<CommittedChangeList>();
for (List<CommittedChangeList> list : lists) {
if (! list.isEmpty()) {
myLists.add(new SubSequence<CommittedChangeList>(list));
}
}
}
public void zip() {
Collections.sort(myLists);
while (! myLists.isEmpty()) {
// check for equality of first n things
if (tryZipFirstN()) {
continue;
}
if (! usualStep()) {
break;
}
}
}
private boolean usualStep() {
while (! myLists.isEmpty()) {
final SubSequence<CommittedChangeList> sequence = myLists.removeFirst();
myResult.add(sequence.getCurrentList());
if (sequence.hasNext()) {
sequence.next();
insert(sequence);
return true;
}
}
return false;
}
private boolean tryZipFirstN() {
final SubSequence<CommittedChangeList> firstSequence = myLists.getFirst();
List<SubSequence<CommittedChangeList>> removed = null;
List<CommittedChangeList> toBeZipped = null;
for (ListIterator<SubSequence<CommittedChangeList>> iterator = myLists.listIterator(1); iterator.hasNext();) {
final SubSequence<CommittedChangeList> sequence = iterator.next();
if (sequence.compareTo(firstSequence) != 0) {
break;
}
if (removed == null) {
removed = new ArrayList<SubSequence<CommittedChangeList>>();
toBeZipped = new ArrayList<CommittedChangeList>();
}
iterator.remove();
removed.add(sequence);
toBeZipped.add(sequence.getCurrentList());
}
if (removed != null) {
// also remove first
myLists.removeFirst();
// and add to equal collection
removed.add(firstSequence);
toBeZipped.add(firstSequence.getCurrentList());
final CommittedChangeList zippedList = myZipper.zip(myGroup, toBeZipped);
myResult.add(zippedList);
for (SubSequence<CommittedChangeList> sequence : removed) {
if (sequence.hasNext()) {
sequence.next();
insert(sequence);
}
}
return true;
}
return false;
}
private void insert(final SubSequence<CommittedChangeList> firstSequence) {
for (ListIterator<SubSequence<CommittedChangeList>> iterator = myLists.listIterator(); iterator.hasNext();) {
final SubSequence<CommittedChangeList> currentSequence = iterator.next();
if (currentSequence.compareTo(firstSequence) > 0) {
iterator.previous();
iterator.add(firstSequence);
return;
}
}
myLists.addLast(firstSequence);
}
public List<CommittedChangeList> getResult() {
return myResult;
}
private class SubSequence<T extends CommittedChangeList> implements Comparable<SubSequence<T>> {
private int myIdx;
private long myCachedNumber;
private final List<T> myList;
private SubSequence(final List<T> list) {
myList = list;
myIdx = 0;
myCachedNumber = myZipper.getNumber(myList.get(0));
}
boolean hasNext() {
return myIdx < (myList.size() - 1);
}
public int compareTo(final SubSequence<T> other) {
final long sign = myCachedNumber - other.myCachedNumber;
return sign == 0 ? 0 : ((sign < 0) ? -1 : 1);
}
void next() {
if (hasNext()) {
++ myIdx;
myCachedNumber = myZipper.getNumber(myList.get(myIdx));
}
}
T getCurrentList() {
return myList.get(myIdx);
}
}
}