// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/**
 *******************************************************************************
 * Copyright (C) 1996-2015, International Business Machines Corporation and    *
 * others. All Rights Reserved.                                                *
 *******************************************************************************
 */

package com.ibm.icu.dev.test.collator;


import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

public class Counter<T> implements Iterable<T>, Comparable<Counter<T>> {
  Map<T,RWLong> map;
  Comparator<T> comparator;
  
  public Counter() {
    this(null);
  }
  
  public Counter(Comparator<T> comparator) {
    if (comparator != null) {
      this.comparator = comparator;
      map = new TreeMap<T, RWLong>(comparator);
    } else {
      map = new LinkedHashMap<T, RWLong>();
    }
  }
  
  static private final class RWLong implements Comparable<RWLong> {
    // the uniqueCount ensures that two different RWIntegers will always be different
    static int uniqueCount;
    public long value;
    private final int forceUnique;
    {
      synchronized (RWLong.class) { // make thread-safe
        forceUnique = uniqueCount++;
      }
    }

    public int compareTo(RWLong that) {
      if (that.value < value) return -1;
      if (that.value > value) return 1;
      if (this == that) return 0;
      synchronized (this) { // make thread-safe
        if (that.forceUnique < forceUnique) return -1;
      }
      return 1; // the forceUnique values must be different, so this is the only remaining case
    }
    public String toString() {
      return String.valueOf(value);
    }
  }

  public Counter<T> add(T obj, long countValue) {
    RWLong count = map.get(obj);
    if (count == null) map.put(obj, count = new RWLong());
    count.value += countValue;
    return this;
  }

  public long getCount(T obj) {
      return get(obj);
    }

  public long get(T obj) {
      RWLong count = map.get(obj);
      return count == null ? 0 : count.value;
    }

  public Counter<T> clear() {
    map.clear();
    return this;
  }

  public long getTotal() {
    long count = 0;
    for (T item : map.keySet()) {
      count += map.get(item).value;
    }
    return count;
  }

  public int getItemCount() {
    return size();
  }
  
  private static class Entry<T> {
    RWLong count;
    T value;
    int uniqueness;
    public Entry(RWLong count, T value, int uniqueness) {
      this.count = count;
      this.value = value;
      this.uniqueness = uniqueness;
    }
  }
  
  private static class EntryComparator<T> implements Comparator<Entry<T>>{
    int countOrdering;
    Comparator<T> byValue;
    
    public EntryComparator(boolean ascending, Comparator<T> byValue) {
      countOrdering = ascending ? 1 : -1;
      this.byValue = byValue;
    }
    public int compare(Entry<T> o1, Entry<T> o2) {
      if (o1.count.value < o2.count.value) return -countOrdering;
      if (o1.count.value > o2.count.value) return countOrdering;
      if (byValue != null) {
        return byValue.compare(o1.value, o2.value);
      }
      return o1.uniqueness - o2.uniqueness;
    }
  }

  public Set<T> getKeysetSortedByCount(boolean ascending) {
    return getKeysetSortedByCount(ascending, null);
  }
  
  public Set<T> getKeysetSortedByCount(boolean ascending, Comparator<T> byValue) {
    Set<Entry<T>> count_key = new TreeSet<Entry<T>>(new EntryComparator<T>(ascending, byValue));
    int counter = 0;
    for (T key : map.keySet()) {
      count_key.add(new Entry<T>(map.get(key), key, counter++));
    }
    Set<T> result = new LinkedHashSet<T>();
    for (Entry<T> entry : count_key) {
       result.add(entry.value);
    }
    return result;
  }

  public Set<T> getKeysetSortedByKey() {
    Set<T> s = new TreeSet<T>(comparator);
    s.addAll(map.keySet());
    return s;
  }

//public Map<T,RWInteger> getKeyToKey() {
//Map<T,RWInteger> result = new HashMap<T,RWInteger>();
//Iterator<T> it = map.keySet().iterator();
//while (it.hasNext()) {
//Object key = it.next();
//result.put(key, key);
//}
//return result;
//}

  public Set<T> keySet() {
    return map.keySet();
  }

  public Iterator<T> iterator() {
    return map.keySet().iterator();
  }

  public Map<T, RWLong> getMap() {
    return map; // older code was protecting map, but not the integer values.
  }

  public int size() {
    return map.size();
  }

  public String toString() {
    return map.toString();
  }

  public Counter<T> addAll(Collection<T> keys, int delta) {
    for (T key : keys) {
      add(key, delta);
    }
    return this;
  }
  
  public Counter<T> addAll(Counter<T> keys) {
    for (T key : keys) {
      add(key, keys.getCount(key));
    }
    return this;
  }

  public int compareTo(Counter<T> o) {
    Iterator<T> i = map.keySet().iterator();
    Iterator<T> j = o.map.keySet().iterator();
    while (true) {
      boolean goti = i.hasNext();
      boolean gotj = j.hasNext();
      if (!goti || !gotj) {
        return goti ? 1 : gotj ? -1 : 0;
      }
      T ii = i.next();
      T jj = i.next();
      int result = ((Comparable<T>)ii).compareTo(jj);
      if (result != 0) {
        return result;
      }
      final long iv = map.get(ii).value;
      final long jv = o.map.get(jj).value;
      if (iv != jv) return iv < jv ? -1 : 0;
    }
  }

  public Counter<T> increment(T key) {
    return add(key, 1);
  }

public boolean containsKey(T key) {
    return map.containsKey(key);
}

public boolean equals(Object o) {
    return map.equals(o);
}

public int hashCode() {
    return map.hashCode();
}

public boolean isEmpty() {
    return map.isEmpty();
}

public Counter<T> remove(T key) {
    map.remove(key);
    return this;
}

//public RWLong put(T key, RWLong value) {
//    return map.put(key, value);
//}
//
//public void putAll(Map<? extends T, ? extends RWLong> t) {
//    map.putAll(t);
//}
//
//public Set<java.util.Map.Entry<T, Long>> entrySet() {
//    return map.entrySet();
//}
//
//public Collection<RWLong> values() {
//    return map.values();
//}

}
