// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.util.indexing;

import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.util.Pair;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.*;

final class IndexConfiguration {
  private final Map<ID<?, ?>, Pair<UpdatableIndex<?, ?, FileContent>, FileBasedIndex.InputFilter>> myIndices = new HashMap<>();
  private final Object2IntMap<ID<?, ?>> myIndexIdToVersionMap = new Object2IntOpenHashMap<>();
  private final List<ID<?, ?>> myIndicesWithoutFileTypeInfo = new ArrayList<>();
  private final Map<FileType, List<ID<?, ?>>> myFileType2IndicesWithFileTypeInfoMap = new HashMap<>();
  private volatile boolean myFreezed;

  <K, V> UpdatableIndex<K, V, FileContent> getIndex(@NotNull ID<K, V> indexId) {
    assert myFreezed;
    final Pair<UpdatableIndex<?, ?, FileContent>, FileBasedIndex.InputFilter> pair = myIndices.get(indexId);

    //noinspection unchecked
    return (UpdatableIndex<K, V, FileContent>)Pair.getFirst(pair);
  }

  @NotNull
  FileBasedIndex.InputFilter getInputFilter(@NotNull ID<?, ?> indexId) {
    assert myFreezed;
    final Pair<UpdatableIndex<?, ?, FileContent>, FileBasedIndex.InputFilter> pair = myIndices.get(indexId);

    assert pair != null : "Index data is absent for index " + indexId;

    return pair.getSecond();
  }

  void freeze() {
    myFreezed = true;
  }

  <K, V> void registerIndex(@NotNull ID<K, V> name,
                            @NotNull UpdatableIndex<K, V, FileContent> index,
                            @NotNull FileBasedIndex.InputFilter inputFilter,
                            int version,
                            @Nullable Collection<? extends FileType> associatedFileTypes) {
    assert !myFreezed;

    synchronized (myIndices) {
      myIndexIdToVersionMap.put(name, version);

      if (associatedFileTypes != null) {
        for(FileType fileType:associatedFileTypes) {
          List<ID<?, ?>> ids = myFileType2IndicesWithFileTypeInfoMap.computeIfAbsent(fileType, __ -> new ArrayList<>(5));
          ids.add(name);
        }
      }
      else {
        myIndicesWithoutFileTypeInfo.add(name);
      }

      Pair<UpdatableIndex<?, ?, FileContent>, FileBasedIndex.InputFilter> old = myIndices.put(name, new Pair<>(index, inputFilter));
      if (old != null) {
        throw new IllegalStateException("Index " + old.first + " already registered for the name '" + name + "'");
      }
    }
  }

  @NotNull
  List<ID<?, ?>> getFileTypesForIndex(@NotNull FileType fileType) {
    assert myFreezed;
    List<ID<?, ?>> ids = myFileType2IndicesWithFileTypeInfoMap.get(fileType);
    if (ids == null) ids = myIndicesWithoutFileTypeInfo;
    return ids;
  }

  void finalizeFileTypeMappingForIndices() {
    assert !myFreezed;
    synchronized (myIndices) {
      for (List<ID<?, ?>> value : myFileType2IndicesWithFileTypeInfoMap.values()) {
        value.addAll(myIndicesWithoutFileTypeInfo);
      }
    }
  }

  @NotNull
  Collection<ID<?, ?>> getIndexIDs() {
    assert myFreezed;
    return myIndices.keySet();
  }

  int getIndexVersion(@NotNull ID<?, ?> id) {
    assert myFreezed;
    return myIndexIdToVersionMap.getInt(id);
  }
}

@@ -258,16 +258,71 @@
 l.Pair;%0A
+import com.intellij.util.containers.CollectionFactory;%0A
 import i
@@ -361,24 +361,24 @@
 ect2IntMap;%0A
-
 import it.un
@@ -676,29 +676,63 @@
 dices = 
-new Hash
+CollectionFactory.createSmallMemoryFootprint
 Map
-%3C%3E
 ();%0A  pr
@@ -993,21 +993,55 @@
 p = 
-new Hash
+CollectionFactory.createSmallMemoryFootprint
 Map
-%3C%3E
 ();%0A

use fastutil