// Copyright (C) 2012 The Android Open Source Project
//
// 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.gerrit.httpd.restapi;

import static com.google.gerrit.httpd.restapi.RestApiServlet.ALLOWED_CORS_METHODS;
import static com.google.gerrit.httpd.restapi.RestApiServlet.XD_AUTHORIZATION;
import static com.google.gerrit.httpd.restapi.RestApiServlet.XD_CONTENT_TYPE;
import static com.google.gerrit.httpd.restapi.RestApiServlet.XD_METHOD;
import static com.google.gerrit.httpd.restapi.RestApiServlet.replyBinaryResult;
import static com.google.gerrit.httpd.restapi.RestApiServlet.replyError;
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;

import com.google.auto.value.AutoValue;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.MultimapBuilder;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.BinaryResult;
import com.google.gerrit.extensions.restapi.Url;
import com.google.gerrit.server.DynamicOptions;
import com.google.gerrit.util.cli.CmdLineParser;
import com.google.gerrit.util.http.CacheHeaders;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.google.inject.Inject;
import com.google.inject.Injector;
import java.io.IOException;
import java.io.StringWriter;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.kohsuke.args4j.CmdLineException;

public class ParameterParser {
  private static final ImmutableSet<String> RESERVED_KEYS =
      ImmutableSet.of("pp", "prettyPrint", "strict", "callback", "alt", "fields");

  @AutoValue
  public abstract static class QueryParams {
    static final String I = QueryParams.class.getName();

    static QueryParams create(
        @Nullable String accessToken,
        @Nullable String xdMethod,
        @Nullable String xdContentType,
        ImmutableListMultimap<String, String> config,
        ImmutableListMultimap<String, String> params) {
      return new AutoValue_ParameterParser_QueryParams(
          accessToken, xdMethod, xdContentType, config, params);
    }

    @Nullable
    public abstract String accessToken();

    @Nullable
    abstract String xdMethod();

    @Nullable
    abstract String xdContentType();

    abstract ImmutableListMultimap<String, String> config();

    abstract ImmutableListMultimap<String, String> params();

    boolean hasXdOverride() {
      return xdMethod() != null || xdContentType() != null;
    }
  }

  public static QueryParams getQueryParams(HttpServletRequest req) throws BadRequestException {
    QueryParams qp = (QueryParams) req.getAttribute(QueryParams.I);
    if (qp != null) {
      return qp;
    }

    String accessToken = null;
    String xdMethod = null;
    String xdContentType = null;
    ListMultimap<String, String> config = MultimapBuilder.hashKeys(4).arrayListValues().build();
    ListMultimap<String, String> params = MultimapBuilder.hashKeys().arrayListValues().build();

    String queryString = req.getQueryString();
    if (!Strings.isNullOrEmpty(queryString)) {
      for (String kvPair : Splitter.on('&').split(queryString)) {
        Iterator<String> i = Splitter.on('=').limit(2).split(kvPair).iterator();
        String key = Url.decode(i.next());
        String val = i.hasNext() ? Url.decode(i.next()) : "";

        if (XD_AUTHORIZATION.equals(key)) {
          if (accessToken != null) {
            throw new BadRequestException("duplicate " + XD_AUTHORIZATION);
          }
          accessToken = val;
        } else if (XD_METHOD.equals(key)) {
          if (xdMethod != null) {
            throw new BadRequestException("duplicate " + XD_METHOD);
          } else if (!ALLOWED_CORS_METHODS.contains(val)) {
            throw new BadRequestException("invalid " + XD_METHOD);
          }
          xdMethod = val;
        } else if (XD_CONTENT_TYPE.equals(key)) {
          if (xdContentType != null) {
            throw new BadRequestException("duplicate " + XD_CONTENT_TYPE);
          }
          xdContentType = val;
        } else if (RESERVED_KEYS.contains(key)) {
          config.put(key, val);
        } else {
          params.put(key, val);
        }
      }
    }

    qp =
        QueryParams.create(
            accessToken,
            xdMethod,
            xdContentType,
            ImmutableListMultimap.copyOf(config),
            ImmutableListMultimap.copyOf(params));
    req.setAttribute(QueryParams.I, qp);
    return qp;
  }

  private final CmdLineParser.Factory parserFactory;
  private final Injector injector;
  private final DynamicMap<DynamicOptions.DynamicBean> dynamicBeans;

  @Inject
  ParameterParser(
      CmdLineParser.Factory pf,
      Injector injector,
      DynamicMap<DynamicOptions.DynamicBean> dynamicBeans) {
    this.parserFactory = pf;
    this.injector = injector;
    this.dynamicBeans = dynamicBeans;
  }

