/*
 * Copyright 2008 Google 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.
 * 
 * Modifications to this file made by IBM are copyright (c) 2008 IBM Corporation 
 * 
 */
package java.lang;

/**
 * Wraps a primitive <code>int</code> as an object.
 */
public final class Integer extends Number implements Comparable<Integer> {
	
//TODO: e4 added TYPE field
  public static final Class TYPE = new Class("int");

  public static final int MAX_VALUE = 0x7fffffff;
  //TODO: e4 changed MIN VALUE
  //public static final int MIN_VALUE = 0x80000000;
  public static final int MIN_VALUE = -2147483648;//0x80000000;

  public static final int SIZE = 32;

  /**
   * Use nested class to avoid clinit on outer.
   */
  private static class BoxedValues {
    // Box values according to JLS - between -128 and 127
  private static Integer[] boxedValues = new Integer[256];
  }
  
  /**
   * Use nested class to avoid clinit on outer.
   */
  private static class ReverseNibbles {
    /**
     * A fast-lookup of the reversed bits of all the nibbles 0-15. Used to
     * implement {@link #reverse(int)}.
     */
  private static int[] reverseNibbles = {
    0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, 0x1, 0x9, 0x5, 0xd, 0x3, 0xb,
    0x7, 0xf};
  }
  
  public static int bitCount(int x) {
    // Courtesy the University of Kentucky
    // http://aggregate.org/MAGIC/#Population%20Count%20(Ones%20Count)
    x -= ((x >> 1) & 0x55555555);
    x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
    x = (((x >> 4) + x) & 0x0f0f0f0f);
    x += (x >> 8);
    x += (x >> 16);
    return x & 0x0000003f;
  }

  public static Integer decode(String s) throws NumberFormatException {
    return new Integer((int) __decodeAndValidateInt(s, MIN_VALUE, MAX_VALUE));
  }

  /**
   * @skip
   * 
   * Here for shared implementation with Arrays.hashCode
   */
  public static int hashCode(int i) {
    return i;
  }

  public static int highestOneBit(int i) {
    if (i < 0) {
      return MIN_VALUE;
    } else if (i == 0) {
      return 0;
    } else {
      int rtn;
      for (rtn = 0x40000000; (rtn & i) == 0; rtn >>= 1) {
        // loop down until matched
      }
      return rtn;
    }
  }

  public static int lowestOneBit(int i) {
    return i & -i;
  }

  public static int numberOfLeadingZeros(int i) {
    if (i < 0) {
      return 0;
    } else if (i == 0) {
      return SIZE;
    } else {
      return SIZE - 1 - (int) Math.floor(Math.log(i) / Math.log(2.0d));
    }
  }

  public static int numberOfTrailingZeros(int i) {
    if (i == 0) {
      return SIZE;
    } else {
      int rtn = 0;
      for (int r = 1; (r & i) == 0; r <<= 1) {
        rtn++;
      }
      return rtn;
    }
  }

  public static int parseInt(String s) throws NumberFormatException {
    return parseInt(s, 10);
  }

  public static int parseInt(String s, int radix) throws NumberFormatException {
    return __parseAndValidateInt(s, radix, MIN_VALUE, MAX_VALUE);
  }

  public static int reverse(int i) {
    int[] nibbles = ReverseNibbles.reverseNibbles;
    return (nibbles[i >>> 28]) | (nibbles[(i >> 24) & 0xf] << 4)
        | (nibbles[(i >> 20) & 0xf] << 8) | (nibbles[(i >> 16) & 0xf] << 12)
        | (nibbles[(i >> 12) & 0xf] << 16) | (nibbles[(i >> 8) & 0xf] << 20)
        | (nibbles[(i >> 4) & 0xf] << 24) | (nibbles[i & 0xf] << 28);
  }

  public static int reverseBytes(int i) {
    return ((i & 0xff) << 24) | ((i & 0xff00) << 8) | ((i & 0xff0000) >> 8)
        | ((i & 0xff000000) >>> 24);
  }

  public static int rotateLeft(int i, int distance) {
    while (distance-- > 0) {
      i = i << 1 | ((i < 0) ? 1 : 0);
    }
    return i;
  }

