package be.iminds.ilabt.jfed.experimenter_gui.util;

import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * User: twalcari
 * Date: 7/29/2014
 * Time: 14:30
 */
public class InetAddressUtil {

    private static final Pattern IPV4_ADDRESS = Pattern.compile("^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$");
    private static final Pattern IPV6_STD_PATTERN = Pattern.compile("^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$");

    private static final Pattern IPV6_HEX_COMPRESSED_PATTERN = Pattern.compile(
                    "^((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)$");


    /**
     * Validates an IPv4 address. Returns true if valid.
     *
     * @param inet4Address the IPv4 address to validate
     * @return true if the argument contains a valid IPv4 address
     */
    public static boolean isValidInet4Address(String inet4Address) {
        if (inet4Address == null)
            return false;

        // verify that address conforms to the IPv4 format
        Matcher matcher = IPV4_ADDRESS.matcher(inet4Address);
        if (!matcher.matches())
            return false;


        // verify that address subgroups are legal
        for (int i = 1; i <= 4; i++) {
            String group = matcher.group(i);
            if (group == null || group.length() <= 0) {
                return false;
            }

            int ipSegment;

            try {
                ipSegment = Integer.parseInt(group);
            } catch (NumberFormatException e) {
                return false;
            }

            //smaller than 0 is not possible because of regex
            if (ipSegment > 255) {
                return false;
            }

        }

        return true;
    }

    /**
     * Simplifies an IPv4-address by removing any trailing zeros
     *
     * @param inet4Address valid IPv4 address to simplify
     * @return A simplified IPv4-address
     */
    public static String simplifyInet4Address(String inet4Address) {
        if (inet4Address == null)
            return null;

        // verify that address conforms to the IPv4 format
        Matcher matcher = IPV4_ADDRESS.matcher(inet4Address);
        if (!matcher.matches())
            return null;


        // verify that address subgroups are legal
        int ipSegment1 = Integer.parseInt(matcher.group(1));
        int ipSegment2 = Integer.parseInt(matcher.group(2));
        int ipSegment3 = Integer.parseInt(matcher.group(3));
        int ipSegment4 = Integer.parseInt(matcher.group(4));


        return ipSegment1 + "." + ipSegment2 + "." + ipSegment3 + "." + ipSegment4;
    }

    public static String getInet4Subnetwork(String inet4Address) {
        if (inet4Address == null)
            return null;

        // verify that address conforms to the IPv4 format
        Matcher matcher = IPV4_ADDRESS.matcher(inet4Address);
        if (!matcher.matches())
            return null;

        return matcher.group(1) + "." + matcher.group(2) + "." + matcher.group(3);
    }

    public static String getInet6Subnetwork(String inet6Address) {
        if (inet6Address == null)
            return null;

        // verify that address conforms to the IPv4 format
        Matcher matcher = IPV6_STD_PATTERN.matcher(inet6Address);
        if (!matcher.matches()) {
            matcher = IPV6_HEX_COMPRESSED_PATTERN.matcher(inet6Address);
        }
        if (!matcher.matches())
            return null;

        return matcher.group(1) + ":" + matcher.group(2) + ":" + matcher.group(3) + ":" + matcher.group(4);
    }

    private static final Random RAND = new Random();

    public static String generateInet6Subnetwork() {
        long randomSubnet = RAND.nextLong();

        String randomHex = Long.toHexString(RAND.nextLong());

        String subnet = "fd" + randomHex.substring(0, 2) + "7fed" + randomHex.substring(2, 10);

        return subnet.substring(0, 4) + ":" + subnet.substring(4, 8) + ":" +
                subnet.substring(8, 12) + ":" + subnet.substring(12, 16);
    }


    public static boolean isValidInet6StdAddress(final String input) {

        return IPV6_STD_PATTERN.matcher(input).matches();
    }

    public static boolean isValidInet6HexCompressedAddress(final String input) {

        return IPV6_HEX_COMPRESSED_PATTERN.matcher(input).matches();
    }

    public static boolean isValidInet6Address(final String input) {

        return isValidInet6StdAddress(input) || isValidInet6HexCompressedAddress(input);
    }

    public static boolean isValidInet6Netmask(String input) {

        try {
            int result = Integer.parseInt(input);
            return result > 0 && result <= 128;
        } catch (NumberFormatException ex) {
            return false;
        }
    }

}
