/*
 * Copyright 2000-2014 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;

import com.intellij.openapi.util.Pair;
import com.intellij.util.Consumer;
import com.intellij.util.Processor;
import com.intellij.util.containers.ReadonlyList;
import com.intellij.util.containers.StepList;
import org.jetbrains.annotations.Nullable;

import java.util.Comparator;
import java.util.List;

/**
 * @author irengrig
 */
public class ReadonlyListsMerger<T> {
  private final List<ReadonlyList<T>> myLists;
  private final Consumer<CompoundNumber> myConsumer;
  private final Comparator<Pair<CompoundNumber, T>> myComparator;

  private ReadonlyListsMerger(final List<ReadonlyList<T>> lists, final Consumer<CompoundNumber> consumer, final Comparator<Pair<CompoundNumber, T>> comparator) {
    myLists = lists;
    myConsumer = consumer;
    myComparator = comparator;
  }

  public static<T extends Comparable<T>> void merge(final List<ReadonlyList<T>> lists, final Consumer<CompoundNumber> consumer) {
    new ReadonlyListsMerger<T>(lists, consumer, new MyComparator<T>()).execute();
  }

  public static<T> void merge(final List<ReadonlyList<T>> lists, final Consumer<CompoundNumber> consumer, final Comparator<Pair<CompoundNumber, T>> comparator) {
    new ReadonlyListsMerger<T>(lists, consumer, comparator).execute();
  }

  public void execute() {
    final int[] idxs = new int[myLists.size()];
    for (int i = 0; i < myLists.size(); i++) {
      final ReadonlyList<T> member = myLists.get(i);
      idxs[i] = member.getSize() == 0 ? -1 : 0;
    }

    while (true) {
      CompoundNumber minIdxs = null;
      for (int i = 0; i < idxs.length; i++) {
        if (idxs[i] == -1) continue;  // at end
        final ReadonlyList<T> list = myLists.get(i);
        if ((minIdxs == null) || (myComparator.compare(Pair.create(new CompoundNumber(i, idxs[i]), list.get(idxs[i])),
                                                       Pair.create(minIdxs, myLists.get(minIdxs.getMemberNumber()).get(minIdxs.getIdx()))) <= 0)) {
          minIdxs = new CompoundNumber(i, idxs[i]);
        }
      }
      if (minIdxs == null) return;
      myConsumer.consume(minIdxs);
      final int memberIdx = minIdxs.getMemberNumber();
      idxs[memberIdx] = (myLists.get(memberIdx).getSize() == (idxs[memberIdx] + 1) ? -1 : idxs[memberIdx] + 1);
    }
  }

  public static<T> void firstPlusSecond(final StepList<T> first, final ReadonlyList<T> second, final Comparator<T> comparator,
                                        @Nullable final Consumer<T> beforeAddListener, final Processor<T> filter) {
    if (second.getSize() == 0) return;
    int idx = stolenBinarySearch(first, second.get(0), comparator, 0);
    if (idx < 0) {
      idx = - (idx + 1);
    }
    // for group headers to not be left alone without its group
    if (idx > 0 && (! filter.process(first.get(idx - 1)))) {
      -- idx;
      if (idx > 0) --idx;
    }
    final ReadonlyList<T> remergePart = first.cut(idx);
    merge(remergePart, second, comparator, new Consumer<T>() {
      @Override
      public void consume(T t) {
        if (beforeAddListener != null) {
          beforeAddListener.consume(t);
        }
        first.add(t);
      }
    }, filter);
  }

  public static<T> void merge(final ReadonlyList<T> one,
                              final ReadonlyList<T> two,
                              final Comparator<T> comparator,
                              final Consumer<T> adder, final Processor<T> filter) {
    int idx1 = 0;
    int idx2 = 0;
    while (idx1 < one.getSize() && idx2 < two.getSize()) {
      final T firstOne = one.get(idx1);
      if (! filter.process(firstOne)) {
        ++ idx1;
        continue;
      }
      final int comp = comparator.compare(firstOne, two.get(idx2));
      if (comp <= 0) {
        adder.consume(firstOne);
        ++ idx1;
      } else {
        adder.consume(two.get(idx2));
        ++ idx2;
      }
    }
    while (idx1 < one.getSize()) {
      final T firstOne = one.get(idx1);
      if (! filter.process(firstOne)) {
        ++ idx1;
        continue;
      }
      adder.consume(one.get(idx1));
      ++ idx1;
    }
    while (idx2 < two.getSize()) {
      adder.consume(two.get(idx2));
      ++ idx2;
    }
  }
  /*private static<T> int insertIdx(final ReadonlyList<T> first, final int from, final T t, final Comparator<T> comparator) {
    int idx = stolenBinarySearch(first, t, comparator, from);
    if (idx < 0) {
      idx = - (idx + 1);
    }
    first.
  }*/

  private static <T> int stolenBinarySearch(ReadonlyList<? extends T> l, T key, Comparator<? super T> c, final int from) {
      int low = from;
      int high = (l.getSize() - from) -1;

      while (low <= high) {
          int mid = (low + high) >>> 1;
          T midVal = l.get(mid);
          int cmp = c.compare(midVal, key);

          if (cmp < 0)
              low = mid + 1;
          else if (cmp > 0)
              high = mid - 1;
          else
              return mid; // key found
      }
      return -(low + 1);  // key not found
  }

  private static class MyComparator<T extends Comparable<T>> implements Comparator<Pair<CompoundNumber, T>> {
    @Override
    public int compare(final Pair<CompoundNumber, T> o1, final Pair<CompoundNumber, T> o2) {
      return o1.getSecond().compareTo(o2.getSecond());
    }
  }
}