  public static int rotateRight(int i, int distance) {
    int ui = i & MAX_VALUE; // avoid sign extension
    int carry = (i < 0) ? 0x40000000 : 0; // MIN_VALUE rightshifted 1
    while (distance-- > 0) {
      int nextcarry = ui & 1;
      ui = carry | (ui >> 1);
      carry = (nextcarry == 0) ? 0 : 0x40000000;
    }
    if (carry != 0) {
      ui = ui | MIN_VALUE;
    }
    return ui;
  }

  public static int signum(int i) {
    if (i == 0) {
      return 0;
    } else if (i < 0) {
      return -1;
    } else {
      return 1;
    }
  }

  public static String toBinaryString(int value) {
    return toPowerOfTwoString(value, 1);
  }

  public static String toHexString(int value) {
    return toPowerOfTwoString(value, 4);
  }

  public static String toOctalString(int value) {
    return toPowerOfTwoString(value, 3);
  }

  public static String toString(int value) {
    return String.valueOf(value);
  }

  public static String toString(int value, int radix) {
    if (radix == 10 || radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) {
      return String.valueOf(value);
    }

    final int bufSize = 33;
    char[] buf = new char[bufSize];
    int pos = bufSize - 1;
    if (value >= 0) {
      while (value >= radix) {
        buf[pos--] = __Digits.digits[value % radix];
        value /= radix;
      }
      buf[pos] = __Digits.digits[value];
    } else {
      while (value <= -radix) {
        buf[pos--] = __Digits.digits[-(value % radix)];
        value /= radix;
      }
      buf[pos--] = __Digits.digits[-value];
      buf[pos] = '-';
    }
    //TODO: e4 fixed bug
    //return String.__valueOf(buf, pos, bufSize);
    return String.valueOf(buf, pos, bufSize);
  }

  public static Integer valueOf(int i) {
    if (i > -129 && i < 128) {
      int rebase = i + 128;
      Integer result = BoxedValues.boxedValues[rebase];
      if (result == null) {
        result = BoxedValues.boxedValues[rebase] = new Integer(i);
      }
      return result;
    }
    return new Integer(i);
  }

  public static Integer valueOf(String s) throws NumberFormatException {
    return new Integer(Integer.parseInt(s));
  }

  public static Integer valueOf(String s, int radix)
      throws NumberFormatException {
    return new Integer(Integer.parseInt(s, radix));
  }

  private static String toPowerOfTwoString(int value, int shift) {
    final int bufSize = 32 / shift;
    int bitMask = (1 << shift) - 1;
    char[] buf = new char[bufSize];
    int pos = bufSize - 1;
    if (value >= 0) {
      while (value > bitMask) {
        buf[pos--] = __Digits.digits[value & bitMask];
        value >>= shift;
      }
    } else {
      while (pos > 0) {
        buf[pos--] = __Digits.digits[value & bitMask];
        value >>= shift;
      }
    }
    buf[pos] = __Digits.digits[value & bitMask];
    //TODO: e4 fixed bug
    // return String.__valueOf(buf, pos, bufSize);
    return String.valueOf(buf, pos, bufSize - pos);
  }

  private final transient int value;

  public Integer(int value) {
    this.value = value;
  }

  public Integer(String s) {
    value = parseInt(s);
  }

  @Override
  public byte byteValue() {
    return (byte) value;
  }

  public int compareTo(Integer b) {
    if (value < b.value) {
      return -1;
    } else if (value > b.value) {
      return 1;
    } else {
      return 0;
    }
  }

  @Override
  public double doubleValue() {
    return value;
  }

  @Override
  public boolean equals(Object o) {
    return (o instanceof Integer) && (((Integer) o).value == value);
  }

  @Override
  public float floatValue() {
    return value;
  }

  @Override
  public int hashCode() {
    return hashCode(value);
  }

  @Override
  public int intValue() {
    return value;
  }

  @Override
  public long longValue() {
    return value;
  }

  @Override
  public short shortValue() {
    return (short) value;
  }

  @Override
  public String toString() {
    return toString(value);
  }

}
