package com.limegroup.gnutella.util;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.limewire.io.IpPort;
import org.limewire.io.NetworkUtils;
import org.limewire.util.ByteUtils;
import org.limewire.util.StringUtils;
/**
* Utility class keeps track of masked ip ranges and an associated count.
*/
// TODO rename class to reflect that it is more flexible than class c networks
public class ClassCNetworks {
private final Map<Integer, Integer> counts = new HashMap<Integer,Integer>();
/** Utility comparator to use for sorting class C networks */
static final Comparator<Map.Entry<Integer,Integer>> CLASS_C_COMPARATOR =
new Comparator<Map.Entry<Integer, Integer>>() {
public int compare(Map.Entry<Integer, Integer> a, Map.Entry<Integer, Integer> b) {
return b.getValue().compareTo(a.getValue());
}
};
private final int mask;
public ClassCNetworks() {
this(24);
}
public ClassCNetworks(int mask) {
this.mask = NetworkUtils.getHexMask(mask);
}
public void addAll(Collection<? extends IpPort> c) {
for (IpPort ip : c)
add(ip.getInetAddress(), 1);
}
public void add(InetAddress addr, int count) {
add(NetworkUtils.getMaskedIP(addr, mask), count);
}
public void add(int masked, int count) {
masked &= mask;
Integer num = counts.get(masked);
if (num == null) {
num = Integer.valueOf(0);
}
num = Integer.valueOf(num.intValue() + count);
counts.put(masked, num);
}
public List<Map.Entry<Integer, Integer>> getTop() {
List<Map.Entry<Integer, Integer>> ret =
new ArrayList<Map.Entry<Integer,Integer>>(counts.size());
ret.addAll(counts.entrySet());
Collections.sort(ret, CLASS_C_COMPARATOR);
return ret;
}
/** Returns the top n class C networks in easy to bencode format.*/
public byte [] getTopInspectable(int number) {
List<Map.Entry<Integer, Integer>> top = getTop();
number = Math.min(top.size(), number);
byte [] ret = new byte[8 * number];
int i = 0;
for (Map.Entry<Integer, Integer> entry : top) {
if (i == number)
break;
ByteUtils.int2beb(entry.getKey(), ret, i * 8);
ByteUtils.int2beb(entry.getValue(), ret, i * 8 + 4);
i++;
}
return ret;
}
/**
* @return exposes the map.
*/
public Map<Integer,Integer> getMap() {
return counts;
}
@Override
public String toString() {
return StringUtils.toString(this, mask, counts);
}
/**
* Combines the provided class C networks into this one.
*/
public void addAll(ClassCNetworks... other) {
for(ClassCNetworks c : other) {
for (int classC : c.getMap().keySet())
add(classC,c.getMap().get(classC));
}
}
}