// 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.servlets;

import java.io.IOException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.ArrayList;
import java.util.List;
import java.util.Arrays;
import java.util.Map;
import java.util.HashMap;
import java.util.Collections;
import java.util.Comparator;
import java.util.AbstractMap;

@WebServlet("/search")
public class SearchServlet extends HttpServlet {

  private static final Logger LOGGER = Logger.getLogger(SearchServlet.class.getName());
  //this list is incomplete
  private static final List<String> irrelevantWords = new ArrayList<String>(Arrays.asList(
      "the", "is", "for", "in", "of", "so", "to"
      ));

  @Override
  public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
    //get location
    //filter by location and cutoff outside it
    
    //get tags
    //drop all without first tag
    //those with most tags in common with search go to top
    //those closest to the user go to the top
  }

  @Override
  public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {

  }

  /**
   * Returns keywords from an event (currently using just the title
   * and description) based off an algorithm
   */
  public static List<String> getKeywords(String title, String desc) {
    //TODO: convert to lowercase in processing (figure out acronyms)
    List<String> titleWords = SearchServlet.getSeparateWords(title);
    
    //process title words
    Map<String, Integer> titleMap = new HashMap<String, Integer>();
    for (String w : titleWords) {
      w = w.toLowerCase();
      if (titleMap.containsKey(w)) {
        titleMap.put(w, titleMap.get(w) + 1);
      } else {
        titleMap.put(w, 1);
      }
    }
    List<String> descWords = SearchServlet.getSeparateWords(desc);
    //process desc words
    Map<String, Integer> descMap = new HashMap<String, Integer>();
    for (String w : descWords) {
      w = w.toLowerCase();
      if (descMap.containsKey(w)) {
        descMap.put(w, descMap.get(w) + 1);
      } else {
        descMap.put(w, 1);
      }
    }

    List<Map.Entry<String, Integer>> titleMapList = new ArrayList<Map.Entry<String, Integer>>(titleMap.entrySet()); 

    //merge lists
    List<Map.Entry<String, Integer>> mergeList = new ArrayList<Map.Entry<String, Integer>>(descMap.entrySet());
    for (Map.Entry titleEntry : titleMapList) {
      boolean found = false;
      for (int i = 0; i < mergeList.size(); i++) {
        Map.Entry mergeEntry = mergeList.get(i);
        if (mergeEntry.getKey().toString().equals(titleEntry.getKey().toString())) {
          mergeEntry.setValue(((int) mergeEntry.getValue()) + ((int) titleEntry.getValue() * 2));
          found = true;
        }
      }
      if (!found) {
        Map.Entry<String,Integer> entry = 
            new AbstractMap.SimpleEntry<String, Integer>(
            titleEntry.getKey().toString(), ((int) titleEntry.getValue()) * 2 );
        mergeList.add(entry);
      }
    }

    Collections.sort(mergeList, 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()); 
      } 
    });

    //add top results to the final list
    List<String> finalList = new ArrayList<String>();
    int count = 0;
    //minimum number of instances to be considered a keyword
    int cutoff = 2;
    while (finalList.size() < 5) {
      Map.Entry e = mergeList.get(count);
      //exclude words with less appearances than the cutoff
      if (((int) e.getValue()) < cutoff) break;
      else if (count >= mergeList.size()) break;
      //exclude common useless words (in, a, the, etc)
      else if (!irrelevantWords.contains(e.getKey().toString())) {
        finalList.add(e.getKey().toString());
      }
      count++;
    }

    return finalList;
  }

  /**
   * Returns a list of words contained in a string
   */
  public static List<String> getSeparateWords(String str) {
    // TODO: handle single quoted strings (right now keeps them in for
    // the common case of contractions

    String[] list = str.split("([\\s.,!?:;()\\[\\]&\"\\s+])");
    for (int i = 0; i < list.length; i++) {
      list[i] = list[i].replaceAll("\\s+","");
    }
    List<String> listArr = new ArrayList<String>(Arrays.asList(list));
    listArr.removeAll(Arrays.asList("", null));
    return listArr;
  }
}

@@ -1552,24 +1552,25 @@
 ion %7B%0A    //
+ 
 get location
@@ -1576,16 +1576,17 @@
 n%0A    //
+ 
 filter b
@@ -1629,16 +1629,17 @@
  %0A    //
+ 
 get tags
@@ -1645,16 +1645,17 @@
 s%0A    //
+ 
 drop all
@@ -1675,24 +1675,25 @@
 t tag%0A    //
+ 
 those with m
@@ -1739,16 +1739,17 @@
 p%0A    //
+ 
 those cl
@@ -2104,16 +2104,17 @@
 %7B%0A    //
+ 
 TODO: co
@@ -2244,24 +2244,25 @@
 %0A    %0A    //
+ 
 process titl
@@ -2611,16 +2611,17 @@
 ;%0A    //
+ 
 process 
@@ -3019,16 +3019,17 @@
 %0A%0A    //
+ 
 merge li
@@ -4072,16 +4072,17 @@
 %0A%0A    //
+ 
 add top 
@@ -4186,16 +4186,17 @@
 ;%0A    //
+ 
 minimum 
@@ -4339,32 +4339,33 @@
 count);%0A      //
+ 
 exclude words wi
@@ -4505,16 +4505,17 @@
       //
+ 
 exclude 

Add spaces to comments