package org.batfish.datamodel.questions;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import com.google.common.collect.ImmutableMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.batfish.datamodel.BgpProcess;
import org.batfish.datamodel.answers.AutocompleteSuggestion;
import org.batfish.datamodel.answers.Schema;

/**
 * Enables specification a set of Ospf process properties.
 *
 * <p>Example specifiers:
 *
 * <ul>
 *   <li>multipath-ebgp —> gets the process's corresponding value
 *   <li>multipath-.* --> gets all properties that start with 'max-metric-'
 * </ul>
 */
public class BgpPropertySpecifier extends PropertySpecifier {

  public static final String ACTIVE_NEIGHBORS = "Active_Neighbors";
  public static final String CLUSTER_IDS = "Cluster_IDs";
  public static final String GENERATED_ROUTES = "Generated_Routes";
  public static final String MULTIPATH_EQUIVALENT_AS_PATH_MATCH_MODE =
      "Multipath_Equivalent_AS_Path_Match_Mode";
  public static final String MULTIPATH_EBGP = "Multipath_EBGP";
  public static final String MULTIPATH_IBGP = "Multipath_IBGP";
  public static final String ORIGINATION_SPACE = "Origination_Space";
  public static final String PASSIVE_NEIGHBORS = "Passive_Neighbors";
  public static final String TIE_BREAKER = "Tie_Breaker";

  public static Map<String, PropertyDescriptor<BgpProcess>> JAVA_MAP =
      new ImmutableMap.Builder<String, PropertyDescriptor<BgpProcess>>()
          .put(
              ACTIVE_NEIGHBORS,
              new PropertyDescriptor<>(BgpProcess::getActiveNeighbors, Schema.set(Schema.STRING)))
          .put(
              CLUSTER_IDS,
              new PropertyDescriptor<>(BgpProcess::getClusterIds, Schema.set(Schema.STRING)))
          .put(
              GENERATED_ROUTES,
              new PropertyDescriptor<>(BgpProcess::getGeneratedRoutes, Schema.set(Schema.STRING)))
          .put(
              MULTIPATH_EQUIVALENT_AS_PATH_MATCH_MODE,
              new PropertyDescriptor<>(
                  BgpProcess::getMultipathEquivalentAsPathMatchMode, Schema.STRING))
          .put(
              MULTIPATH_EBGP,
              new PropertyDescriptor<>(BgpProcess::getMultipathEbgp, Schema.BOOLEAN))
          .put(
              MULTIPATH_IBGP,
              new PropertyDescriptor<>(BgpProcess::getMultipathIbgp, Schema.BOOLEAN))
          .put(
              ORIGINATION_SPACE,
              new PropertyDescriptor<>(BgpProcess::getOriginationSpace, Schema.STRING))
          .put(
              PASSIVE_NEIGHBORS,
              new PropertyDescriptor<>(BgpProcess::getPassiveNeighbors, Schema.set(Schema.STRING)))
          // skip router-id; included as part of process identity
          .put(TIE_BREAKER, new PropertyDescriptor<>(BgpProcess::getTieBreaker, Schema.STRING))
          .build();

  public static final BgpPropertySpecifier ALL = new BgpPropertySpecifier(".*");

  private final String _expression;

  private final Pattern _pattern;

  @JsonCreator
  public BgpPropertySpecifier(String expression) {
    _expression = expression;
    _pattern = Pattern.compile(_expression.trim().toLowerCase()); // canonicalize
  }

  /**
   * Returns a list of suggestions based on the query, based on {@link
   * PropertySpecifier#baseAutoComplete}.
   */
  public static List<AutocompleteSuggestion> autoComplete(String query) {
    return PropertySpecifier.baseAutoComplete(query, JAVA_MAP.keySet());
  }

  @Override
  public Set<String> getMatchingProperties() {
    return JAVA_MAP
        .keySet()
        .stream()
        .filter(prop -> _pattern.matcher(prop.toLowerCase()).matches())
        .collect(Collectors.toSet());
  }

  @Override
  @JsonValue
  public String toString() {
    return _expression;
  }
}

@@ -182,24 +182,68 @@
 mutableMap;%0A
+import com.google.common.collect.Iterables;%0A
 import java.
@@ -840,75 +840,10 @@
 %0A%0A  
-public static final String ACTIVE_NEIGHBORS = %22Active_Neighbors%22;%0A 
+//
  pub
@@ -899,76 +899,8 @@
 s%22;%0A
-  public static final String GENERATED_ROUTES = %22Generated_Routes%22;%0A
   pu
@@ -965,22 +965,16 @@
 H_MODE =
-%0A     
  %22Multip
@@ -981,27 +981,8 @@
 ath_
-Equivalent_AS_Path_
 Matc
@@ -1151,86 +1151,8 @@
 ing 
-ORIGINATION_SPACE = %22Origination_Space%22;%0A  public static final String PASSIVE_
 NEIG
@@ -1385,37 +1385,34 @@
 s%3E%3E()%0A          
-.put(
+/*
 %0A              A
@@ -1410,384 +1410,447 @@
     
-    ACTIVE_NEIGHBORS,%0A              new PropertyDescriptor%3C%3E(BgpProcess::getActiveNeighbors, Schema.set(Schema.STRING)))%0A          .put(%0A              CLUSTER_IDS,%0A              new PropertyDescriptor%3C%3E(BgpProcess::getClusterIds, Schema.set(Schema.STRING)))%0A          .put(%0A              GENERATED_ROUTES,%0A              new PropertyDescriptor%3C%3E(BgpProcess::getGeneratedRoutes,
+Suppressing CLUSTER_IDs until we can figure out how to get these for route reflectors only%0A%0A          .put(%0A              CLUSTER_IDS,%0A              new PropertyDescriptor%3C%3E(%0A                  (process) -%3E%0A                      process%0A                          .getClusterIds()%0A                          .stream()%0A                          .map(Ip::new)%0A                          .collect(ImmutableSet.toImmutableSet()),%0A                 
  Sch
@@ -1866,32 +1866,45 @@
 chema.STRING)))%0A
+          */%0A
           .put(%0A
@@ -2381,25 +2381,17 @@
     
-ORIGINATION_SPACE
+NEIGHBORS
 ,%0A  
@@ -2431,56 +2431,79 @@
 r%3C%3E(
-BgpProcess::getOriginationSpace, Schema.STRING))
+%0A                  (process) -%3E%0A                      Iterables.concat(
 %0A   
@@ -2501,38 +2501,32 @@
 ncat(%0A          
-.put(%0A
               PA
@@ -2527,78 +2527,83 @@
     
-PASSIVE_NEIGHBORS,%0A              new PropertyDescriptor%3C%3E(BgpP
+  process.getActiveNeighbors().keySet(),%0A                          p
 rocess
-::
+.
 getP
@@ -2617,17 +2617,47 @@
 eighbors
-,
+().keySet()),%0A                 
  Schema.

Simplify BGP properties: (#2226)