package org.ambraproject.wombat.service.remote;

import com.google.common.base.Preconditions;
import org.ambraproject.wombat.util.CacheParams;
import org.ambraproject.wombat.util.UrlParamBuilder;

import java.util.Objects;
import java.util.OptionalInt;
import java.util.UUID;

public abstract class ContentKey {

  protected final String key;

  // Nested subclasses only
  private ContentKey(String key) {
    Preconditions.checkArgument(!key.isEmpty());
    this.key = key;
  }

  public abstract void setParameters(UrlParamBuilder requestParams);

  public abstract String asCacheKey();

  @Override
  public boolean equals(Object o) {
    return this == o || o != null && getClass() == o.getClass() && key.equals(((ContentKey) o).key);
  }

  @Override
  public int hashCode() {
    return key.hashCode();
  }


  public static ContentKey createForLatestVersion(String key) {
    return new VersionContentKey(key, OptionalInt.empty());
  }

  public static ContentKey createForVersion(String key, int version) {
    return new VersionContentKey(key, OptionalInt.of(version));
  }

  private static final class VersionContentKey extends ContentKey {
    private final OptionalInt version;

    private VersionContentKey(String key, OptionalInt version) {
      super(key);
      Preconditions.checkArgument(!version.isPresent() || version.getAsInt() >= 0);
      this.version = version;
    }

    @Override
    public void setParameters(UrlParamBuilder requestParams) {
      requestParams.add("key", key);
      if (version.isPresent()) {
        requestParams.add("version", Integer.toString(version.getAsInt()));
      }
    }

    @Override
    public String asCacheKey() {
      String versionString = version.isPresent() ? Integer.toString(version.getAsInt()) : String.valueOf((Object) null);
      return CacheParams.createKeyHash(key, versionString);
    }

    @Override
    public String toString() {
      return String.format("[key: %s, version: %s]", key, version);
    }

    @Override
    public boolean equals(Object o) {
      return this == o || super.equals(o) && version.equals(((VersionContentKey) o).version);
    }

    @Override
    public int hashCode() {
      return 31 * super.hashCode() + version.hashCode();
    }
  }


  public static ContentKey createForUuid(String key, UUID uuid) {
    return new UuidContentKey(key, uuid);
  }

  private static final class UuidContentKey extends ContentKey {
    private final UUID uuid;

    public UuidContentKey(String key, UUID uuid) {
      super(key);
      this.uuid = Objects.requireNonNull(uuid);
    }

    @Override
    public void setParameters(UrlParamBuilder requestParams) {
      requestParams.add("key", key).add("uuid", uuid.toString());
    }

    @Override
    public String asCacheKey() {
      return CacheParams.createKeyHash(key, uuid.toString());
    }

    @Override
    public String toString() {
      return String.format("[key: %s, uuid: %s]", key, uuid);
    }

    @Override
    public boolean equals(Object o) {
      return this == o || super.equals(o) && uuid.equals(((UuidContentKey) o).uuid);
    }

    @Override
    public int hashCode() {
      return 31 * super.hashCode() + uuid.hashCode();
    }
  }

}

@@ -270,16 +270,122 @@
 .UUID;%0A%0A
+/**%0A * Uniquely identifies an entity in the Content Repo, using various ways to distinguish versions.%0A */%0A
 public a
@@ -586,75 +586,343 @@
 %0A%0A  
-public abstract void setParameters(UrlParamBuilder requestParams);%0A
+/**%0A   * Set the parameters for a Content Repo request to identify this key's entity.%0A   *%0A   * @param requestParams the builder to modify by adding parameters%0A   */%0A  public abstract void setParameters(UrlParamBuilder requestParams);%0A%0A  /**%0A   * @return a cache key that is reliably unique among all %7B@link ContentKey%7D instances%0A   */
 %0A  p
@@ -1179,24 +1179,130 @@
 de();%0A  %7D%0A%0A%0A
+  /**%0A   * @param key a Content Repo key%0A   * @return a pointer at the latest version with that key%0A   */%0A
   public sta
@@ -1418,16 +1418,166 @@
 );%0A  %7D%0A%0A
+  /**%0A   * @param key     a Content Repo key%0A   * @param version a Content Repo version number%0A   * @return a pointer at the identified version%0A   */%0A
   public
@@ -1700,32 +1700,123 @@
 version));%0A  %7D%0A%0A
+  /**%0A   * Identifies a Content Repo entity with the progression of version numbers.%0A   */%0A
   private static
@@ -2968,16 +2968,172 @@
 %7D%0A  %7D%0A%0A%0A
+  /**%0A   * @param key  a Content Repo key%0A   * @param uuid a UUID identifying a Content Repo version%0A   * @return a pointer at the identified version%0A   */%0A
   public
@@ -3237,16 +3237,109 @@
 );%0A  %7D%0A%0A
+  /**%0A   * Identifies a Content Repo entity with a UUID pointing directly a a version.%0A   */%0A
   privat

Add Javadoc