package com.google.gwt.lang {
import java.lang.Math__;
import java.lang.Long;
import java.lang.ArithmeticException;
import java.lang.Double;
import java.lang.Arguments;
import java.lang.JavaArray;
dynamic public class LongLib {
  public static var boxedValues: JavaArray = new JavaArray("[[D").lengths(256);
  public static var LN_2: Number = Math__.log__D(2);
  public static var MAX_VALUE: JavaArray = typeChange__J(-1);
  public static var MIN_VALUE: JavaArray = typeChange__J(-1);
  public static var NEG_ONE: JavaArray = fromInt__I(-1);
  public static var ONE: JavaArray = fromInt__I(1);
  public static var TWO: JavaArray = fromInt__I(2);
  public static var TWO_PWR_24: JavaArray = typeChange__J(16777216);
  public static var ZERO: JavaArray = fromInt__I(0);
  public static var RUN_IN_JVM: Boolean = false;
  public static const PRECISION_BITS: int = 48;
  public static const HIGH: int = 1;
  public static const HIGH_MAX: Number = 9.2233720325598085E18;
  public static const HIGH_MIN: Number = -9.223372036854776E18;
  public static const LOW: int = 0;
  public static const LOW_MAX: Number = 4.294967295E9;
  public static const LOW_MIN: Number = 0;
  public static const TWO_PWR_15_DBL: Number = 0x8000;
  public static const TWO_PWR_16_DBL: Number = 0x10000;
  public static const TWO_PWR_31_DBL: Number = 65536.0 * 32768.0;
  public static const TWO_PWR_32_DBL: Number = 65536.0 * 65536.0;
  public static const TWO_PWR_48_DBL: Number = 4.294967296E9 * 65536.0;
  public static const TWO_PWR_63_DBL: Number = 4.294967296E9 * 2.147483648E9;
  public static const TWO_PWR_64_DBL: Number = 4.294967296E9 * 4.294967296E9;
  public static function add___3D_3D(a: JavaArray, b: JavaArray): JavaArray {
    var newHigh: Number = a[1] + b[1];
    var newLow: Number = a[0] + b[0];
    return create__DD(newLow, newHigh);
  }
  public static function and___3D_3D(a: JavaArray, b: JavaArray): JavaArray {
    return makeFromBits__II(highBits___3D(a) & highBits___3D(b), lowBits___3D(a) & lowBits___3D(b));
  }
  public static function compare___3D_3D(a: JavaArray, b: JavaArray): int {
    if (eq___3D_3D(a, b)) {
      return 0;
    }
    var nega: Boolean = isNegative___3D(a);
    var negb: Boolean = isNegative___3D(b);
    if (nega && !negb) {
      return -1;
    }
    if (!nega && negb) {
      return 1;
    }
    if (isNegative___3D(sub___3D_3D(a, b))) {
      return -1;
    } else {
      return 1;
    }
    return 0;
  }
  public static function div___3D_3D(a: JavaArray, b: JavaArray): JavaArray {
    if (isZero___3D(b)) {
      throw new ArithmeticException(new Arguments(java.lang.ArithmeticException.ArithmeticException__Ljava_lang_String_2, ["/ by zero"]));
    }
    if (isZero___3D(a)) {
      return ZERO;
    }
    if (eq___3D_3D(a, MIN_VALUE)) {
      if (eq___3D_3D(b, ONE) || eq___3D_3D(b, NEG_ONE)) {
        return MIN_VALUE;
      }
      var halfa: JavaArray = shr___3DI(a, 1);
      var approx: JavaArray = shl___3DI(div___3D_3D(halfa, b), 1);
      var rem: JavaArray = sub___3D_3D(a, mul___3D_3D(b, approx));
      return add___3D_3D(approx, div___3D_3D(rem, b));
    }
    if (eq___3D_3D(b, MIN_VALUE)) {
      return ZERO;
    }
    if (isNegative___3D(a)) {
      if (isNegative___3D(b)) {
        return div___3D_3D(neg___3D(a), neg___3D(b));
      } else {
        return neg___3D(div___3D_3D(neg___3D(a), b));
      }
    }
    if (isNegative___3D(b)) {
      return neg___3D(div___3D_3D(a, neg___3D(b)));
    }
    var result: JavaArray = ZERO;
    var rem_1: JavaArray = a;
    while (gte___3D_3D(rem_1, b)) {
      var deltaResult: JavaArray = fromDouble__D(Math__.floor__D(toDoubleRoundDown___3D(rem_1) / toDoubleRoundUp___3D(b)));
      if (isZero___3D(deltaResult)) {
        deltaResult = ONE;
      }
      var deltaRem: JavaArray = mul___3D_3D(deltaResult, b);
      result = add___3D_3D(result, deltaResult);
      rem_1 = sub___3D_3D(rem_1, deltaRem);
    }
    return result;
  }
  public static function eq___3D_3D(a: JavaArray, b: JavaArray): Boolean {
    return ((a[0] == b[0]) && (a[1] == b[1]));
  }
  public static function fromDouble__D(value: Number): JavaArray {
    if (Double.isNaN__D(value)) {
      return ZERO;
    }
    if (value < -9.223372036854776E18) {
      return MIN_VALUE;
    }
    if (value >= 9.223372036854776E18) {
      return MAX_VALUE;
    }
    if (value > 0) {
      return create__DD(Math__.floor__D(value), 0.0);
    } else {
      return create__DD(Math__.ceil__D(value), 0.0);
    }
    return null;
  }
  public static function fromInt__I(value: int): JavaArray {
    if (value > -129 && value < 128) {
      var rebase: int = value + 128;
      var result: JavaArray = boxedValues[rebase];
      if (result === null) {
        result = boxedValues[rebase] = internalFromInt__I(value);
      }
      return result;
    }
    return internalFromInt__I(value);
  }
  public static function gt___3D_3D(a: JavaArray, b: JavaArray): Boolean {
    return compare___3D_3D(a, b) > 0;
  }
  public static function gte___3D_3D(a: JavaArray, b: JavaArray): Boolean {
    return compare___3D_3D(a, b) >= 0;
  }
  public static function lt___3D_3D(a: JavaArray, b: JavaArray): Boolean {
    return compare___3D_3D(a, b) < 0;
  }
  public static function lte___3D_3D(a: JavaArray, b: JavaArray): Boolean {
    return compare___3D_3D(a, b) <= 0;
  }
  public static function mod___3D_3D(a: JavaArray, b: JavaArray): JavaArray {
    return sub___3D_3D(a, mul___3D_3D(div___3D_3D(a, b), b));
  }
  public static function mul___3D_3D(a: JavaArray, b: JavaArray): JavaArray {
    if (isZero___3D(a)) {
      return ZERO;
    }
    if (isZero___3D(b)) {
      return ZERO;
    }
    if (eq___3D_3D(a, MIN_VALUE)) {
      return multByMinValue___3D(b);
    }
    if (eq___3D_3D(b, MIN_VALUE)) {
      return multByMinValue___3D(a);
    }
    if (isNegative___3D(a)) {
      if (isNegative___3D(b)) {
        return mul___3D_3D(neg___3D(a), neg___3D(b));
      } else {
        return neg___3D(mul___3D_3D(neg___3D(a), b));
      }
    }
    if (isNegative___3D(b)) {
      return neg___3D(mul___3D_3D(a, neg___3D(b)));
    }
    if (lt___3D_3D(a, TWO_PWR_24) && lt___3D_3D(b, TWO_PWR_24)) {
      return create__DD(toDouble___3D(a) * toDouble___3D(b), 0.0);
    }
    var a3: Number = a[1] % 2.81474976710656E14;
    var a4: Number = a[1] - a3;
    var a1: Number = a[0] % 65536.0;
    var a2: Number = a[0] - a1;
    var b3: Number = b[1] % 2.81474976710656E14;
    var b4: Number = b[1] - b3;
    var b1: Number = b[0] % 65536.0;
    var b2: Number = b[0] - b1;
    var res: JavaArray = ZERO;
    res = addTimes___3DDD(res, a4, b1);
    res = addTimes___3DDD(res, a3, b2);
    res = addTimes___3DDD(res, a3, b1);
    res = addTimes___3DDD(res, a2, b3);
    res = addTimes___3DDD(res, a2, b2);
    res = addTimes___3DDD(res, a2, b1);
    res = addTimes___3DDD(res, a1, b4);
    res = addTimes___3DDD(res, a1, b3);
    res = addTimes___3DDD(res, a1, b2);
    res = addTimes___3DDD(res, a1, b1);
    return res;
  }
  public static function neg___3D(a: JavaArray): JavaArray {
    if (eq___3D_3D(a, MIN_VALUE)) {
      return MIN_VALUE;
    }
    var newHigh: Number = -a[1];
    var newLow: Number = -a[0];
    if (newLow > 4.294967295E9) {
      newLow -= 4.294967296E9;
      newHigh += 4.294967296E9;
    }
    if (newLow < 0.0) {
      newLow += 4.294967296E9;
      newHigh -= 4.294967296E9;
    }
    return createNormalized__DD(newLow, newHigh);
  }
  public static function neq___3D_3D(a: JavaArray, b: JavaArray): Boolean {
    return ((a[0] != b[0]) || (a[1] != b[1]));
  }
  public static function not___3D(a: JavaArray): JavaArray {
    return makeFromBits__II(~highBits___3D(a), ~lowBits___3D(a));
  }
  public static function or___3D_3D(a: JavaArray, b: JavaArray): JavaArray {
    return makeFromBits__II(highBits___3D(a) | highBits___3D(b), lowBits___3D(a) | lowBits___3D(b));
  }
  public static function shl___3DI(a: JavaArray, n: int): JavaArray {
    n &= 63;
    if (eq___3D_3D(a, MIN_VALUE)) {
      if (n == 0) {
        return a;
      } else {
        return ZERO;
      }
    }
    if (isNegative___3D(a)) {
      return neg___3D(shl___3DI(neg___3D(a), n));
    }
    var twoToN: Number = pwrAsDouble__I(n);
    var newHigh: Number = a[1] * twoToN % 1.8446744073709552E19;
    var newLow: Number = a[0] * twoToN;
    var diff: Number = newLow - (newLow % 4.294967296E9);
    newHigh += diff;
    newLow -= diff;
    if (newHigh >= 9.223372036854776E18) {
      newHigh -= 1.8446744073709552E19;
    }
    return createNormalized__DD(newLow, newHigh);
  }
  public static function shr___3DI(a: JavaArray, n: int): JavaArray {
    n &= 63;
    var shiftFact: Number = pwrAsDouble__I(n);
    var newHigh: Number = a[1] / shiftFact;
    var newLow: Number = Math__.floor__D(a[0] / shiftFact);
    return create__DD(newLow, newHigh);
  }
  public static function shru___3DI(a: JavaArray, n: int): JavaArray {
    n &= 63;
    var sr: JavaArray = shr___3DI(a, n);
    if (isNegative___3D(a)) {
      sr = add___3D_3D(sr, shl___3DI(TWO, 63 - n));
    }
    return sr;
  }
  public static function sub___3D_3D(a: JavaArray, b: JavaArray): JavaArray {
    var newHigh: Number = a[1] - b[1];
    var newLow: Number = a[0] - b[0];
    return create__DD(newLow, newHigh);
  }
  public static function toDouble___3D(a: JavaArray): Number {
    return a[1] + a[0];
  }
  public static function toInt___3D(a: JavaArray): int {
    return lowBits___3D(a);
  }
  public static function toString___3D(a: JavaArray): String {
    if (isZero___3D(a)) {
      return "0";
    }
    if (eq___3D_3D(a, MIN_VALUE)) {
      return "-9223372036854775808";
    }
    if (isNegative___3D(a)) {
      return "-" + toString___3D(neg___3D(a));
    }
    var rem: JavaArray = a;
    var res: String = "";
    while (!isZero___3D(rem)) {
      var divByZeroes: int = 9;
      var divBy: int = 1000000000;
      var digits: String = "" + toInt___3D(mod___3D_3D(rem, fromInt__I(1000000000)));
      rem = div___3D_3D(rem, fromInt__I(1000000000));
      if (!isZero___3D(rem)) {
        var zeroesNeeded: int = 9 - Object(digits).length__();
        for (; zeroesNeeded > 0; zeroesNeeded--) {
          digits = "0" + digits;
        }
      }
      res = digits + res;
    }
    return res;
  }
  public static function typeChange__J(value: Number): JavaArray {
    if (RUN_IN_JVM) {
      return makeFromBits__II(int((value >> 32)), int(value));
    } else {
      return typeChange0__J(value);
    }
    return null;
  }
  public static function xor___3D_3D(a: JavaArray, b: JavaArray): JavaArray {
    return makeFromBits__II(highBits___3D(a) ^ highBits___3D(b), lowBits___3D(a) ^ lowBits___3D(b));
  }
  public static function toLong___3D(a: JavaArray): Number {
    return Number(a[1]) + Number(a[0]);
  }
  private static function addTimes___3DDD(accum: JavaArray, a: Number, b: Number): JavaArray {
    if (a == 0.0) {
      return accum;
    }
    if (b == 0.0) {
      return accum;
    }
    return add___3D_3D(accum, create__DD(a * b, 0.0));
  }
  private static function create__DD(valueLow: Number, valueHigh: Number): JavaArray {
    valueHigh %= 1.8446744073709552E19;
    valueLow %= 1.8446744073709552E19;
    {
      var diffHigh: Number = valueHigh % 4.294967296E9;
      var diffLow: Number = Math__.floor__D(valueLow / 4.294967296E9) * 4.294967296E9;
      valueHigh = (valueHigh - diffHigh) + diffLow;
      valueLow = (valueLow - diffLow) + diffHigh;
    }
    while (valueLow < 0.0) {
      valueLow += 4.294967296E9;
      valueHigh -= 4.294967296E9;
    }
    while (valueLow > 4.294967295E9) {
      valueLow -= 4.294967296E9;
      valueHigh += 4.294967296E9;
    }
    valueHigh = valueHigh % 1.8446744073709552E19;
    while (valueHigh > 9.2233720325598085E18) {
      valueHigh -= 1.8446744073709552E19;
    }
    while (valueHigh < -9.223372036854776E18) {
      valueHigh += 1.8446744073709552E19;
    }
    return createNormalized__DD(valueLow, valueHigh);
  }
  private static function createNormalized__DD(valueLow: Number, valueHigh: Number): JavaArray {
    if (RUN_IN_JVM) {
      return new JavaArray("[D").values(valueLow, valueHigh);
    } else {
      return newLong0__DD(valueLow, valueHigh);
    }
    return null;
  }
  private static function highBits___3D(a: JavaArray): int {
    return int((a[1] / 4.294967296E9));
  }
  private static function internalFromInt__I(value: int): JavaArray {
    if (value >= 0) {
      return createNormalized__DD(value, 0.0);
    } else {
      return createNormalized__DD(value + 4.294967296E9, -4.294967296E9);
    }
    return null;
  }
  private static function isNegative___3D(a: JavaArray): Boolean {
    return a[1] < 0;
  }
  private static function isOdd___3D(a: JavaArray): Boolean {
    return (lowBits___3D(a) & 1) == 1;
  }
  private static function isZero___3D(a: JavaArray): Boolean {
    return a[0] == 0.0 && a[1] == 0.0;
  }
  private static function lowBits___3D(a: JavaArray): int {
    if (a[0] >= 2.147483648E9) {
      return int((a[0] - 4.294967296E9));
    } else {
      return int(a[0]);
    }
    return 0;
  }
  private static function makeFromBits__II(highBits: int, lowBits: int): JavaArray {
    var high: Number = highBits * 4.294967296E9;
    var low: Number = lowBits;
    if (lowBits < 0) {
      low += 4.294967296E9;
    }
    return createNormalized__DD(low, high);
  }
  private static function multByMinValue___3D(a: JavaArray): JavaArray {
    if (isOdd___3D(a)) {
      return MIN_VALUE;
    } else {
      return ZERO;
    }
    return null;
  }
  private static function newLong0__DD(valueLow: Number, valueHigh: Number): JavaArray {
    var array = new java.lang.JavaArray("D");
    array.array = [valueLow, valueHigh];
    return array;
    //e4 explicity create array
    //return [valueLow, valueHigh];
  }
  private static function pwrAsDouble__I(n: int): Number {
    if (n <= 30) {
      return (1 << n);
    } else {
      return pwrAsDouble__I(30) * pwrAsDouble__I(n - 30);
    }
    return 0;
  }
  private static function toDoubleRoundDown___3D(a: JavaArray): Number {
    var magnitute: int = int((Math__.log__D(a[1]) / LN_2));
    if (magnitute <= 48) {
      return toDouble___3D(a);
    } else {
      var diff: int = magnitute - 48;
      var toSubtract: int = (1 << diff) - 1;
      return a[1] + (a[0] - toSubtract);
    }
    return 0;
  }
  private static function toDoubleRoundUp___3D(a: JavaArray): Number {
    var magnitute: int = int((Math__.log__D(a[1]) / LN_2));
    if (magnitute <= 48) {
      return toDouble___3D(a);
    } else {
      var diff: int = magnitute - 48;
      var toAdd: int = (1 << diff) - 1;
      return a[1] + (a[0] + toAdd);
    }
    return 0;
  }
  private static function typeChange0__J(value: Number): JavaArray {
    var array = new java.lang.JavaArray("D");
    array.array = [value];
    return array;
    //TODO: e4 explicitly create an array
    //return value;
  }
  function LongLib() {
    return;
  }
}
}
