package io.nextop;
import com.google.common.base.Objects;
import javax.annotation.Nullable;
import java.net.InetAddress;
import java.net.UnknownHostException;
public final class Authority {
public static enum Type {
IP,
NAMED,
LOCAL
}
public static Authority valueOf(String s) {
int n = s.length();
if (n <= 0) {
return local();
}
int i = n - 1;
// find last : to be compatible with ipv6
while (0 <= i && ':' != s.charAt(i)) {
--i;
}
if (i < 0) {
// no port - use the default
try {
return create(Ip.valueOf(s), 0);
} catch (IllegalArgumentException e) {
return create(DomainName.valueOf(s), 0);
}
} else {
try {
return create(Ip.valueOf(s.substring(0, i)), Integer.parseInt(s.substring(i + 1, n)));
} catch (IllegalArgumentException e) {
try {
return create(DomainName.valueOf(s.substring(0, i)), Integer.parseInt(s.substring(i + 1, n)));
} catch (IllegalArgumentException e2) {
// could be an ipv6 with a default port
return create(DomainName.valueOf(s), 0);
}
}
}
}
public static Authority create(Ip host, int port) {
validatePort(port);
return new Authority(Type.IP, host, port);
}
public static Authority create(DomainName host, int port) {
validatePort(port);
return new Authority(Type.NAMED, host, port);
}
public static Authority local() {
return new Authority(Type.LOCAL, null, 0);
}
private static void validatePort(int port) {
if ((port & 0xFFFF) != port) {
throw new IllegalArgumentException();
}
}
public final Type type;
@Nullable
private final Object host;
/** <code>0</code> means default */
public final int port;
private Authority(Type type, @Nullable Object host, int port) {
this.type = type;
this.host = host;
this.port = port;
}
public Ip getIp() {
switch (type) {
case IP:
return (Ip) host;
default:
throw new IllegalStateException();
}
}
public DomainName getDomainName() {
switch (type) {
case IP:
return (DomainName) host;
default:
throw new IllegalStateException();
}
}
@Nullable
public String getHost() {
return null != host ? host.toString() : null;
}
@Override
public String toString() {
switch (type) {
case IP:
case NAMED:
if (0 < port) {
return String.format("%s:%d", host, port);
} else {
return String.format("%s", host);
}
case LOCAL:
return "";
default:
throw new IllegalStateException();
}
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Authority)) {
return false;
}
Authority b = (Authority) o;
return type.equals(b.type)
&& port == b.port
&& Objects.equal(host, b.host);
}
@Override
public int hashCode() {
int m = 31;
int c = type.hashCode();
c = m * c + Objects.hashCode(host);
c = m * c + port;
return c;
}
public static InetAddress toInetAddress(Authority authority) {
switch (authority.type) {
case IP:
try {
return InetAddress.getByAddress(authority.getIp().bytes);
} catch (UnknownHostException e) {
throw new IllegalArgumentException(e);
}
case NAMED:
try {
return InetAddress.getByName(authority.getDomainName().toString());
} catch (UnknownHostException e) {
throw new IllegalArgumentException(e);
}
default:
case LOCAL:
throw new IllegalArgumentException();
}
}
}