package org.pac4j.saml.util;

import java.net.URI;
import java.net.URISyntaxException;

import org.pac4j.core.context.HttpConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * URI utilities.
 * 
 * @author jkacer
 * @since 1.8.0
 */
public final class UriUtils implements HttpConstants {

    /** SLF4J logger. */
    private static final Logger logger = LoggerFactory.getLogger(UriUtils.class);

    /**
     * Private constructor, to prevent instantiation of this utility class.
     */
    private UriUtils() {
        super();
    }

    /**
     * Compares two URIs for equality, ignoring default port numbers for selected protocols.
     * 
     * By default, {@link URI#equals(Object)} doesn't take into account default port numbers, so http://server:80/resource is a different
     * URI than http://server/resource.
     * 
     * And URLs should not be used for comparison, as written here:
     * http://stackoverflow.com/questions/3771081/proper-way-to-check-for-url-equality
     * 
     * @param uri1
     *            URI 1 to be compared.
     * @param uri2
     *            URI 2 to be compared.
     * 
     * @return True if both URIs are equal.
     */
    public static boolean urisEqualAfterPortNormalization(final URI uri1, final URI uri2) {
        if (uri1 == null && uri2 == null) {
            return true;
        }
        if (uri1 == null || uri2 == null) {
            return false;
        }
        
        try {
            URI normalizedUri1 = normalizePortNumbersInUri(uri1);
            URI normalizedUri2 = normalizePortNumbersInUri(uri2);
            boolean eq = normalizedUri1.equals(normalizedUri2);
            return eq;
        } catch (URISyntaxException use) {
            logger.error("Cannot compare 2 URIs.", use);
            return false;    
        }
    }
    
    /**
     * Normalizes a URI. If it contains the default port for the used scheme, the method replaces the port with "default".
     * 
     * @param uri
     *            The URI to normalize.
     * 
     * @return A normalized URI.
     * 
     * @throws URISyntaxException
     *             If a URI cannot be created because of wrong syntax.
     */
    private static URI normalizePortNumbersInUri(final URI uri) throws URISyntaxException {
        int port = uri.getPort();
        final String scheme = uri.getScheme();

        if (SCHEME_HTTP.equals(scheme) && port == DEFAULT_HTTP_PORT) {
            port = -1;
        }
        if (SCHEME_HTTPS.equals(scheme) && port == DEFAULT_HTTPS_PORT) {
            port = -1;
        }
        
        final URI result = new URI(scheme, uri.getUserInfo(), uri.getHost(), port, uri.getPath(), uri.getQuery(), uri.getFragment());
        return result;
    }
}