// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed 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 com.google.gitiles;

import static com.google.common.base.MoreObjects.firstNonNull;
import static com.google.gitiles.FormatType.DEFAULT;
import static com.google.gitiles.FormatType.HTML;
import static com.google.gitiles.FormatType.JSON;
import static com.google.gitiles.FormatType.TEXT;
import static java.nio.charset.StandardCharsets.UTF_8;
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
import static javax.servlet.http.HttpServletResponse.SC_OK;
import static org.eclipse.jgit.util.HttpSupport.ENCODING_GZIP;

import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.common.net.HttpHeaders;
import com.google.gson.FieldNamingPolicy;
import com.google.gson.GsonBuilder;

import org.joda.time.Instant;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.zip.GZIPOutputStream;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/** Base servlet class for Gitiles servlets that serve Soy templates. */
public abstract class BaseServlet extends HttpServlet {
  private static final long serialVersionUID = 1L;
  private static final String ACCESS_ATTRIBUTE = BaseServlet.class.getName() + "/GitilesAccess";
  private static final String DATA_ATTRIBUTE = BaseServlet.class.getName() + "/Data";
  private static final String STREAMING_ATTRIBUTE = BaseServlet.class.getName() + "/Streaming";

  static void setNotCacheable(HttpServletResponse res) {
    res.setHeader(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate");
    res.setHeader(HttpHeaders.PRAGMA, "no-cache");
    res.setHeader(HttpHeaders.EXPIRES, "Mon, 01 Jan 1990 00:00:00 GMT");
    res.setDateHeader(HttpHeaders.DATE, new Instant().getMillis());
  }

  public static BaseServlet notFoundServlet() {
    return new BaseServlet(null, null) {
      private static final long serialVersionUID = 1L;
      @Override
      public void service(HttpServletRequest req, HttpServletResponse res) {
        res.setStatus(SC_NOT_FOUND);
      }
    };
  }

  public static Map<String, String> menuEntry(String text, String url) {
    if (url != null) {
      return ImmutableMap.of("text", text, "url", url);
    } else {
      return ImmutableMap.of("text", text);
    }
  }

  public static boolean isStreamingResponse(HttpServletRequest req) {
    return firstNonNull((Boolean) req.getAttribute(STREAMING_ATTRIBUTE), false);
  }

  protected static ArchiveFormat getArchiveFormat(GitilesAccess access) throws IOException {
    return ArchiveFormat.getDefault(access.getConfig());
  }

  /**
   * Put a value into a request's Soy data map.
   *
   * @param req in-progress request.
   * @param key key.
   * @param value Soy data value.
   */
  public static void putSoyData(HttpServletRequest req, String key, Object value) {
    getData(req).put(key, value);
  }

  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse res)
      throws IOException, ServletException {
    FormatType format;
    try {
      format = FormatType.getFormatType(req);
    } catch (IllegalArgumentException err) {
      res.sendError(SC_BAD_REQUEST);
      return;
    }
    if (format == DEFAULT) {
      format = getDefaultFormat(req);
    }
    switch (format) {
      case HTML:
        doGetHtml(req, res);
        break;
      case TEXT:
        doGetText(req, res);
        break;
      case JSON:
        doGetJson(req, res);
        break;
      default:
        res.sendError(SC_BAD_REQUEST);
        break;
    }
  }

  /**
   * @param req in-progress request.
   * @return the default {@link FormatType} used when {@code ?format=} is not
   *     specified.
   */
  protected FormatType getDefaultFormat(HttpServletRequest req) {
    return HTML;
  }

  /**
   * Handle a GET request when the requested format type was HTML.
   *
   * @param req in-progress request.
   * @param res in-progress response.
   */
  protected void doGetHtml(HttpServletRequest req, HttpServletResponse res)
      throws IOException {
    res.sendError(SC_BAD_REQUEST);
  }

  /**
   * Handle a GET request when the requested format type was plain text.
   *
   * @param req in-progress request.
   * @param res in-progress response.
   */
  protected void doGetText(HttpServletRequest req, HttpServletResponse res)
      throws IOException {
    res.sendError(SC_BAD_REQUEST);
  }

