// Copyright 2019 Google LLC
//
// 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
//
//     https://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.sps;

import com.google.appengine.api.datastore.Entity;
import com.google.gson.Gson;
import com.google.maps.DistanceMatrixApi;
import com.google.maps.DistanceMatrixApiRequest;
import com.google.maps.GeoApiContext;
import com.google.maps.GeocodingApi;
import com.google.maps.GeocodingApiRequest;
import com.google.maps.errors.ApiException;
import com.google.maps.model.DistanceMatrix;
import com.google.maps.model.GeocodingResult;
import com.google.maps.model.LatLng;
import java.io.IOException;
import java.util.Comparator;
import java.util.Map;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;

public class Utils {

  private static final Logger LOGGER = Logger.getLogger(Utils.class.getName());
  private static String MAPS_API_KEY = getApiKey();
  private static final GeoApiContext context =
      new GeoApiContext.Builder().apiKey(MAPS_API_KEY).build();

  private static String getApiKey() {
    String key = null;
    try {
      key = SecretHandler.getApiKey();
    } catch (IOException e) {
      LOGGER.warning(e.getMessage());
    }
    return key;
  }

  /**
   * Converts an Object instance into a JSON string using the Gson library.
   *
   * @param o Object to be converted to JSON
   * @return String containing converted JSON
   */
  public static String convertToJson(Object o) {
    Gson gson = new Gson();
    String json = gson.toJson(o);
    return json;
  }

  /**
   * Gets a parameter from an HTTP request or returns the default value.
   *
   * @param request HTTP request to get the parameter from
   * @param name String containing the name of the parameter to get
   * @param defaultValue String containing a default value to return if there is no parameter
   * @return the request parameter, or the default value if the parameter was not specified by the
   *     client
   */
  public static String getParameter(HttpServletRequest request, String name, String defaultValue) {
    String value = request.getParameter(name);
    if (value == null) {
      return defaultValue;
    }
    return value;
  }

  /**
   * Gets the latitude and longitude of a location using the Google Maps API.
   *
   * @param location String containing the address of the location
   * @return the latitude and longitude of the location
   */
  public static LatLng getLatLng(String location) {
    GeocodingResult[] results = null;
    try {
      GeocodingApiRequest request = GeocodingApi.newRequest(context);
      request.address(location);
      results = request.await();
    } catch (ApiException e) {
      LOGGER.warning(e.getMessage());
    } catch (InterruptedException e) {
      LOGGER.warning(e.getMessage());
    } catch (IOException e) {
      LOGGER.warning(e.getMessage());
    }

    return new LatLng(results[0].geometry.location.lat, results[0].geometry.location.lng);
  }

  /**
   * Calculates the distance in km between two locations using driving routes generated by the
   * Google Maps API.
   *
   * @param from Latitude and longitude of the beginning location
   * @param to Latitude and longitude of the ending location
   * @return the distance in km between the two locations
   */
  public static int getDistance(LatLng from, LatLng to) {
    DistanceMatrix result = null;
    try {
      DistanceMatrixApiRequest request = DistanceMatrixApi.newRequest(context);
      request.origins(from);
      request.destinations(to);
      result = request.await();
    } catch (ApiException e) {
      LOGGER.warning(e.getMessage());
    } catch (InterruptedException e) {
      LOGGER.warning(e.getMessage());
    } catch (IOException e) {
      LOGGER.warning(e.getMessage());
    }

    if (result.rows[0].elements[0].status.toString().equals("ZERO_RESULTS")) {
      return -1;
    }
    int distance = (int) (result.rows[0].elements[0].distance.inMeters / 1000);
    return distance;
  }

  /** Orders a map from greatest to least based off its values */
  public static final Comparator<Map.Entry<String, Integer>> ORDER_MAP_GREATEST_TO_LEAST =
      new Comparator<Map.Entry<String, Integer>>() {
        public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
          return (o2.getValue()).compareTo(o1.getValue());
        }
      };

  // comparators to apply sort to results
  public static final Comparator<Entity> ORDER_BY_NAME =
      new Comparator<Entity>() {
        @Override
        public int compare(Entity a, Entity b) {
          if (!a.getKind().equals("Event") || !b.getKind().equals("Event")) {
            throw new IllegalArgumentException("must be event items");
          }
          return a.getProperty("eventName")
              .toString()
              .compareTo(b.getProperty("eventName").toString());
        }
      };

  /** creates a comparator based on entity dot product with a given vector. */
  public static Comparator<Entity> getComparatorByInterestMatch(Map<String, Integer> metrics) {
    Comparator<Entity> result =
        new Comparator<Entity>() {
          @Override
          public int compare(Entity a, Entity b) {
            if (!a.getKind().equals("Event") || !b.getKind().equals("Event")) {
              throw new IllegalArgumentException("must be event items");
            }
            Map<String, Integer> v1 = Interactions.buildVectorForEvent(a);
            Map<String, Integer> v2 = Interactions.buildVectorForEvent(b);
            return Integer.compare(
                Interactions.dotProduct(v1, metrics), Interactions.dotProduct(v2, metrics));
          }
        };
    return result;
  }
}

@@ -4525,16 +4525,17 @@
 s values
+.
  */%0A  pu

Add period