package grok.core;

import java.util.Arrays;
import java.util.List;

import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.SetMultimap;

/**
 * @see <a href="http://www.mec.ca/AST/ContentPrimary/Learn/Climbing/IntroToClimbing/ClimbingGradeConversion.jsp"></a>
 */
@AutoValue
public abstract class ClimbingGrade implements Comparable<ClimbingGrade> {
  public enum Country {
    USA, FRANCE, AUSTRALIA, SOUTH_AFRICA, GERMANY, UNITED_KINGDOM;
  }

  public static ClimbingGrade usa(String value) {
    return of(Country.USA, value);
  }

  public static ClimbingGrade of(Country country, String value) {
    for (ClimbingGrade maybe : KNOWN) {
      if (maybe.matches(country, value)) {
        return maybe;
      }
    }
    throw new IllegalArgumentException(value + " does not exist for " + country);
  }

  //@formatter:off
  private static final List<ClimbingGrade> KNOWN = Arrays.asList(
      known("5.1",   "2",      "7",     "8",     "III-",       "M"),
      known("5.2",   "2+",     "8",     "9",     "III",        "D"),
      known("5.3",   "3",      "9/10",  "10",    "III+",       "VD 3a"),
      known("5.4",   "3+",     "11",    "12",    "IV-",        "VD/HVD 3b"),
      known("5.5",   "4",      "12",    "13",    "IV",         "HVD/S 3c"),
      known("5.6",   "4+",     "13",    "14",    "IV+/V-",     "MS 4a"),
      known("5.7",   "5a",     "14/15", "15",    "V-/V",       "S/HS 4b"),
      known("5.8",   "5b",     "15/16", "16",    "V+/VI-",     "HS/VS 4b"),
      known("5.9",   "5c",     "17",    "17/18", "VI-/VI",     "HVS 4c"),
      known("5.10a", "6a",     "18",    "19",    "VI/VI+",     "HVS 5a"),
      known("5.10b", "6a+",    "19",    "20",    "VII-",       "E1 5a"),
      known("5.10c", "6b",     "20",    "21",    "VII-/VII",   "E1 5b"),
      known("5.10d", "6b+",    "20/21", "22",    "VII/VII+",   "E2 5b"),
      known("5.11a", "6c",     "21",    "22/23", "VII+",       "E2 5c"),
      known("5.11b", "6c/6c+", "22",    "23/24", "VIII-",      "E3 5c"),
      known("5.11c", "6c+",    "22/23", "24",    "VIII",       "E3 6a"),
      known("5.11d", "7a",     "23",    "25",    "VIII/VIII+", "E4 6a"),
      known("5.12a", "7a+",    "24",    "26",    "VIII+",      "E4 6b"),
      known("5.12b", "7b",     "25",    "27",    "IX-",        "E5 6b"),
      known("5.12c", "7b+",    "26",    "28",    "IX-/IX",     "E5/E6 6b"),
      known("5.12d", "7c",     "27",    "29",    "IX/IX+",     "E6 6b"),
      known("5.13a", "7c+",    "28",    "30",    "IX+",        "E6 6c"),
      known("5.13b", "8a",     "29",    "31",    "X-",         "E7 6c"),
      known("5.13c", "8a+",    "30",    "32",    "X-/X",       "E7 7a"),
      known("5.13d", "8b",     "31",    "33",    "X/X+",       "E8 7a"),
      known("5.14a", "8b+",    "32",    "34",    "X+",         "E8 7b"),
      known("5.14b", "8c",     "33",    "35",    "XI-",        "E9 7b"),
      known("5.14c", "8c+",    "34",    "36",    "XI",         "E10 7b"),
      known("5.14d", "9a",     "35",    "37",    "XI+",        "E10 7c"),
      known("5.15a", "9a+",    "36",    "38",    "XI+/XII-",   "E11 7c"),
      known("5.15b", "9b",     "37",    "39",    "XII-/XII",   "E11 8a"),
      known("5.15c", "9b+",    "38",    "40",    "XII",        "E11 8b"),
      known("5.15d", "9c",     "39",    "41",    "XII+",       "E11+8c"));
  //@formatter:on

  private static ClimbingGrade known(String usa, String france, String australia,
                                     String southAfrica, String germany, String uk) {
    return new AutoValue_ClimbingGrade(ImmutableSetMultimap.<Country, String> builder()
                                                           .putAll(Country.USA, split(usa))
                                                           .putAll(Country.FRANCE, split(france))
                                                           .putAll(Country.AUSTRALIA, split(australia))
                                                           .putAll(Country.SOUTH_AFRICA, split(southAfrica))
                                                           .putAll(Country.GERMANY, split(germany))
                                                           .putAll(Country.UNITED_KINGDOM, split(uk))
                                                           .build());
  }

  private static String[] split(String value) {
    return value.split("/");
  }

  ClimbingGrade() {}

  abstract SetMultimap<Country, String> values();

  private boolean matches(Country country, String value) {
    return values().get(country).contains(value);
  }

  @Override
  public int compareTo(ClimbingGrade other) {
    return Integer.compare(KNOWN.indexOf(this), KNOWN.indexOf(other));
  }
}

@@ -59,14 +59,116 @@
 til.
-List;%0A
+Collection;%0Aimport java.util.List;%0Aimport java.util.Map;%0A%0Aimport com.fasterxml.jackson.annotation.JsonValue;
 %0Aimp
@@ -4597,16 +4597,112 @@
 ues();%0A%0A
+  @JsonValue%0A  Map%3CCountry, Collection%3CString%3E%3E valuesMap() %7B%0A    return values().asMap();%0A  %7D%0A%0A
   privat

Allow climbing grade to serialize to json