/*
 * 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.util.indexing.containers;

import com.intellij.util.indexing.ValueContainer;
import gnu.trove.TIntProcedure;

/**
* Created by Maxim.Mossienko on 5/27/2014.
*/
public class SortedIdSet implements Cloneable, RandomAccessIntContainer {
  private int[] mySet;
  private int mySetLength;
  private int mySize;

  public SortedIdSet(final int initialCapacity) {
    assert initialCapacity < Short.MAX_VALUE;
    mySet = new int[initialCapacity]; // todo slightly increase size
  }

  public SortedIdSet(final int[] array, int size) {
    mySet = array;
    mySetLength = mySize = size;
  }

  public boolean isEmpty() {
    return mySize == 0;
  }

  public int size() {
    return mySize;
  }

  public boolean add(int value) {
    assert value > 0;
    int pos;

    if (mySetLength == 0 || (mySetLength > 0 && Math.abs(mySet[mySetLength -1]) < value)) {
      pos = -mySetLength-1; // most of the time during bulk indexing we add near the end
    }
    else {
      pos = binarySearch(mySet, 0, mySetLength, value);
    }
    if (pos >= 0) {
      if (mySet[pos] > 0) return false;
      pos = -pos - 1; // found removed
    }
    if (mySetLength == mySet.length) {
      int nextArraySize = mySet.length < 1024 ? mySet.length << 1 : mySet.length + mySet.length / 5;
      int[] newSet = new int[nextArraySize];
      System.arraycopy(mySet, 0, newSet, 0, mySet.length);
      mySet = newSet;
    }
    pos = -pos - 1;

    boolean lengthIsIncreased = pos == mySetLength;  // insert at end
    if (!lengthIsIncreased && Math.abs(mySet[pos]) != value) { // todo we can shift until first removed
      System.arraycopy(mySet, pos, mySet, pos + 1, mySetLength - pos);
      lengthIsIncreased = true;
    }
    mySet[pos] = value;
    ++mySize;
    if (lengthIsIncreased) ++mySetLength;
    return true;
  }

  public boolean remove(int value) {
    assert value > 0;
    int pos = binarySearch(mySet, 0, mySetLength, value);
    if (pos < 0 || mySet[pos] < 0) return false;
    mySet[pos] = -value;
    //if (pos != mySetLength - 1) System.arraycopy(mySet, pos + 1, mySet, pos, mySetLength - pos - 1);
    --mySize;
    //--mySetLength;
    return true;
  }

  @Override
  public ValueContainer.IntIterator intIterator() {
    return new Iterator();
  }

  @Override
  public ValueContainer.IntPredicate intPredicate() {
    return new ValueContainer.IntPredicate() {

      @Override
      public boolean contains(int id) {
        return SortedIdSet.this.contains(id);
      }
    };
  }

  private class Iterator implements ValueContainer.IntIterator {
    private int myCursor;

    Iterator() {
      myCursor = findNext(0);
    }

    @Override
    public boolean hasNext() {
      return myCursor != -1;
    }

    @Override
    public int next() {
      int result = get(myCursor);
      myCursor = findNext(myCursor + 1);
      return result;
    }

    @Override
    public int size() {
      return SortedIdSet.this.size();
    }

    @Override
    public boolean hasAscendingOrder() {
      return true;
    }

    @Override
    public ValueContainer.IntIterator createCopyInInitialState() {
      return new Iterator();
    }
  }

  private static int binarySearch(int[] set, int off, int length, int key) {
    int low = off;
    int high = length - 1;

    while (low <= high) {
      int mid = (low + high) >>> 1;
      int midVal = Math.abs(set[mid]);

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

  public void forEach(TIntProcedure procedure) {
    for(int i = 0; i < mySetLength; ++i) {
      int value = mySet[i];
      if (value > 0 && !procedure.execute(value)) break;
    }
  }

  public boolean contains(int value) {
    assert value > 0;
    int pos = binarySearch(mySet, 0, mySetLength, value);
    return pos >= 0 && mySet[pos] > 0;
  }

  @Override
  public Object clone() {
    try {
      SortedIdSet set = (SortedIdSet)super.clone();
      set.mySet = mySet.clone();
      return set;
    }
    catch (CloneNotSupportedException e) {
      throw new RuntimeException(e);
    }
  }

  public void compact() {
    if(2 * mySize < mySetLength && mySetLength > 5) {
      int positivePosition = -1;
      for(int i = 0; i < mySetLength; ++i) {
        if (mySet[i] < 0) {
          while(i < mySetLength && mySet[i] < 0) ++i;

          if (i == mySetLength) {
            break;
          } else {
            mySet[++positivePosition] = mySet[i];
          }
        } else {
          ++positivePosition;
          if (i != positivePosition) mySet[positivePosition] = mySet[i];
        }
      }
      // todo slightly decrease size
      mySetLength = (short)(positivePosition + 1);
    }
  }

  public RandomAccessIntContainer ensureContainerCapacity(int count) {
    int newSize = mySetLength + count;
    if (newSize < mySet.length) return this;
    if (newSize > ChangeBufferingList.MAX_FILES) {
      return new IdBitSet(this, count);
    }

    newSize = ChangeBufferingList.calcNextArraySize(mySet.length, newSize);
    assert newSize < Short.MAX_VALUE;

    int[] newSet = new int[newSize]; // todo slightly increase size and compact
    System.arraycopy(mySet, 0, newSet, 0, mySetLength);
    mySet = newSet;

    return this;
  }

  public int findNext(int i) {
    while(i < mySetLength) {
      if (mySet[i] > 0) return i;
      ++i;
    }
    return -1;
  }

  public int get(int cursor) {
    assert cursor < mySetLength;
    int value = mySet[cursor];
    assert value > 0;
    return value;
  }
}
