/**
 * Copyright 2009 KaChing Group Inc. Licensed under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
 * or agreed to in writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package com.kaching.platform.common.values;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

import java.util.Map;
import java.util.concurrent.ConcurrentMap;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.MapMaker;
import com.google.common.collect.ImmutableMap.Builder;
import com.kaching.platform.common.functional.Thunk;

/**
 * Utility class to help with numbered enums. A numbered enum is one that
 * implements {@link NumberedValue}.
 */
public class NumberedEnum {

  private static ConcurrentMap<Class<?>, Thunk<Map<Integer, Enum<?>>>> mappings =
      new MapMaker().makeMap();

  /**
   * Returns the enum constant of the specified enum type with the specified
   * number. (This function is similar to {@link Enum#valueOf(Class, String)}.)
   * 
   * @throws IllegalArgumentException if no enum match the provided number
   * @throws NullPointerException if the {@code value} is {@code null}
   */
  @SuppressWarnings("unchecked")
  public static <E extends Enum<E> & NumberedValue> E valueOf(final Class<E> type, int number) {
    checkNotNull(type);
    mappings.putIfAbsent(
        type,
        new Thunk<Map<Integer,Enum<?>>>() {
          @Override
          protected Map<Integer, Enum<?>> compute() {
            try {
              Builder<Integer, Enum<?>> builder = ImmutableMap.<Integer, Enum<?>> builder();
              E[] values = (E[]) type.getMethod("values").invoke(null);
              for (E value : values) {
                builder.put(value.getNumber(), value);
              }
              return builder.build();
            } catch (Exception e) {
              throw new IllegalStateException();
            }
          }
        });
    E value = (E) mappings.get(type).get().get(number);
    checkArgument(value != null);
    return value;
  }
  
}

@@ -834,24 +834,65 @@
 rentMap;%0D%0A%0D%0A
+import com.google.common.base.Function;%0D%0A
 import com.g
@@ -1030,62 +1030,8 @@
 er;%0D
-%0Aimport com.kaching.platform.common.functional.Thunk;%0D
 %0A%0D%0A/
@@ -1224,22 +1224,16 @@
 ass%3C?%3E, 
-Thunk%3C
 Map%3CInte
@@ -1246,17 +1246,16 @@
 num%3C?%3E%3E%3E
-%3E
  mapping
@@ -1288,563 +1288,44 @@
 make
-Map();%0D%0A%0D%0A  /**%0D%0A   * Returns the enum constant of the specified enum type with the specified%0D%0A   * number. (This function is similar to %7B@link Enum#valueOf(Class, String)%7D.)%0D%0A   * %0D%0A   * @throws IllegalArgumentException if no enum match the provided number%0D%0A   * @throws NullPointerException if the %7B@code value%7D is %7B@code null%7D%0D%0A   */%0D%0A  @SuppressWarnings(%22unchecked%22)%0D%0A  public static %3CE extends Enum%3CE%3E & NumberedValue%3E E valueOf(final Class%3CE%3E type, int number) %7B%0D%0A    checkNotNull(type);%0D%0A    mappings.putIfAbsent(%0D%0A        type,%0D%0A        new Thunk%3C
+ComputingMap(new Function%3CClass%3C?%3E, 
 Map%3C
@@ -1332,16 +1332,17 @@
 Integer,
+ 
 Enum%3C?%3E%3E
@@ -1356,18 +1356,16 @@
         
- 
- 
 @Overrid
@@ -1379,19 +1379,14 @@
     
-  protected
+public
  Map
@@ -1408,23 +1408,32 @@
 ?%3E%3E 
-compute(
+apply(Class%3C?%3E from
 ) %7B%0D%0A
-  
     
@@ -1441,26 +1441,24 @@
      try %7B%0D%0A
-  
             
@@ -1553,33 +1553,130 @@
     
-  E%5B%5D values = (E%5B%5D) type
+// Multiple casts valid from type parameter bounds declared in valueOf().%0D%0A            Enum%3C?%3E%5B%5D values = (Enum%3C?%3E%5B%5D) from
 .get
@@ -1723,16 +1723,20 @@
     
-  
 for (E
+num%3C?%3E
  val
@@ -1765,18 +1765,16 @@
         
-  
 builder.
@@ -1777,21 +1777,38 @@
 der.put(
+((NumberedValue)
 value
+)
 .getNumb
@@ -1818,26 +1818,24 @@
 ), value);%0D%0A
-  
             
@@ -1849,18 +1849,16 @@
         
-  
 return b
@@ -1870,26 +1870,24 @@
 r.build();%0D%0A
-  
           %7D 
@@ -1921,18 +1921,16 @@
         
-  
 throw ne
@@ -1953,32 +1953,41 @@
 ception();%0D%0A    
+      %7D%0D%0A
         %7D%0D%0A     
@@ -1987,32 +1987,504 @@
 %0D%0A      
-    %7D%0D%0A        %7D
+%7D);%0D%0A%0D%0A  /**%0D%0A   * Returns the enum constant of the specified enum type with the specified%0D%0A   * number. (This function is similar to %7B@link Enum#valueOf(Class, String)%7D.)%0D%0A   * %0D%0A   * @throws IllegalArgumentException if no enum match the provided number%0D%0A   * @throws NullPointerException if the %7B@code value%7D is %7B@code null%7D%0D%0A   */%0D%0A  @SuppressWarnings(%22unchecked%22)%0D%0A  public static %3CE extends Enum%3CE%3E & NumberedValue%3E E valueOf(final Class%3CE%3E type, int number) %7B%0D%0A    checkNotNull(type
 );%0D%0A    
@@ -2520,22 +2520,16 @@
 pe).get(
-).get(
 number);

Use MapMaker#makeComputingMap() rather than Map+Thunk.