  <T> boolean parse(
      T param, ListMultimap<String, String> in, HttpServletRequest req, HttpServletResponse res)
      throws IOException {
    CmdLineParser clp = parserFactory.create(param);
    DynamicOptions pluginOptions = new DynamicOptions(param, injector, dynamicBeans);
    pluginOptions.parseDynamicBeans(clp);
    pluginOptions.setDynamicBeans();
    pluginOptions.onBeanParseStart();
    try {
      clp.parseOptionMap(in);
    } catch (CmdLineException | NumberFormatException e) {
      if (!clp.wasHelpRequestedByOption()) {
        replyError(req, res, SC_BAD_REQUEST, e.getMessage(), e);
        return false;
      }
    }

    if (clp.wasHelpRequestedByOption()) {
      StringWriter msg = new StringWriter();
      clp.printQueryStringUsage(req.getRequestURI(), msg);
      msg.write('\n');
      msg.write('\n');
      clp.printUsage(msg, null);
      msg.write('\n');
      CacheHeaders.setNotCacheable(res);
      replyBinaryResult(req, res, BinaryResult.create(msg.toString()).setContentType("text/plain"));
      return false;
    }
    pluginOptions.onBeanParseEnd();

    return true;
  }

  private static Set<String> query(HttpServletRequest req) {
    Set<String> params = new HashSet<>();
    if (!Strings.isNullOrEmpty(req.getQueryString())) {
      for (String kvPair : Splitter.on('&').split(req.getQueryString())) {
        params.add(Iterables.getFirst(Splitter.on('=').limit(2).split(kvPair), null));
      }
    }
    return params;
  }

  /**
   * Convert a standard URL encoded form input into a parsed JSON tree.
   *
   * <p>Given an input such as:
   *
   * <pre>
   * message=Does+not+compile.&labels.Verified=-1
   * </pre>
   *
   * which is easily created using the curl command line tool:
   *
   * <pre>
   * curl --data 'message=Does not compile.' --data labels.Verified=-1
   * </pre>
   *
   * converts to a JSON object structure that is normally expected:
   *
   * <pre>
   * {
   *   "message": "Does not compile.",
   *   "labels": {
   *     "Verified": "-1"
   *   }
   * }
   * </pre>
   *
   * This input can then be further processed into the Java input type expected by a view using
   * Gson. Here we rely on Gson to perform implicit conversion of a string {@code "-1"} to a number
   * type when the Java input type expects a number.
   *
   * <p>Conversion assumes any field name that does not contain {@code "."} will be a property of
   * the top level input object. Any field with a dot will use the first segment as the top level
   * property name naming an object, and the rest of the field name as a property in the nested
   * object.
   *
   * @param req request to parse form input from and create JSON tree.
   * @return the converted JSON object tree.
   * @throws BadRequestException the request cannot be cast, as there are conflicting definitions
   *     for a nested object.
   */
  static JsonObject formToJson(HttpServletRequest req) throws BadRequestException {
    Map<String, String[]> map = req.getParameterMap();
    return formToJson(map, query(req));
  }

  @VisibleForTesting
  static JsonObject formToJson(Map<String, String[]> map, Set<String> query)
      throws BadRequestException {
    JsonObject inputObject = new JsonObject();
    for (Map.Entry<String, String[]> ent : map.entrySet()) {
      String key = ent.getKey();
      String[] values = ent.getValue();

      if (query.contains(key) || values.length == 0) {
        // Disallow processing query parameters as input body fields.
        // Implementations of views should avoid duplicate naming.
        continue;
      }

      JsonObject obj = inputObject;
      int dot = key.indexOf('.');
      if (0 <= dot) {
        String property = key.substring(0, dot);
        JsonElement e = inputObject.get(property);
        if (e == null) {
          obj = new JsonObject();
          inputObject.add(property, obj);
        } else if (e.isJsonObject()) {
          obj = e.getAsJsonObject();
        } else {
          throw new BadRequestException(String.format("key %s conflicts with %s", key, property));
        }
        key = key.substring(dot + 1);
      }

      if (obj.get(key) != null) {
        // This error should never happen. If all form values are handled
        // together in a single pass properties are set only once. Setting
        // again indicates something has gone very wrong.
        throw new BadRequestException("invalid form input, use JSON instead");
      } else if (values.length == 1) {
        obj.addProperty(key, values[0]);
      } else {
        JsonArray list = new JsonArray();
        for (String v : values) {
          list.add(new JsonPrimitive(v));
        }
        obj.add(key, list);
      }
    }
    return inputObject;
  }
}
