package com.googlecode.totallylazy.io;
import com.googlecode.totallylazy.Strings;
import com.googlecode.totallylazy.functions.Function1;
import com.googlecode.totallylazy.regex.Regex;
import java.io.File;
import java.net.URI;
import java.net.URL;
import java.util.regex.MatchResult;
import static com.googlecode.totallylazy.Strings.isEmpty;
public class Uri implements Comparable<Uri> {
public static final Regex JAR_URL = Regex.regex("jar:([^!]+)!(/.*)");
public static final Regex RFC3986 = Regex.regex("^(?:([^:/?\\#]+):)?(?://([^/?\\#]*))?([^?\\#]*)(?:\\?([^\\#]*))?(?:\\#(.*))?");
public static final String JAR_SCHEME = "jar";
public static final String FILE_SCHEME = "file";
private final String scheme;
private final String authority;
private final String path;
private final String query;
private final String fragment;
public Uri(String scheme, String authority, String path, String query, String fragment) {
this.scheme = scheme;
this.authority = authority;
this.path = path;
this.query = query;
this.fragment = fragment;
}
public Uri(CharSequence value) {
if (JAR_URL.matches(value)) {
MatchResult jar = JAR_URL.match(value);
scheme = JAR_SCHEME;
authority = jar.group(1);
path = jar.group(2);
query = null;
fragment = null;
} else {
MatchResult result = RFC3986.match(value);
scheme = result.group(1);
authority = result.group(2);
path = result.group(3);
query = result.group(4);
fragment = result.group(5);
}
}
public static Uri uri(File value) {
return uri(value.toURI());
}
public static Uri uri(CharSequence value) {
return new Uri(value);
}
public static Uri uri(URL value) {
return new Uri(value.toString());
}
public static Uri uri(URI value) {
return new Uri(value.toString());
}
public static Uri packageUri(Class<?> aClass) {
return uri(URLs.packageUrl(aClass));
}
public static Uri rootUri(Class<?> aClass) {
return uri(URLs.rootUrl(aClass));
}
public String scheme() {
return scheme;
}
public Uri scheme(String value) {
return new Uri(value, authority, path, query, fragment);
}
public Uri dropScheme() {
return scheme(null);
}
public String authority() {
return authority;
}
public Uri authority(String value) {
return new Uri(scheme, value, path, query, fragment);
}
private Authority Authority() {
return Authority.authority(authority);
}
private Uri Authority(Authority value) {
return authority(value.toString());
}
public Uri dropAuthority() {
return authority(null);
}
public String userInfo() {
return Authority().userInfo();
}
public Uri userInfo(String value) {
return Authority(Authority().userInfo(value));
}
public Uri dropUserInfo() {
return userInfo(null);
}
public String host() {
return Authority().host();
}
public Uri host(String value) {
return Authority(Authority().host(value));
}
public Uri dropHost() {
return host(null);
}
public int port() {
return Authority().port();
}
public Uri port(int value) {
return Authority(Authority().port(value));
}
public Uri dropPort() {
return port(-1);
}
public String path() {
return path;
}
public Uri path(String value) {
return new Uri(scheme, authority, value, query, fragment);
}
public Uri dropPath() {
return path(Strings.EMPTY);
}
public Uri mergePath(String value) {
if (value.startsWith("/")) {
return path(value);
}
if (authority() != null && path().equals(Strings.EMPTY)) {
return path("/" + value);
}
return path(path().replaceFirst("([^/]*)$", value));
}
public String query() {
return query;
}
public Uri query(String value) {
return new Uri(scheme, authority, path, Strings.isBlank(value) ? null : value, fragment);
}
public Uri dropQuery() {
return query(null);
}
public String fragment() {
return fragment;
}
public Uri fragment(String value) {
return new Uri(scheme, authority, path, query, value);
}
public Uri dropFragment() {
return fragment(null);
}
@Override
public final boolean equals(final Object o) {
return o instanceof Uri && toString().equals(o.toString());
}
@Override
public final int hashCode() {
return toString().hashCode();
}
@Override
public String toString() {
if (JAR_SCHEME.equals(scheme)) {
return String.format("%s:%s!%s", JAR_SCHEME, authority, path);
}
return standardToString();
}
private String standardToString() {
StringBuilder builder = new StringBuilder();
if (scheme != null) {
builder.append(scheme).append(":");
}
if (authority != null) {
builder.append("//").append(authority);
}
builder.append(path);
if (query != null) {
builder.append("?").append(query);
}
if (fragment != null) {
builder.append("#").append(fragment);
}
return builder.toString();
}
public URL toURL() {
return URLs.url(toString());
}
public URI toURI() {
return URLs.uri(toString());
}
public boolean isFullyQualified() {
return !isEmpty(authority);
}
public boolean isAbsolute() {
return path.startsWith("/");
}
public boolean isRelative() {
return !isAbsolute();
}
@Override
public int compareTo(Uri other) {
return toString().compareTo(other.toString());
}
public File toFile() {
return new File(toURI());
}
public Uri removeDotSegments() {
if(Strings.isEmpty(path)) return this;
return path(DotSegments.remove(path));
}
public static class functions {
public static Function1<String, Uri> uri = Uri::uri;
public static Function1<String, Uri> uri() {
return uri;
}
public static final Function1<Uri, String> path = Uri::path;
public static final Function1<Uri, String> host = Uri::host;
public static Function1<Uri, Uri> host(final String newHost) {
return uri1 -> uri1.host(newHost);
}
public static Function1<Uri, URL> URL = Uri::toURL;
}
static class Authority {
private static final Regex AUTHORITY = Regex.regex("(?:([^@]+)@)?([^:]+)(?:\\:([\\d]+))?");
private final String userInfo;
private final String host;
private final int port;
private Authority(String userInfo, String host, int port) {
this.userInfo = userInfo;
this.host = host;
this.port = port;
}
static Authority authority(String authority) {
if (authority == null) return authority(null, null, null);
MatchResult match = AUTHORITY.match(authority);
return authority(match.group(1), match.group(2), match.group(3));
}
static Authority authority(String userInfo, String host, String port) {
return authority(userInfo, host, port == null ? -1 : Integer.parseInt(port));
}
static Authority authority(String userInfo, String host, int port) {
return new Authority(userInfo, host, port);
}
String userInfo() {
return userInfo;
}
Authority userInfo(String value) {
return authority(value, host, port);
}
String host() {
return host;
}
Authority host(String value) {
return authority(userInfo, value, port);
}
int port() {
return port;
}
Authority port(int value) {
return authority(userInfo, host, value);
}
@Override
public String toString() {
if (isEmpty(host)) return null;
StringBuilder builder = new StringBuilder();
if (!isEmpty(userInfo)) builder.append(userInfo).append("@");
builder.append(host);
if (port != -1) builder.append(":").append(port);
return builder.toString();
}
}
}