gt:                                 "\"size\": " + HabitUpApplication.NUM_OF_ES_RESULTS + "," +
context: package com.example.habitup.Controller;
  
  import android.os.AsyncTask;
  import android.util.Log;
  
  import com.example.habitup.Model.Attributes;
  import com.example.habitup.Model.Habit;
  import com.example.habitup.Model.HabitEvent;
  import com.example.habitup.Model.UserAccount;
  import com.searchly.jestdroid.DroidClientConfig;
  import com.searchly.jestdroid.JestClientFactory;
  import com.searchly.jestdroid.JestDroidClient;
  
  import java.util.ArrayList;
  import java.util.List;
  
  import io.searchbox.core.Delete;
  import io.searchbox.core.DeleteByQuery;
  import io.searchbox.core.DocumentResult;
  import io.searchbox.core.Index;
  import io.searchbox.core.Search;
  import io.searchbox.core.SearchResult;
  
  /**
   * ElasticSearchController performs all ElasticSearch-related operations, primarily establishing
   * connections with the database and performing queries.
   *
   * Some of these queries will have to be updated to override the default 10 results cap - those
   * key to P4 implementation have this done already, but others (e.g. GetAllUsersTask) will need to
   * be updated for P5.
   *
   * @author tyheise
   * @author gojeffcho
   *
   * Javadoc last updated 2017-11-13 by @gojeffcho
   */
  
  public class ElasticSearchController {
  
      private static JestDroidClient client;
  
      private static final String serverURL = "http://cmput301.softwareprocess.es:8080/";
      private static final String db = "team29_habitup";
      private static final String userType = "user";
      private static final String attrType = "attributes";
      private static final String habitType = "habit";
      private static final String habitEventType = "habitevent";
  
      /**
       * Put a UserAccount to the DB - by UID, so can be an add or edit operation
       * .execute() with UserAccount object
       */
      public static class AddUsersTask extends AsyncTask<UserAccount, Void, Void> {
  
          @Override
          protected Void doInBackground(UserAccount... users) {
              verifySettings();
  
              for (UserAccount user : users) {
                  Index index = new Index.Builder(user).index(db).type(userType).refresh(true).id(Integer.toString(user.getUID())).build();
  
                  try {
                      DocumentResult result = client.execute(index);
                      if (result.isSucceeded()) {
  //                        Log.i("HabitUpDEBUG", "AddUsersTask Success");
                      }
  
                      else{
                          Log.i("Error", "Elasticsearch was not able to add the User");
                          throw new RuntimeException("Failed to add user.");
                      }
                  }
  
                  catch (Exception e) {
                      Log.i("Error", "The application failed to build and send the User");
                      throw new RuntimeException("Failed to add user.");
                  }
              }
  
              return null;
          }
      }
  
      /**
       * This is the main task used to update a user in the elastic search server.
       */
      public static class UpdateUsersTask extends AsyncTask<UserAccount, Void, Void> {
          @Override
          protected Void doInBackground(UserAccount... users) {
              // ... : arbitrary number of arguments in Java
              verifySettings();
  
              UserAccount user = users[0];
  
              int jestId = user.getUID();
  
              Index index = new Index.Builder(user).index(db).type(userType).id(Integer.toString(jestId)).build();
  
              try {
                  // where is client?
                  DocumentResult result = client.execute(index);
                  if (result.isSucceeded()) {
                      Log.i("Success","User successfully updated");
                  } else {
                      Log.e("Error", "Elasticsearch was not able to update");
                  }
              } catch (Exception e) {
                  Log.i("Error", "The application failed to build and send the users");
              }
  
              return null;
          }
      }
  
      // Given a username, returns the user object corresponding to it
  
      /**
       * Get a UserAccount object corresponding to a String username
       * .execute() with a String (username)
       * .get() -> ArrayList<UserAccount>
       */
      public static class GetUser extends AsyncTask<String, Void, ArrayList<UserAccount>> {
          @Override
          protected ArrayList<UserAccount> doInBackground(String... search_parameters) {
              verifySettings();
  
              ArrayList<UserAccount> accounts = new ArrayList<>();
              String UserQuery;
  
              if (search_parameters[0].equals("")){
                  UserQuery = search_parameters[0];
              }
  
              else{
                  UserQuery = "{\"query\": {\"match\" : { \"username\" : \"" + search_parameters[0] + "\" }}}";
              }
  
              //Log.i("Debug", "username to search for is: "+ search_parameters[0]);
  
              Search search = new Search.Builder(UserQuery)
                      .addIndex(db)
                      .addType(userType)
                      .build();
  
              try {
                  // Send request to the server to get the user
                  SearchResult result = client.execute(search);
                  if (result.isSucceeded()){
  
                      //Log.i("DeBug", "Succeeded in finding a user");
  
                      List<UserAccount> foundUsers = result.getSourceAsObjectList(UserAccount.class);
                      accounts.addAll(foundUsers);
                  }
                  else{
                      Log.i("Error", "The search query failed to find any tweets that matched");
                  }
              }
              catch (Exception e) {
                  Log.i("Error", "Something went wrong when we tried to communicate with the elasticsearch server!");
              }
  
              return accounts;
          }
      }
  
      /**
       * Gets all UserAccounts, up to NUM_OF_ES_RESULTS
       * .execute() with no args
       * .get() -> ArrayList<UserAccount>
       */
      public static class GetAllUsers extends AsyncTask<Void, Void, ArrayList<UserAccount>> {
          @Override
          protected ArrayList<UserAccount> doInBackground(Void... voids) {
              verifySettings();
  
              ArrayList<UserAccount> accounts = new ArrayList<>();
              String UserQuery;
  
  //            UserQuery = "{\"query\": {\"match_all\" : {}}}";
  
              String query = "{" +
                                  "\"size\": " + HabitUpApplication.NUM_OF_USER_RESULTS + "," +
                                  "\"query\": {" +
                                      "\"match_all\" : {}" +
                                  "}" +
                              "}";
  
              //Log.i("Debug", "username to search for is: "+ search_parameters[0]);
  
              Search search = new Search.Builder(query)
                      .addIndex(db)
                      .addType(userType)
                      .build();
  
              try {
                  // Send request to the server to get the user
                  SearchResult result = client.execute(search);
                  if (result.isSucceeded()){
  
                      //Log.i("DeBug", "Succeeded in finding a user");
  
                      List<UserAccount> foundUsers = result.getSourceAsObjectList(UserAccount.class);
                      accounts.addAll(foundUsers);
                  }
                  else{
                      Log.i("Error", "The search query failed to find any tweets that matched");
                  }
              }
              catch (Exception e) {
                  Log.i("Error", "Something went wrong when we tried to communicate with the elasticsearch server!");
              }
  
              return accounts;
          }
      }
  
      /**
       * Put Attributes object to the DB - done by UID, so can be add or edit
       * .execute() with Attributes object
       */
      public static class AddAttrsTask extends AsyncTask<Attributes, Void, Void> {
  
          @Override
          protected Void doInBackground(Attributes... attrs) {
  
              verifySettings();
  
              for (Attributes attr : attrs) {
                  Index index = new Index.Builder(attr).index(db).type(attrType).id(Integer.toString(attr.getUid())).refresh(true).build();
  
  
                  try {
                      // where is the client?
                      DocumentResult result = client.execute(index);
                      if (result.isSucceeded()) {
  //                        Log.i("HabitUpDEBUG", "AddAttr SUCCESS");
                      }
  
                      else{
                          Log.i("Error", "Elasticsearch was not able to add the Attributes");
                      }
                  } catch (Exception e) {
                      Log.i("Error", "The application failed to build and send the Attributes");
                  }
              }
  
              return null;
          }
      }
  
      /**
       * Gets Attributes object belonging to the UID
       * .execute() with String UID
       * .get() -> ArrayList<Attributes>
       */
      public static class GetAttributesTask extends AsyncTask<String, Void, ArrayList<Attributes>> {
          @Override
          protected ArrayList<Attributes> doInBackground(String... uids) {
              verifySettings();
  
              ArrayList<Attributes> attributes = new ArrayList<>();
              String query;
  
              if (uids[0].equals("")){
                  query = uids[0];
              }
  
              else{
                  query = "{\"query\": {\"match\" : { \"uid\" : \"" + uids[0] + "\" }}}";
              }
  
              //Log.i("Debug", "username to search for is: "+ search_parameters[0]);
  
              Search search = new Search.Builder(query)
                      .addIndex(db)
                      .addType(attrType)
                      .build();
  
              try {
                  // Send request to the server to get the user
                  SearchResult result = client.execute(search);
                  if (result.isSucceeded()){
  
                      List<Attributes> foundAttr = result.getSourceAsObjectList(Attributes.class);
                      attributes.addAll(foundAttr);
                  }
                  else{
                      Log.i("Error", "The search query failed to find any tweets that matched");
                  }
              }
              catch (Exception e) {
                  Log.i("Error", "Something went wrong when we tried to communicate with the elasticsearch server!");
              }
  
              return attributes;
          }
      }
  
      /**
       * Put a Habit to the DB - done by HID, so can be add or edit task
       * .execute() with Habit object
       */
      public static class AddHabitsTask extends AsyncTask<Habit, Void, Void> {
  
          @Override
          protected Void doInBackground(Habit... habits) {
  
              verifySettings();
  
              for (Habit habit : habits) {
                  Index index = new Index.Builder(habit).index(db).type(habitType).id(Integer.toString(habit.getHID())).refresh(true).build();
  
                  try {
                      DocumentResult result = client.execute(index);
                      if (result.isSucceeded()) {
  //                        Log.i("HabitUpDEBUG", "Wrote Habit " + habit.getHabitName());
                      } else {
                          Log.i("HabitUpDEBUG", "Elasticsearch was not able to add the Habit");
                      }
  
                  } catch (Exception e) {
                      Log.i("HabitUpDEBUG", "The application failed to build and send the Habit");
                  }
              }
  
              return null;
          }
  
      }
  
      /**
       * Gets the Habit corresponding to an HID
       * .execute() with String HID
       * .get() -> ArrayList<Habit>
       */
      public static class GetHabitsTask extends AsyncTask<String, Void, ArrayList<Habit>>{
  
          @Override
          protected ArrayList<Habit> doInBackground(String... Hids) {
              verifySettings();
              String UserQuery;
              ArrayList<Habit> habits = new ArrayList<Habit>();
  
              if (Hids[0].equals("")){
                  UserQuery = Hids[0];
              } else {
                  UserQuery = "{\"query\": {\"match\" : { \"hid\" : \"" + Hids[0] + "\" }}}";
              }
  
  
              Search search = new Search.Builder(UserQuery).addIndex(db).addType(habitType).build();
  
              try {
                  SearchResult result = client.execute(search);
                  if (result.isSucceeded()) {
                      List<Habit> foundHabit = result.getSourceAsObjectList(Habit.class);
                      habits.addAll(foundHabit);
  
                  } else {
                      Log.i("Error2", "Something went wrong when we tried to communicate with the elasticsearch server");
                  }
              }
              catch (Exception e) {
                  Log.i("Error1", "Something went wrong when we tried to communicate with the elasticsearch server!");
              }
  
              return habits;
          }
      }
  
      /**
       * Gets Habits matching a name for the CurrentUser
       * .execute() using String of HabitName
       * .get() -> ArrayList<Habit>
       */
      public static class GetHabitsByNameForCurrentUserTask extends AsyncTask<String, Void, ArrayList<Habit>>{
  
          @Override
          protected ArrayList<Habit> doInBackground(String... habitNames) {
              verifySettings();
              String UserQuery;
              ArrayList<Habit> habits = new ArrayList<Habit>();
  
              if (habitNames[0].equals("")){
                  UserQuery = habitNames[0];
              } else {
                  UserQuery = "{" +
                                  "\"query\": {" +
                                      "\"bool\": {" +
                                          "\"must\": [" +
                                              "{\"term\": {\"uid\" : " + HabitUpApplication.getCurrentUIDAsString() + " }}, " +
                                              "{\"match_phrase\": {\"name\" : \"" + habitNames[0] + "\" }}" +
                                          "]" +
                                      "}" +
                                  "}" +
                              "}";
              }
  
  //            Log.i("HabitUpDEBUG", "ESCtl/HabitByNameForUID - query: " + UserQuery);
  
              Search search = new Search.Builder(UserQuery).addIndex(db).addType(habitType).build();
  
              try {
                  SearchResult result = client.execute(search);
                  if (result.isSucceeded()) {
                      List<Habit> foundHabit = result.getSourceAsObjectList(Habit.class);
                      habits.addAll(foundHabit);
  
                  } else {
                      Log.i("HabitUpDEBUG", "ESCtl/HabitByNameForUID - Result Failed");
                  }
              }
              catch (Exception e) {
                  Log.i("HabitUpDEBUG", "ESCtl/HabitByNameForUID - Exception");
              }
  
  //            Log.i("HabitUpDEBUG", "ESCtl/HabitByNameForUID - " + habits.size() + " matches");
  //            for (Habit h : habits) {
  //                Log.i("HabitUpDEBUG", "ESCtl/HabitByNameForUID - matched " + h.getHabitName() + " #" + h.getHID());
  //            }
  
              return habits;
          }
      }
  
      /**
       * Get all Habits belonging to a UserAccount
       * .execute() with String UID
       * .get() -> ArrayList<Habit>
       */
      public static class GetUserHabitsTask extends AsyncTask<String, Void, ArrayList<Habit>>{
  
          @Override
          protected ArrayList<Habit> doInBackground(String... uids) {
              verifySettings();
              String UserQuery;
              ArrayList<Habit> habits = new ArrayList<Habit>();
  
              if (uids[0].equals("")){
                  UserQuery = uids[0];
              } else {
                  UserQuery = "{" +
  