/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.sling.servlets.get.impl;

import java.io.IOException;

import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;

import org.apache.sling.api.SlingConstants;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.request.RequestPathInfo;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.apache.sling.servlets.get.impl.helpers.JsonRendererServlet;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.Designate;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The <code>RedirectServlet</code> implements support for GET requests to
 * resources of type <code>sling:redirect</code>. This servlet tries to get the
 * redirect target by
 * <ul>
 * <li>first adapting the resource to a {@link ValueMap} and trying to get the
 * property <code>sling:target</code>.</li>
 * <li>The second attempt is to access the resource <code>sling:target</code>
 * below the requested resource and attapt this to a string.</li>
 * </ul>
 * <p>
 * If there is no value found for <code>sling:target</code> a 404 (NOT FOUND)
 * status is sent by this servlet. Otherwise a 302 (FOUND, temporary redirect)
 * status is sent where the target is the relative URL from the current resource
 * to the target resource. Selectors, extension, suffix and query string are
 * also appended to the redirect URL.
 */
@SuppressWarnings("serial")
@Component(service = Servlet.class,
    property = {
            "service.description=Request Redirect Servlet",
            "service.vendor=The Apache Software Foundation",
            "sling.servlet.resourceTypes=sling:redirect",
            "sling.servlet.methods=GET",
            "sling.servlet.prefix:Integer=-1"
    })
@Designate(ocd = RedirectServlet.Config.class)
public class RedirectServlet extends SlingSafeMethodsServlet {

    @ObjectClassDefinition(name="Apache Sling Redirect Servlet",
            description="The Sling servlet handling redirect resources.")
    public @interface Config {

        @AttributeDefinition(name = "JSON Max results",
                description = "The maximum number of resources that should " +
                  "be returned when doing a node.5.json or node.infinity.json. In JSON terms " +
                  "this basically means the number of Objects to return. Default value is " +
                  "200.")
        int json_maximumresults() default 200;
    }

    /** The name of the target property */
    public static final String TARGET_PROP = "sling:target";

    /** The name of the redirect status property */
    public static final String STATUS_PROP = "sling:status";

    /** default log */
    private final Logger log = LoggerFactory.getLogger(getClass());

    private Servlet jsonRendererServlet;

    private int jsonMaximumResults;

    @Activate
    protected void activate(Config cfg) {
      this.jsonMaximumResults = cfg.json_maximumresults();
      // When the maximumResults get updated, we force a reset for the jsonRendererServlet.
      jsonRendererServlet = getJsonRendererServlet();
    }

    @Override
    protected void doGet(SlingHttpServletRequest request,
            SlingHttpServletResponse response) throws ServletException,
            IOException {

        // handle json export of the redirect node
        if (JsonRendererServlet.EXT_JSON.equals(request.getRequestPathInfo().getExtension())) {
            getJsonRendererServlet().service(request, response);
            return;
        }

        // check for redirectability
        if (response.isCommitted()) {
            // committed response cannot be redirected
            log.warn("RedirectServlet: Response is already committed, not redirecting");
            request.getRequestProgressTracker().log(
                "RedirectServlet: Response is already committed, not redirecting");
            return;
        } else if (request.getAttribute(SlingConstants.ATTR_REQUEST_SERVLET) != null) {
            // included request will not redirect
            log.warn("RedirectServlet: Servlet is included, not redirecting");
            request.getRequestProgressTracker().log(
                "RedirectServlet: Servlet is included, not redirecting");
            return;
        }

        String targetPath = null;

        // convert resource to a value map
        final Resource rsrc = request.getResource();
        final ValueMap valueMap = rsrc.adaptTo(ValueMap.class);
        if (valueMap != null) {
            targetPath = valueMap.get(TARGET_PROP, String.class);
        }
        if (targetPath == null) {
            // old behaviour
            final Resource targetResource = request.getResourceResolver().getResource(
                rsrc, TARGET_PROP);
            if (targetResource == null) {
                response.sendError(HttpServletResponse.SC_NOT_FOUND,
                    "Missing target for redirection");
                return;
            }

            // if the target resource is a path (string), redirect there
            targetPath = targetResource.adaptTo(String.class);
        }

        // if we got a target path, make it external and redirect to it
        if (targetPath != null) {
            if (!isUrl(targetPath)) {
                // make path relative and append selectors, extension etc.
                // this is an absolute URI suitable for the Location header
                targetPath = toRedirectPath(targetPath, request);
            } else {
                // just append any selectors, extension, suffix and query string
                targetPath = appendSelectorsExtensionSuffixQuery(request,
                    new StringBuilder(targetPath)).toString();
            }

            final int status = getStatus(valueMap);

            // redirect the client, use our own setup since we might have a
            // custom response status and we already have converted the target
            // into an absolute URI.
            response.reset();
            response.setStatus(status);
            response.setHeader("Location", isUrl(targetPath) ? targetPath : response.encodeRedirectURL(targetPath));
            response.flushBuffer();

            return;
        }

        // no way of finding the target, just fail
        response.sendError(HttpServletResponse.SC_NOT_FOUND,
            "Cannot redirect to target resource " + targetPath);
    }

