package crazypants.enderio.base.conduit.geom;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Nonnull;

import crazypants.enderio.base.conduit.IConduit;
import net.minecraft.util.EnumFacing;

public class CollidableCache {

  public static final CollidableCache instance = new CollidableCache();

  private final Map<CacheKey, Collection<CollidableComponent>> cache = new HashMap<CollidableCache.CacheKey, Collection<CollidableComponent>>();

  public CacheKey createKey(@Nonnull Class<? extends IConduit> baseType, @Nonnull Offset offset, @Nonnull EnumFacing dir, boolean isStub) {
    return new CacheKey(baseType, offset, dir, isStub);
  }

  public Collection<CollidableComponent> getCollidables(@Nonnull CacheKey key, @Nonnull IConduit conduit) {
    Collection<CollidableComponent> result = cache.get(key);
    if (result == null) {
      result = conduit.createCollidables(key);
      cache.put(key, result);
    }
    return result;
  }

  public static class CacheKey {

    public final @Nonnull Class<? extends IConduit> baseType;
    public final @Nonnull String className; // used to generate reliable equals / hashcode
    public final @Nonnull Offset offset;
    public final @Nonnull EnumFacing dir;
    public final boolean isStub;

    public CacheKey(@Nonnull Class<? extends IConduit> baseType, @Nonnull Offset offset, @Nonnull EnumFacing dir, boolean isStub) {
      this.baseType = baseType;
      className = baseType.getCanonicalName();
      this.offset = offset;
      this.dir = dir;
      this.isStub = isStub;
    }

    @Override
    public int hashCode() {
      final int prime = 31;
      int result = 1;
      result = prime * result + className.hashCode();
      result = prime * result + dir.hashCode();
      result = prime * result + (isStub ? 1231 : 1237);
      result = prime * result + offset.hashCode();
      return result;
    }

    @Override
    public boolean equals(Object obj) {
      if (this == obj) {
        return true;
      }
      if (obj == null) {
        return false;
      }
      if (getClass() != obj.getClass()) {
        return false;
      }
      CacheKey other = (CacheKey) obj;
      if (!className.equals(other.className)) {
        return false;
      }
      if (dir != other.dir) {
        return false;
      }
      if (isStub != other.isStub) {
        return false;
      }
      if (offset != other.offset) {
        return false;
      }
      return true;
    }

  }

}

@@ -150,16 +150,50 @@
 Nonnull;
+%0Aimport javax.annotation.Nullable;
 %0A%0Aimport
@@ -616,38 +616,39 @@
 ffset offset, @N
-onn
 ull
+able
  EnumFacing dir,
@@ -1276,22 +1276,23 @@
 final @N
-onn
 ull
+able
  EnumFac
@@ -1425,22 +1425,23 @@
 fset, @N
-onn
 ull
+able
  EnumFac
@@ -1808,16 +1808,33 @@
 result +
+ ((dir != null) ?
  dir.has
@@ -1832,32 +1832,37 @@
 ? dir.hashCode()
+ : 0)
 ;%0A      result =

Fix CollidableCache being more of a CrashingCache