package com.limegroup.gnutella.filters;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

/**
 * A mutable list of IP addresses.  More specifically, a list of sets of
 * addresses, like "18.239.0.*".  Provides fast operations to find if an address
 * is in the list.  Used to implement IPFilter.  Not synchronized.
 *
 * @author Gregorio Roper 
 */
public class IPList {
    /** The list of IP's. */
    private List /* of IP */ ips = new LinkedList();

    public IPList () {}

    /** 
     * Adds a certain IP to the IPList.
     * @param ip_str a String containing the IP, see IP.java for formatting
     */
    public void add(String ip_str) {
	    IP ip;
        try {
            ip = new IP(ip_str);
        } catch (IllegalArgumentException e) {
            return;
        }
        
        if (!ips.contains(ip)) {// don't add the same IP more than once
            ips.add(ip);
        }
    }

    /**
     * @param String equal to an IP
     * @returns true if ip_address is contained somewhere in the list of IPs
     */
    public boolean contains (IP ip) {
        for (Iterator iter=ips.iterator(); iter.hasNext(); ) {
            IP pattern=(IP)iter.next();
            if (pattern.contains(ip))
                return true;
        }
        return false;
    }
    
    /**
     * Calculates the first set bit in the distance between an IPv4 address and
     * the ranges represented by this list.
     * 
     * This is equivalent to floor(log2(distance)) + 1.
     *  
     * @param ip an IPv4 address, represented as an IP object with a /32 netmask.
     * @return an int on the interval [0,31].
     */
    public int logMinDistanceTo(IP ip) {
        int distance = minDistanceTo(ip);
        int logDistance = 0;
        int testMask = -1; // All bits set
        // Guaranteed to terminate since testMask will reach zero
        while ((distance & testMask) != 0) {
            testMask <<= 1;
            ++logDistance;
        }
        return logDistance;
    }
    
    
    /**
     * Calculates the minimum distance between an IPv4 address this list of IPv4 address ranges.
     * 
     * @param ip an IPv4 address, represented as an IP object with a /32 netmask.
     * @return 32-bit unsigned distance (using xor metric), represented as Java int
     */
    public int minDistanceTo(IP ip) {
        if (ip.getMask() != -1) {
            throw new IllegalArgumentException("Expected single IP, not an IP range.");
        }
        // Note that this function uses xor with Integer.MIN_VALUE
        // to reverse the sense of the most significant bit.  This
        // causes the "<" and ">" operators to work properly even
        // though we're representing 32-bit unsinged values as
        // Java ints.
       int min_distance = Integer.MAX_VALUE;
       for (Iterator iter=ips.iterator(); iter.hasNext();) {
           IP ipRange = (IP) iter.next();
           int distance = Integer.MIN_VALUE ^ ipRange.getDistanceTo(ip);
           if (min_distance > distance) {
               min_distance = distance;
           }
       }
        
       // Change the most significant bit back to its normal sense.
       return Integer.MIN_VALUE ^ min_distance;
    }
}