  /**
   * Handle a GET request when the requested format type was JSON.
   *
   * @param req in-progress request.
   * @param res in-progress response.
   */
  protected void doGetJson(HttpServletRequest req, HttpServletResponse res)
      throws IOException {
    res.sendError(SC_BAD_REQUEST);
  }

  protected static Map<String, Object> getData(HttpServletRequest req) {
    @SuppressWarnings("unchecked")
    Map<String, Object> data = (Map<String, Object>) req.getAttribute(DATA_ATTRIBUTE);
    if (data == null) {
      data = Maps.newHashMap();
      req.setAttribute(DATA_ATTRIBUTE, data);
    }
    return data;
  }

  protected final Renderer renderer;
  private final GitilesAccess.Factory accessFactory;

  protected BaseServlet(Renderer renderer, GitilesAccess.Factory accessFactory) {
    this.renderer = renderer;
    this.accessFactory = accessFactory;
  }

  /**
   * Render data to HTML using Soy.
   *
   * @param req in-progress request.
   * @param res in-progress response.
   * @param templateName Soy template name; must be in one of the template files
   *     defined in {@link Renderer}.
   * @param soyData data for Soy.
   * @throws IOException an error occurred during rendering.
   */
  protected void renderHtml(HttpServletRequest req, HttpServletResponse res, String templateName,
      Map<String, ?> soyData) throws IOException {
    renderer.render(req, res, templateName,
        startHtmlResponse(req, res, soyData));
  }

  /**
   * Start a streaming HTML response with header and footer rendered by Soy.
   * <p>
   * A streaming template includes the special template
   * {@code gitiles.streamingPlaceholder} at the point where data is to be
   * streamed. The template before and after this placeholder is rendered using
   * the provided data map.
   *
   * @param req in-progress request.
   * @param res in-progress response.
   * @param templateName Soy template name; must be in one of the template files
   *     defined in {@link Renderer}.
   * @param soyData data for Soy.
   * @return output stream to render to. The portion of the template before the
   *     placeholder is already written and flushed; the portion after is
   *     written only on calling {@code close()}.
   * @throws IOException an error occurred during rendering the header.
   */
  protected OutputStream startRenderStreamingHtml(HttpServletRequest req,
      HttpServletResponse res, String templateName, Map<String, ?> soyData) throws IOException {
    req.setAttribute(STREAMING_ATTRIBUTE, true);
    return renderer.renderStreaming(res, templateName, startHtmlResponse(req, res, soyData));
  }

  private Map<String, ?> startHtmlResponse(HttpServletRequest req, HttpServletResponse res,
      Map<String, ?> soyData) throws IOException {
    res.setContentType(FormatType.HTML.getMimeType());
    res.setCharacterEncoding(UTF_8.name());
    setCacheHeaders(res);

    Map<String, Object> allData = getData(req);

    GitilesConfig.putVariant(
        getAccess(req).getConfig(), "customHeader", "headerVariant", allData);
    allData.putAll(soyData);
    GitilesView view = ViewFilter.getView(req);
    if (!allData.containsKey("repositoryName") && view.getRepositoryName() != null) {
      allData.put("repositoryName", view.getRepositoryName());
    }
    if (!allData.containsKey("breadcrumbs")) {
      allData.put("breadcrumbs", view.getBreadcrumbs());
    }

    res.setStatus(HttpServletResponse.SC_OK);
    return allData;
  }

  /**
   * Render data to JSON using GSON.
   *
   * @param req in-progress request.
   * @param res in-progress response.
   * @param src @see com.google.gson.Gson#toJson(Object, Type, Appendable)
   * @param typeOfSrc @see com.google.gson.Gson#toJson(Object, Type, Appendable)
   */
  protected void renderJson(HttpServletRequest req, HttpServletResponse res, Object src,
      Type typeOfSrc) throws IOException {
    setApiHeaders(res, JSON);
    res.setStatus(SC_OK);
    try (Writer writer = newWriter(req, res)) {
      newGsonBuilder(req).create().toJson(src, typeOfSrc, writer);
      writer.write('\n');
    }
  }

