package com.atlassian.stash.internal.web.util;

import com.atlassian.bitbucket.avatar.CacheableAvatarSupplier;
import com.atlassian.bitbucket.i18n.I18nService;
import com.google.common.base.Strings;
import com.google.common.io.ByteStreams;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;

import static java.util.concurrent.TimeUnit.MILLISECONDS;

public abstract class AvatarSupport extends ControllerSupport {

    protected AvatarSupport(I18nService i18nService) {
        super(i18nService);
    }

    /**
     * Streams the provided {@link CacheableAvatarSupplier avatar}, automatically handling "If-Modified-Since",
     * "Cache-Control" and "Last-Modified" headers to encourage browsers to cache avatars.
     *
     * @param supplier a supplier providing access to the avatar data to stream
     * @param request  the HTTP request to retrieve the avatar
     * @param response the HTTP response to which the avatar should be streamed
     * @throws IOException if the avatar cannot be read from the provided supplier, or written to the provided response
     */
    protected void streamAvatar(CacheableAvatarSupplier supplier, HttpServletRequest request,
                                HttpServletResponse response) throws IOException {
        if (!Strings.isNullOrEmpty(request.getParameter("v"))) {
            // if we have a cache-busting URL, the client can cache for a long time
            CachePolicies.cacheFor(response, 365, TimeUnit.DAYS);
        } else {
            // support Last-Modified/If-Modified-Since headers, when the URL contains no version parameter
            long modifiedSince = request.getDateHeader("If-Modified-Since");
            long timestamp = supplier.getTimestamp();
            if (timestamp != CacheableAvatarSupplier.TIMESTAMP_UNKNOWN) {
                if (modifiedSince > 0 && (
                        timestamp == CacheableAvatarSupplier.TIMESTAMP_ETERNAL ||
                                // Last-Modified dates are always in seconds
                                MILLISECONDS.toSeconds(modifiedSince) >= MILLISECONDS.toSeconds(timestamp))) {
                    response.sendError(HttpServletResponse.SC_NOT_MODIFIED);

                    return;
                }
                response.setDateHeader("Last-Modified", timestamp);
            }
        }
        response.setContentType(supplier.getContentType());

        try (InputStream avatarStream = supplier.open()) {
            ByteStreams.copy(avatarStream, response.getOutputStream());
        }
        response.flushBuffer();
    }
}
