package nearenough.protocol;

import nearenough.exceptions.InvalidTagException;

import java.util.Arrays;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Roughtime protocol Tags
 */
public enum RtTag {

  CERT('C', 'E', 'R', 'T'),
  DELE('D', 'E', 'L', 'E'),
  INDX('I', 'N', 'D', 'X'),
  MAXT('M', 'A', 'X', 'T'),
  MIDP('M', 'I', 'D', 'P'),
  MINT('M', 'I', 'N', 'T'),
  NONC('N', 'O', 'N', 'C'),
  PAD('P', 'A', 'D', 0xff),
  PATH('P', 'A', 'T', 'H'),
  PUBK('P', 'U', 'B', 'K'),
  RADI('R', 'A', 'D', 'I'),
  ROOT('R', 'O', 'O', 'T'),
  SIG('S', 'I', 'G', 0x00),
  SREP('S', 'R', 'E', 'P');

  // TODO(stuart) use primitive collection to eliminate boxing
  private static final Map<Integer, RtTag> wireToTag = Arrays.stream(values())
      .collect(Collectors.toMap(RtTag::intValue, Function.identity()));

  /**
   * Return the {@link RtTag} that corresponds to the provided uint32 value, or throw
   * {@link InvalidTagException} if no mapping exists.
   *
   * @param tagValue unsigned 32-bit tag
   *
   * @return the {@link RtTag} that corresponds to the value, or throw
   * {@link InvalidTagException} if no mapping exists.
   */
  public static RtTag fromUnsignedInt(int tagValue) throws InvalidTagException {
    RtTag tag = wireToTag.get(tagValue);

    if (tag != null) {
      return tag;
    } else {
      String exMsg = String.format(
          "'%c%c%c%c' (0x%08x)",
          (char) (tagValue >> 24 & 0xff),
          (char) (tagValue >> 16 & 0xff),
          (char) (tagValue >> 8 & 0xff),
          (char) (tagValue & 0xff),
          tagValue
      );
      throw new InvalidTagException(exMsg);
    }
  }

  private final int intValue;

  RtTag(int... bytes) {
    this.intValue = (bytes[3] | bytes[2] << 8 | bytes[1] << 16 | bytes[0] << 24);
  }

  private int intValue() {
    return intValue;
  }
}

@@ -34,169 +34,145 @@
 ort 
-nearenough.excep
+io.netty.util.collec
 tion
-s
 .In
-validTagException;%0A%0Aimport java.util.Arrays;%0Aimport java.util.Map;%0Aimport java.util.function.Function;%0Aimport java.util.stream.Collectors
+tObjectHashMap;%0Aimport io.netty.util.collection.IntObjectMap;%0Aimport nearenough.exceptions.InvalidTagException
 ;%0A%0A/
@@ -200,16 +200,17 @@
 col Tags
+.
 %0A */%0Apub
@@ -629,26 +629,9 @@
  // 
-TODO(stuart) use p
+P
 rimi
@@ -646,16 +646,24 @@
 lection 
+is used 
 to elimi
@@ -673,16 +673,53 @@
 e boxing
+ from the hot-path of fromUnsignedInt
 %0A  priva
@@ -738,21 +738,21 @@
 nal 
-Map%3CInteger, 
+IntObjectMap%3C
 RtTa
@@ -770,103 +770,152 @@
 g = 
-Arrays.stream(values())%0A      .collect(Collectors.toMap(RtTag::intValue, Function.identity()));
+new IntObjectHashMap%3C%3E(values().length);%0A%0A  static %7B%0A    for (RtTag rtTag : values()) %7B%0A      wireToTag.put(rtTag.wireValue(), rtTag);%0A    %7D%0A  %7D
 %0A%0A  
@@ -980,16 +980,39 @@
 provided
+ %3Cem%3Elittle-endian%3C/em%3E
  uint32 
@@ -1013,24 +1013,29 @@
 int32 value,
+%0A   *
  or throw%0A  
@@ -1023,37 +1023,33 @@
 e,%0A   * or throw
-%0A   *
+s
  %7B@link InvalidT
@@ -1109,16 +1109,30 @@
 agValue 
+little-endian 
 unsigned
@@ -1218,21 +1218,17 @@
 or throw
-%0A   *
+s
  %7B@link 
@@ -1239,32 +1239,37 @@
 lidTagException%7D
+%0A   *
  if no mapping e
@@ -1787,27 +1787,28 @@
 e final int 
-int
+wire
 Value;%0A%0A  Rt
@@ -1835,16 +1835,89 @@
     
-this.int
+// Per the spec, Roughtime tag values are little-endian on-the-wire%0A    this.wire
 Valu
@@ -1927,17 +1927,17 @@
  (bytes%5B
-3
+0
 %5D %7C byte
@@ -1938,17 +1938,17 @@
 %7C bytes%5B
-2
+1
 %5D %3C%3C 8 %7C
@@ -1950,25 +1950,25 @@
 %3C 8 %7C bytes%5B
-1
+2
 %5D %3C%3C 16 %7C by
@@ -1971,17 +1971,17 @@
 %7C bytes%5B
-0
+3
 %5D %3C%3C 24)
@@ -2001,19 +2001,20 @@
 ate int 
-int
+wire
 Value() 
@@ -2026,19 +2026,20 @@
  return 
-int
+wire
 Value;%0A 

Use a primitive Int2Object map in RtTag to eliminate autoboxing.