/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package org.anarres.dhcp.common.address;

import com.google.common.net.InetAddresses;
import java.net.InetAddress;
import java.util.Arrays;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;

/**
 * A network address: A base address and a netmask representing a contiguous
 * range of addresses.
 * 
 * The base address is canonicalized by the constructor to be the
 * first address in the permissible range. Thus {@link #getAddress()}
 * will NOT necessarily return the same {@link InetAddress} as was passed
 * to the constructor.
 * 
 * @see NetworkSet
 *
 * @author shevek
 */
public class NetworkAddress extends AbstractMaskedAddress {

    /**
     * Constructs a NetworkAddress from a String of the form 1.2.3.4/25.
     * @throws IllegalArgumentException if the argument was duff.
     */
    @Nonnull
    public static NetworkAddress forString(@Nonnull String addressString) {
        String netmaskString = null;
        int idx = addressString.indexOf('/');
        if (idx != -1) {
            netmaskString = addressString.substring(idx + 1);
            addressString = addressString.substring(0, idx);
        }
        InetAddress address = InetAddresses.forString(addressString);
        int netmask;
        if (netmaskString != null) {
            try {
                netmask = Integer.parseInt(netmaskString);
            } catch (NumberFormatException e) {
                throw new IllegalArgumentException("Cannot parse netmask from " + netmaskString, e);
            }
        } else {
            netmask = address.getAddress().length * Byte.SIZE;
        }
        return new NetworkAddress(address, netmask);
    }

    /**
     * This constructor canonicalizes the fundamental address to be the network address.
     */
    public NetworkAddress(@Nonnull InetAddress address, @Nonnegative int netmask) {
        super(AddressUtils.toNetworkAddress(address, netmask), netmask);
    }

    @Override
    public InetAddress getNetworkAddress() {
        return getAddress();
    }

    /**
     * Returns the <code>index</code>th machine address in this network.
     *
     * The 0th address is the network address. The first usable address is index 1.
     * Treats index as unsigned.
     * If your network is larger than 2^64 machines, you are out of luck
     * with this method.
     *
     * @see AddressUtils#add(InetAddress, long)
     */
    @Nonnull
    public InterfaceAddress getMachineAddress(long index) {
        InetAddress address = AddressUtils.add(getNetworkAddress(), index);
        return new InterfaceAddress(address, getNetmask());
    }

    /**
     * Returns true iff this network contains the given InetAddress.
     */
    public boolean contains(@Nonnull InetAddress address) {
        if (!getAddress().getClass().equals(address.getClass()))
            return false;
        byte[] network = AddressUtils.toNetworkAddress(address.getAddress(), getNetmask());
        return Arrays.equals(getAddress().getAddress(), network);
    }

    /**
     * Returns true iff this network contains the whole of the given network.
     * That is to say, the given network represents a sub-network of this network.
     */
    public boolean contains(@Nonnull NetworkAddress networkAddress) {
        return contains(networkAddress.getNetworkAddress())
                && contains(networkAddress.getBroadcastAddress());
    }

    /**
     * Returns an InetAddressRange representation of this network's address range.
     * 
     * The InetAddressRange isn't as useful for computation, but can be
     * useful for display or configuring other tools.
     */
    @Nonnull
    public InetAddressRange toRange() {
        return new InetAddressRange(getNetworkAddress(), getBroadcastAddress());
    }
}

@@ -2382,41 +2382,8 @@
  1.%0A
-     * Treats index as unsigned.%0A
     
@@ -2419,17 +2419,17 @@
 than 2%5E6
-4
+3
  machine
@@ -2479,24 +2479,70 @@
 hod.%0A     *%0A
+     * @see #getMachineInterfaceAddress(long)%0A
      * @see 
@@ -2611,23 +2611,18 @@
 ublic In
-terfac
 e
+t
 Address 
@@ -2635,24 +2635,37 @@
 hineAddress(
+@Nonnegative 
 long index) 
@@ -2678,75 +2678,625 @@
     
-InetAddress address = AddressUtils.add(getNetworkAddress(),
+return AddressUtils.add(getNetworkAddress(), index);%0A    %7D%0A%0A    /**%0A     * Returns the %3Ccode%3Eindex%3C/code%3Eth machine address in this network.%0A     *%0A     * The 0th address is the network address. The first usable address is index 1.%0A     * If your network is larger than 2%5E63 machines, you are out of luck%0A     * with this method.%0A     *%0A     * The netmask in the returned %7B@link InterfaceAddress%7D is that of this%0A     * NetworkAddress.%0A     *%0A     * @see #getMachineAddress(long)%0A     * @see AddressUtils#add(InetAddress, long)%0A     */%0A    @Nonnull%0A    public InterfaceAddress getMachineInterfaceAddress(long
  index)
-;
+ %7B
 %0A   
@@ -3328,23 +3328,40 @@
 Address(
-address
+getMachineAddress(index)
 , getNet

Extend NetworkAddress utility methods.