  @SuppressWarnings("unused") // Used in subclasses.
  protected GsonBuilder newGsonBuilder(HttpServletRequest req) throws IOException {
    return new GsonBuilder()
      .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
      .setPrettyPrinting()
      .generateNonExecutableJson();
  }

  /**
   * @see #startRenderText(HttpServletRequest, HttpServletResponse)
   * @param req in-progress request.
   * @param res in-progress response.
   * @param contentType contentType to set.
   * @return the response's writer.
   */
  protected Writer startRenderText(HttpServletRequest req, HttpServletResponse res,
      String contentType) throws IOException {
    setApiHeaders(res, contentType);
    return newWriter(req, res);
  }

  /**
   * Prepare the response to render plain text.
   * <p>
   * Unlike
   * {@link #renderHtml(HttpServletRequest, HttpServletResponse, String, Map)}
   * and
   * {@link #renderJson(HttpServletRequest, HttpServletResponse, Object, Type)},
   * which assume the data to render is already completely prepared, this method
   * does not write any data, only headers, and returns the response's
   * ready-to-use writer.
   *
   * @param req in-progress request.
   * @param res in-progress response.
   * @return the response's writer.
   */
  protected Writer startRenderText(HttpServletRequest req, HttpServletResponse res)
      throws IOException {
    return startRenderText(req, res, TEXT.getMimeType());
  }

  /**
   * Render an error as plain text.
   *
   * @param req in-progress request.
   * @param res in-progress response.
   * @param statusCode HTTP status code.
   * @param message full message text.
   *
   * @throws IOException
   */
  protected void renderTextError(HttpServletRequest req, HttpServletResponse res, int statusCode,
      String message) throws IOException {
    res.setStatus(statusCode);
    setApiHeaders(res, TEXT);
    setCacheHeaders(res);
    try (Writer out = newWriter(req, res)) {
      out.write(message);
    }
  }

  protected GitilesAccess getAccess(HttpServletRequest req) {
    GitilesAccess access = (GitilesAccess) req.getAttribute(ACCESS_ATTRIBUTE);
    if (access == null) {
      access = accessFactory.forRequest(req);
      req.setAttribute(ACCESS_ATTRIBUTE, access);
    }
    return access;
  }

  protected void setCacheHeaders(HttpServletResponse res) {
    setNotCacheable(res);
  }

  protected void setApiHeaders(HttpServletResponse res, String contentType) {
    if (!Strings.isNullOrEmpty(contentType)) {
      res.setContentType(contentType);
    }
    res.setCharacterEncoding(UTF_8.name());
    res.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment");
    res.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "*");
    setCacheHeaders(res);
  }

  protected void setApiHeaders(HttpServletResponse res, FormatType type) {
    setApiHeaders(res, type.getMimeType());
  }

  protected void setDownloadHeaders(HttpServletResponse res, String filename, String contentType) {
    res.setContentType(contentType);
    res.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + filename);
    setCacheHeaders(res);
  }

  protected static Writer newWriter(OutputStream os, HttpServletResponse res) throws IOException {
    return new OutputStreamWriter(os, res.getCharacterEncoding());
  }

  private Writer newWriter(HttpServletRequest req, HttpServletResponse res)
      throws IOException {
    OutputStream out;
    if (acceptsGzipEncoding(req)) {
      res.setHeader(HttpHeaders.CONTENT_ENCODING, "gzip");
      out = new GZIPOutputStream(res.getOutputStream());
    } else {
      out = res.getOutputStream();
    }
    return newWriter(out, res);
  }

  protected static boolean acceptsGzipEncoding(HttpServletRequest req) {
    String accepts = req.getHeader(HttpHeaders.ACCEPT_ENCODING);
    if (accepts == null) {
      return false;
    }
    for (int b = 0; b < accepts.length();) {
      int comma = accepts.indexOf(',', b);
      int e = 0 <= comma ? comma : accepts.length();
      String term = accepts.substring(b, e).trim();
      if (term.equals(ENCODING_GZIP)) {
        return true;
      }
      b = e + 1;
    }
    return false;
  }

  protected static byte[] gzip(byte[] raw) throws IOException {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    try (GZIPOutputStream gz = new GZIPOutputStream(out)) {
      gz.write(raw);
    }
    return out.toByteArray();
  }
}
