package be.iminds.ilabt.jfed.connectivity_tester;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Objects;

/**
 * User: wvdemeer
 */
public abstract class ResolveTest implements ConnectivityTest {
    private final String address;
    private final boolean useAlternativeResolver;
    private final String expectedAddress;

    private final String ipVersion;
    private final Class<? extends InetAddress> inetAddressClass;

    public ResolveTest(String ipVersion, Class<? extends InetAddress> inetAddressClass, String address, boolean useAlternativeResolver) {
        this.ipVersion = ipVersion;
        this.inetAddressClass = inetAddressClass;
        this.address = address;
        this.useAlternativeResolver = useAlternativeResolver;
        this.expectedAddress = null;
    }

    public ResolveTest(String ipVersion, Class<? extends InetAddress> inetAddressClass, String address, boolean useAlternativeResolver, String expectedAddress) {
        this.ipVersion = ipVersion;
        this.inetAddressClass = inetAddressClass;
        this.address = address;
        this.useAlternativeResolver = useAlternativeResolver;
        this.expectedAddress = expectedAddress;
    }

    @Override
    public String getName() {
        return "DNS Resolve IPv"+ipVersion+"-host using "+
                (useAlternativeResolver ?
                "org.xbill.DNS resolver" :
                "native java resolver")+
                " '" + address + "'"+
                (expectedAddress == null ? "" : " expecting to get address \""+expectedAddress+"\"");
    }

    @Override
    public boolean isLoginRequired() {
        return false;
    }

    private static String otherAddresses(InetAddress excludeInetAddress, InetAddress[] allInetAddresses) {
        String res = "";
        for (InetAddress inetAddress : allInetAddresses)
            if (excludeInetAddress == null || !Objects.equals(inetAddress.getHostAddress(), excludeInetAddress.getHostAddress())) {
                if (res.isEmpty())
                    res += inetAddress.getHostAddress();
                else
                    res += ", "+inetAddress.getHostAddress();
        }
        return res;
    }

    @Override
    public ConnectivityTestResult call() {
        try {
            InetAddress[] inetAddresses;
            if (useAlternativeResolver)
                inetAddresses = org.xbill.DNS.Address.getAllByName(address);
            else
                inetAddresses = InetAddress.getAllByName(address);
            for (InetAddress inetAddress : inetAddresses) {
                if (inetAddressClass.isInstance(inetAddress)) {
                    if (expectedAddress == null || inetAddress.getHostAddress().equals(expectedAddress)) {
                        String other = otherAddresses(inetAddress, inetAddresses);
                        return new ConnectivityTestResult(Status.SUCCEEDED, "Successfully resolved \""+address+"\" to " +
                                inetAddress.getHostAddress()+
                                (other.isEmpty() ? "" : " (additional results: "+other+")"));
                    }
                }
            }
            if (expectedAddress == null)
                return new ConnectivityTestResult(Status.FAILED, "Successfully resolved \""+address+"\" but found no IPv"+ipVersion+" address: " + otherAddresses(null, inetAddresses));
            else
                return new ConnectivityTestResult(Status.FAILED,
                        "Successfully resolved \""+address+"\" but did not find expected IPv"+ipVersion+" address \""+expectedAddress+"\": " + otherAddresses(null, inetAddresses));
        } catch (UnknownHostException e) {
            return new ConnectivityTestResult(Status.FAILED, "Unable to resolve \"" + address+"\"");
        }
    }
}
