package com.twilio.wiztowar;

import com.yammer.dropwizard.Bundle;
import com.yammer.dropwizard.assets.AssetServlet;
import com.yammer.dropwizard.config.Bootstrap;
import com.yammer.dropwizard.config.Environment;

import static com.google.common.base.Preconditions.checkArgument;

/**
 * A variant of the {@link com.yammer.dropwizard.assets.AssetsBundle} included in Dropwizard
 * suited for deployments where there is a non-empty servlet context.
 */
public class WarAssetsBundle implements Bundle {
    private static final String DEFAULT_INDEX_FILE = "index.htm";
    private static final String DEFAULT_PATH = "/assets";

    private final String resourcePath;
    private final String warPath;
    private final String uriPath;
    private final String indexFile;

    /**
     * Creates a new {@link WarAssetsBundle} which serves up static assets from
     * {@code src/main/resources/assets/*} as {@code /assets/*}.
     *
     * @see com.twilio.wiztowar.WarAssetsBundle#WarAssetsBundle(String, String, String, String)
     */
    public WarAssetsBundle() {
        this("", DEFAULT_PATH, DEFAULT_INDEX_FILE,"");
    }

    /**
     * Creates a new {@link WarAssetsBundle} which will configure the service to serve the static files
     * located in {@code src/main/resources/${path}} as {@code /${path}}. For example, given a
     * {@code path} of {@code "/assets"}, {@code src/main/resources/assets/example.js} would be
     * served up from {@code /assets/example.js}.
     *
     * @param path    the classpath and URI root of the static asset files
     * @see com.twilio.wiztowar.WarAssetsBundle#WarAssetsBundle(String, String, String, String)
     */
    public WarAssetsBundle(String path) {
        this(path, path, DEFAULT_INDEX_FILE,"");
    }

    /**
     * Creates a new AssetsBundle which will configure the service to serve the static files
     * located in {@code src/main/resources/${resourcePath}} as {@code /${uriPath}}. For example, given a
     * {@code resourcePath} of {@code "/assets"} and a uriPath of {@code "/js"},
     * {@code src/main/resources/assets/example.js} would be served up from {@code /js/example.js}.
     *
     * @param resourcePath    the resource path (in the classpath) of the static asset files
     * @param uriPath    the uri path for the static asset files
     * @see com.twilio.wiztowar.WarAssetsBundle#WarAssetsBundle(String, String, String, String)
     */
    public WarAssetsBundle(String resourcePath, String uriPath) {
        this(resourcePath, uriPath, DEFAULT_INDEX_FILE,"");
    }

    /**
     * Creates a new AssetsBundle which will configure the service to serve the static files
     * located in {@code src/main/resources/${resourcePath}} as {@code /${uriPath}}. If no file name is
     * in ${uriPath}, ${indexFile} is appended before serving. For example, given a
     * {@code resourcePath} of {@code "/assets"} and a uriPath of {@code "/js"},
     * {@code src/main/resources/assets/example.js} would be served up from {@code /js/example.js}.
     *
     * @param warPath             the path to the application - typically the war-name in an app-server
     * @param resourcePath        the resource path (in the classpath) of the static asset files
     * @param uriPath             the uri path for the static asset files
     * @param indexFile           the name of the index file to use
     */
    public WarAssetsBundle(String warPath, String resourcePath, String uriPath, String indexFile) {
        checkArgument(resourcePath.startsWith("/"), "%s is not an absolute path", resourcePath);
        checkArgument(!"/".equals(resourcePath), "%s is the classpath root", resourcePath);
        this.resourcePath = resourcePath.endsWith("/") ? resourcePath : (resourcePath + '/');
        this.uriPath = uriPath.endsWith("/") ? uriPath : (uriPath + '/');
        this.indexFile = indexFile;
        this.warPath = warPath;
    }

    @Override
    public void initialize(Bootstrap<?> bootstrap) {
        // nothing doing
    }

    @Override
    public void run(Environment environment) {
        environment.addServlet(createServlet(), uriPath + '*');
    }

    private AssetServlet createServlet() {
        final String warPathWithTrailingSlash = warPath.endsWith("/") ? warPath : warPath + "/";
        final String warPathWithStartingSlash = warPathWithTrailingSlash
            .startsWith("/") ? warPathWithTrailingSlash : "/" + warPathWithTrailingSlash;
        final String uriPathSansStartingSlash = uriPath.startsWith("/") ? uriPath.substring(1) : uriPath;
        return new AssetServlet(resourcePath, warPathWithStartingSlash + uriPathSansStartingSlash, indexFile);
    }
}