    /**
     * Returns the response status from the {@link #STATUS_PROP} property in the
     * value map. If <code>valueMap</code> is <code>null</code>, the property is
     * not contained in the map or if the value is outside of the value HTTP
     * response status range of [ 100 .. 999 ], the default status 302/FOUND is
     * returned.
     *
     * @param valueMap The <code>valueMap</code> providing the optional status
     *            property.
     * @return The status value as defined above.
     */
    static int getStatus(final ValueMap valueMap) {
        if (valueMap != null) {
            final Integer statusInt = valueMap.get(STATUS_PROP, Integer.class);
            if (statusInt != null) {
                int status = statusInt.intValue();
                if (status >= 100 && status <= 999) {
                    return status;
                }
            }
        }

        // fall back to default value
        return HttpServletResponse.SC_FOUND;

    }

    /**
     * Create an absolute URI suitable for the "Location" response header
     * including any selectors, extension, suffix and query from the current
     * request.
     */
    static String toRedirectPath(String targetPath,
            SlingHttpServletRequest request) {

        // make sure the target path is absolute
        final String rawAbsPath;
        if (targetPath.startsWith("/")) {
            rawAbsPath = targetPath;
        } else {
            rawAbsPath = request.getResource().getPath() + "/" + targetPath;
        }

        final StringBuilder target = new StringBuilder();

        // and ensure the path is normalized, us unnormalized if not possible
        final String absPath = ResourceUtil.normalize(rawAbsPath);
        if (absPath == null) {
            target.append(rawAbsPath);
        } else {
            target.append(absPath);
        }

        appendSelectorsExtensionSuffixQuery(request, target);

        // return the mapped full path
        return request.getResourceResolver().map(request, target.toString());
    }

    /**
     * Appends optional request selectors, extension, suffix and query string to
     * the URL to be prepared in the target string builder and returns the
     * string builder.
     *
     * @param request The Sling HTTP Servlet Request providing access to the
     *            data to be appended
     * @param target The String builder to append the data to. This must not be
     *            null.
     * @return The <code>target</code> string builder.
     * @throws NullPointerException if request or target is <code>null</code>.
     */
    private static StringBuilder appendSelectorsExtensionSuffixQuery(
            SlingHttpServletRequest request, StringBuilder target) {
        // append current selectors, extension and suffix
        final RequestPathInfo rpi = request.getRequestPathInfo();
        if (rpi.getExtension() != null) {

            if (rpi.getSelectorString() != null) {
                target.append('.').append(rpi.getSelectorString());
            }

            target.append('.').append(rpi.getExtension());

            if (rpi.getSuffix() != null) {
                target.append(rpi.getSuffix());
            }
        }

        // append current querystring
        if (request.getQueryString() != null) {
            target.append('?').append(request.getQueryString());
        }

        return target;
    }

    /**
     * Returns an absolute URI built from the given parameters.
     *
     * @param scheme The scheme for the URI to be built.
     * @param host The name of the host.
     * @param port The port or -1 to not add a port number to the URI. For
     *            <code>http</code> and <code>https</code> schemes the port is
     *            not added if it is the default port.
     * @param targetPath The path of the resulting URI. This path is expected to
     *            not be an absolute URI.
     * @return The absolute URI built from the components.
     */
    static String toAbsoluteUri(final String scheme, final String host,
            final int port, final String targetPath) {

        // 1. scheme and host
        final StringBuilder absUriBuilder = new StringBuilder();
        absUriBuilder.append(scheme).append("://").append(host);

        // 2. append the port depending on the scheme and whether the port is
        // the default or not
        if (port > 0) {
            if (!(("http".equals(scheme) && port == 80) || ("https".equals(scheme) && port == 443))) {
                absUriBuilder.append(':').append(port);
            }
        }

        // 3. the actual target path
        absUriBuilder.append(targetPath);
        return absUriBuilder.toString();
    }

    private Servlet getJsonRendererServlet() {
        if (jsonRendererServlet == null) {
            Servlet jrs = new JsonRendererServlet(jsonMaximumResults);
            try {
                jrs.init(getServletConfig());
            } catch (Exception e) {
                // don't care too much here
            }
            jsonRendererServlet = jrs;
        }
        return jsonRendererServlet;
    }

    /**
     * Returns <code>true</code> if the path is potentially an URL. This
     * checks whether the path starts with a scheme followed by a colon
     * according to <a href="http://www.faqs.org/rfcs/rfc2396.html">RFC-2396</a>:
     * <pre>
     *     scheme = alpha *( alpha | digit | "+" | "-" | "." )
     *     alpha  = [ "A" .. "Z", "a" .. "z" ]
     *     digit  = [ "0" .. "9" ]
     * </pre>
     */
    private static boolean isUrl(final String path) {
        for (int i = 0; i < path.length(); i++) {
            char c = path.charAt(i);
            if (c == ':') {
                return true;
            }
            if (!((c >= 'a' && c <= 'z')
                    || (c >= 'A' && c <= 'Z')
                    || (i > 0
                            && ((c >= '0' && c <= '9')
                                    || c == '.'
                                    || c == '+'
                                    || c == '-')))) {
                break;
            }
        }
        return false;
    }

}
