package tc.oc.commons.bukkit.util;
import java.util.Iterator;
import gnu.trove.impl.Constants;
import gnu.trove.iterator.TIntIntIterator;
import gnu.trove.iterator.TIntIterator;
import gnu.trove.map.TIntIntMap;
import gnu.trove.map.hash.TIntIntHashMap;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.material.MaterialData;
import org.bukkit.util.BlockVector;
import static tc.oc.commons.bukkit.util.MaterialUtils.decodeMaterial;
import static tc.oc.commons.bukkit.util.MaterialUtils.encodeMaterial;
/**
* Efficiently counts distinct {@link MaterialData}s
*/
public class MaterialCounter {
private final TIntIntMap counts;
private MaterialCounter(TIntIntMap counts) {
this.counts = counts;
}
public MaterialCounter() {
this(new TIntIntHashMap(Constants.DEFAULT_CAPACITY, Constants.DEFAULT_LOAD_FACTOR, -1, 0));
}
public MaterialCounter(MaterialCounter other) {
this(new TIntIntHashMap(other.counts));
}
public boolean contains(int encodedMaterial) {
return counts.containsKey(encodedMaterial);
}
public boolean contains(int typeId, byte metadata) {
return contains(encodeMaterial(typeId, metadata));
}
public boolean contains(MaterialData material) {
return contains(encodeMaterial(material));
}
public int get(int encodedMaterial) {
return counts.get(encodedMaterial);
}
public int get(int typeId, byte metadata) {
return get(encodeMaterial(typeId, metadata));
}
public int get(MaterialData material) {
return get(encodeMaterial(material));
}
public int increment(int encodedMaterial, int count) {
return counts.adjustOrPutValue(encodedMaterial, count, count);
}
public int increment(int typeId, byte metadata, int count) {
return increment(encodeMaterial(typeId, metadata), count);
}
public int increment(MaterialData material, int count) {
return increment(encodeMaterial(material), count);
}
public int increment(BlockState block, int count) {
return increment(encodeMaterial(block), count);
}
public int analyze(World world, BlockVector pos) {
return increment(encodeMaterial(world, pos), 1);
}
public int analyze(Location location) {
return increment(encodeMaterial(location), 1);
}
public int analyze(Block block) {
return increment(encodeMaterial(block), 1);
}
public int analyze(BlockState block) {
return increment(encodeMaterial(block), 1);
}
public void analyze(World world, Iterator<BlockVector> blocks) {
while(blocks.hasNext()) {
analyze(world, blocks.next());
}
}
public void clear() {
counts.clear();
}
public void addAll(MaterialCounter other) {
for(TIntIntIterator iter = other.counts.iterator(); iter.hasNext();) {
iter.advance();
counts.adjustOrPutValue(iter.key(), iter.value(), iter.value());
}
}
public Iterable<MaterialData> materials() {
return new Iterable<MaterialData>() {
@Override
public Iterator<MaterialData> iterator() {
return new Iterator<MaterialData>() {
final TIntIterator iter = counts.keySet().iterator();
@Override
public boolean hasNext() {
return iter.hasNext();
}
@Override
public MaterialData next() {
return decodeMaterial(iter.next());
}
@Override
public void remove() {
iter.remove();
}
};
}
};
}
}