package edu.umass.cs.ciir.waltz.coders.map.impl.vocab;

import ciir.jfoley.chai.collections.util.Comparing;
import ciir.jfoley.chai.collections.util.ListFns;
import ciir.jfoley.chai.fn.TransformFn;

import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;

/**
 * @author jfoley
 */
public interface ListIndex<T,K> {

  static <T,K> ListIndex<T,K> create(String kind, List<T> inner, TransformFn<T, K> keyFn) {
    return create(kind, inner, keyFn, Comparing.defaultComparator());
  }
  static <T,K> ListIndex<T,K> create(String kind, List<T> inner, TransformFn<T, K> keyFn, Comparator<K> keyCmp) {
    switch (kind.toLowerCase()) {
      case "none":
        return new NoIndex<>(inner, keyFn, keyCmp);
      case "hashall":
        return new HashAllIndex<>(inner, keyFn);
      default: throw new UnsupportedOperationException(kind);
    }
  }

  T find(K key);

  class NoIndex<T,K> implements ListIndex<T,K> {
    public final List<T> inner;
    public final TransformFn<T,K> keyFn;
    public final Comparator<K> keyCmp;

    public NoIndex(List<T> inner, TransformFn<T, K> keyFn, Comparator<K> keyCmp) {
      this.inner = inner;
      this.keyFn = keyFn;
      this.keyCmp = keyCmp;
    }

    @Override
    public T find(K key) {
      int pos = Collections.binarySearch(ListFns.lazyMap(inner, keyFn), key, keyCmp);
      if(pos < 0) return null;
      return inner.get(pos);
    }
  }

  class HashAllIndex<T,K> implements ListIndex<T,K> {
    private final HashMap<K,T> items;

    public HashAllIndex(List<T> inner, TransformFn<T, K> keyFn) {
      items = new HashMap<>();
      for (T t : inner) {
        items.put(keyFn.transform(t), t);
      }
    }

    @Override
    public T find(K key) {
      return items.get(key);
    }
  }

}

@@ -101,16 +101,70 @@
 paring;%0A
+import ciir.jfoley.chai.collections.util.IterableFns;%0A
 import c
@@ -246,16 +246,44 @@
 ormFn;%0A%0A
+import java.util.ArrayList;%0A
 import j
@@ -362,31 +362,8 @@
 Map;
-%0Aimport java.util.List;
 %0A%0A/*
@@ -463,36 +463,40 @@
 te(String kind, 
-List
+Iterable
 %3CT%3E inner, Trans
@@ -641,20 +641,24 @@
 g kind, 
-List
+Iterable
 %3CT%3E inne
@@ -1042,16 +1042,21 @@
 c final 
+Array
 List%3CT%3E 
@@ -1158,28 +1158,32 @@
 lic NoIndex(
-List
+Iterable
 %3CT%3E inner, T
@@ -1249,21 +1249,85 @@
 inner = 
-inner
+new ArrayList%3C%3E();%0A      IterableFns.intoSink(inner, this.inner::add)
 ;%0A      
@@ -1696,20 +1696,24 @@
 llIndex(
-List
+Iterable
 %3CT%3E inne

build these guys from Iterables instead of Lists -- they shouldn't necessarily expect it to be materialized