package ru.yandex.wmtools.common.util.uri;

import java.io.IOException;
import java.net.URI;
import java.net.URL;

import org.jetbrains.annotations.NotNull;
import org.springframework.util.MultiValueMap;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriUtils;

import ru.yandex.wmtools.common.error.InternalException;
import ru.yandex.wmtools.common.error.InternalProblem;

/**
 * Temporary replacement for {@link java.net.URI} until support for RFC 3986 is implemented.
 *
 * @author aherman
 */
public class URI2 {
    private final UriComponents uriComponents;

    URI2(@NotNull UriComponents uriComponents) {
        if(uriComponents == null) {
            throw new NullPointerException("URI must not be null");
        }
        this.uriComponents = uriComponents;
    }

    UriComponents getUriComponents() {
        return uriComponents;
    }

    /**
     * @see org.springframework.web.util.UriComponents#getScheme()
     */
    public String getScheme() {
        return uriComponents.getScheme();
    }

    /**
     * @see org.springframework.web.util.UriComponents#getUserInfo()
     */
    public String getUserInfo() {
        return uriComponents.getUserInfo();
    }

    /**
     * @see org.springframework.web.util.UriComponents#getHost()
     */
    public String getHost() {
        return uriComponents.getHost();
    }

    /**
     * @see org.springframework.web.util.UriComponents#getPort()
     */
    public int getPort() {
        return uriComponents.getPort();
    }

    /**
     * @see org.springframework.web.util.UriComponents#getPath()
     */
    public String getPath() {
        return uriComponents.getPath();
    }

    /**
     * @see org.springframework.web.util.UriComponents#getQuery()
     */
    public String getQuery() {
        return uriComponents.getQuery();
    }

    public MultiValueMap<String, String> getQueryParams() {
        return uriComponents.getQueryParams();
    }

    /**
     * @see org.springframework.web.util.UriComponents#getFragment()
     */
    public String getFragment() {
        return uriComponents.getFragment();
    }

    public boolean isAbsolute() {
        return uriComponents.getScheme() != null;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        URI2 uri2 = (URI2) o;

        if (!uriComponents.equals(uri2.uriComponents)) {
            return false;
        }

        return true;
    }

    @Override
    public int hashCode() {
        return uriComponents.hashCode();
    }

    public String toUriString() {
        return uriComponents.encode().toUriString();
    }

    public URI toUri() {
        return uriComponents.encode().toUri();
    }

    @Override
    public String toString() {
        return toUriString();
    }

    public URL toURL() throws InternalException {
        try {
            return new URL(getScheme(), getHost(), getPort(),
                    UriUtils.encodePath(getPath(), "UTF-8") + "?" + UriUtils.encodeQuery(getQuery(), "UTF-8")
            );
        } catch (IOException e) {
            throw new InternalException(InternalProblem.PROCESSING_ERROR, "Unable to convert URI to URL");
        }
    }
}
