


#double convert_rational_to_double(U *)
#double convert_bignum_to_double(unsigned int *)
#int ge(unsigned int *, unsigned int *, int)



mint = (a) ->
  return bigInt a

isSmall = (a) ->
  a.geq(Number.MIN_SAFE_INTEGER) && a.leq(Number.MAX_SAFE_INTEGER)

# b is +1 or -1, a is a bigint
setSignTo = (a,b) ->
  if a.isPositive()
    if b < 0
      return a.multiply bigInt -1
  else
    # a is negative
    if b > 0
      return a.multiply bigInt -1
  return a


makeSignSameAs = (a,b) ->
  if a.isPositive()
    if b.isNegative()
      return a.multiply bigInt -1
  else
    # a is negative
    if b.isPositive()
      return a.multiply bigInt -1
  return a

makePositive = (a) ->
  if a.isNegative()
    return a.multiply bigInt -1
  return a

# n is an int
###
mtotal = 0
MP_MIN_SIZE = 2
MP_MAX_FREE  = 1000

mnew = (n) ->
  if (n < MP_MIN_SIZE)
    n = MP_MIN_SIZE
  if (n == MP_MIN_SIZE && mfreecount)
    p = free_stack[--mfreecount]
  else
    p = [] #(unsigned int *) malloc((n + 3) * sizeof (int))
    #if (p == 0)
    #  stop("malloc failure")
  p[0] = n
  mtotal += n
  return p[3]
###

# p is the index of array of ints
# !!! array wasn't passed here
###
free_stack = []

mfree = (array, p) ->
  p -= 3
  mtotal -= array[p]
  if (array[p] == MP_MIN_SIZE && mfreecount < MP_MAX_FREE)
    free_stack[mfreecount++] = p
  else
    free(p)
###

# convert int to bignum

# n is an int
###
mint = (n) ->
  p = mnew(1)
  if (n < 0)
    # !!! this is FU
    # MSIGN(p) = -1
    fu = true
  else
    # !!! this is FU
    #MSIGN(p) = 1
    fu = true
  # !!! this is FU
  #MLENGTH(p) = 1
  p[0] = Math.abs(n)
  return p
###

# copy bignum

# a is an array of ints
###
mcopy = (a) ->
  #unsigned int *b

  b = mnew(MLENGTH(a))

  # !!! fu
  #MSIGN(b) = MSIGN(a)
  #MLENGTH(b) = MLENGTH(a)

  for i in [0...MLENGTH(a)]
    b[i] = a[i]

  return b
###


###
# 
# ge not invoked from anywhere - is you need ge
# just use the bigNum's ge implementation
# leaving it here just in case I decide to backport to C
#
# a >= b ?
# and and b arrays of ints, len is an int
ge = (a, b, len) ->
  i = 0
  for i in [0...len]
    if (a[i] == b[i])
      continue
    else
      break
  if (a[i] >= b[i])
    return 1
  else
    return 0
###

add_numbers = ->
  a = 1.0
  b = 1.0

  #if DEBUG then console.log("add_numbers adding numbers: " + print_list(stack[tos - 1]) + " and " + print_list(stack[tos - 2]))

  if (isrational(stack[tos - 1]) && isrational(stack[tos - 2]))
    qadd()
    return

  save()

  p2 = pop()
  p1 = pop()

  if (isdouble(p1))
    a = p1.d
  else
    a = convert_rational_to_double(p1)

  if (isdouble(p2))
    b = p2.d
  else
    b = convert_rational_to_double(p2)

  theResult = a+b
  push_double(theResult)

  restore()

subtract_numbers = ->
  a = 0.0
  b = 0.0

  if (isrational(stack[tos - 1]) && isrational(stack[tos - 2]))
    qsub()
    return

  save()

  p2 = pop()
  p1 = pop()

  if (isdouble(p1))
    a = p1.d
  else
    a = convert_rational_to_double(p1)

  if (isdouble(p2))
    b = p2.d
  else
    b = convert_rational_to_double(p2)

  push_double(a - b)

  restore()

multiply_numbers = ->
  a = 0.0
  b = 0.0

  if (isrational(stack[tos - 1]) && isrational(stack[tos - 2]))
    qmul()
    return

  save()

  p2 = pop()
  p1 = pop()

  if (isdouble(p1))
    a = p1.d
  else
    a = convert_rational_to_double(p1)

  if (isdouble(p2))
    b = p2.d
  else
    b = convert_rational_to_double(p2)

  push_double(a * b)

  restore()

divide_numbers = ->
  a = 0.0
  b = 0.0

  if (isrational(stack[tos - 1]) && isrational(stack[tos - 2]))
    qdiv()
    return

  save()

  p2 = pop()
  p1 = pop()

  if (isZeroAtomOrTensor(p2))
    stop("divide by zero")

  if (isdouble(p1))
    a = p1.d
  else
    a = convert_rational_to_double(p1)

  if (isdouble(p2))
    b = p2.d
  else
    b = convert_rational_to_double(p2)

  push_double(a / b)

  restore()

invert_number = ->
  #unsigned int *a, *b

  save()

  p1 = pop()

  if (isZeroAtomOrTensor(p1))
    stop("divide by zero")

  if (isdouble(p1))
    push_double(1 / p1.d)
    restore()
    return

  a = bigInt(p1.q.a)
  b = bigInt(p1.q.b)

  b = makeSignSameAs(b,a)
  a = setSignTo(a,1)

  p1 = new U()
  p1.k = NUM
  p1.q.a = b
  p1.q.b = a

  push(p1)

  restore()

# a and b are Us
compare_rationals = (a, b) ->
  t = 0
  #unsigned int *ab, *ba
  ab = mmul(a.q.a, b.q.b)
  ba = mmul(a.q.b, b.q.a)
  t = mcmp(ab, ba)
  return t

# a and b are Us
compare_numbers = (a,b) ->
  x = 0.0
  y = 0.0
  if (isrational(a) && isrational(b))
    return compare_rationals(a, b)
  if (isdouble(a))
    x = a.d
  else
    x = convert_rational_to_double(a)
  if (isdouble(b))
    y = b.d
  else
    y = convert_rational_to_double(b)
  if (x < y)
    return -1
  if (x > y)
    return 1
  return 0

negate_number = ->
  save()
  p1 = pop()
  if (isZeroAtomOrTensor(p1))
    push(p1)
    restore()
    return

  switch (p1.k)
    when NUM
      p2 = new U()
      p2.k = NUM
      p2.q.a = bigInt(p1.q.a.multiply(bigInt.minusOne))
      p2.q.b = bigInt(p1.q.b)
      push(p2)
    when DOUBLE
      push_double(-p1.d)
    else
      stop("bug caught in mp_negate_number")
  restore()

bignum_truncate = ->
  #unsigned int *a

  save()

  p1 = pop()

  a = mdiv(p1.q.a, p1.q.b)

  p1 = new U()

  p1.k = NUM

  p1.q.a = a
  p1.q.b = bigInt(1)

  push(p1)

  restore()

mp_numerator = ->
  save()

  p1 = pop()

  if (p1.k != NUM)
    push(one)
    restore()
    return

  p2 = new U()

  p2.k = NUM

  p2.q.a = bigInt(p1.q.a)
  p2.q.b = bigInt(1)

  push(p2)

  restore()

mp_denominator = ->
  save()

  p1 = pop()

  if (p1.k != NUM)
    push(one)
    restore()
    return

  p2 = new U()
  p2.k = NUM
  p2.q.a = bigInt(p1.q.b)
  p2.q.b = bigInt(1)

  push(p2)

  restore()

# expo is an integer
bignum_power_number = (expo) ->
  #unsigned int *a, *b, *t

  save()

  p1 = pop()

  a = mpow(p1.q.a, Math.abs(expo))
  b = mpow(p1.q.b, Math.abs(expo))

  if (expo < 0)
    # swap a and b
    t = a
    a = b
    b = t

    a = makeSignSameAs(a,b)
    b = setSignTo(b,1)

  p1 = new U()

  p1.k = NUM

  p1.q.a = a
  p1.q.b = b

  push(p1)

  restore()

# p an array of ints
convert_bignum_to_double = (p) ->
  return p.toJSNumber()

# p is a U
convert_rational_to_double = (p) ->
  if !p.q?
    debugger
  quotientAndRemainder = p.q.a.divmod(p.q.b)
  result = quotientAndRemainder.quotient + quotientAndRemainder.remainder / p.q.b.toJSNumber()

  return result

# n an integer
new_integer = (n) ->
  theNewInteger = new U()
  theNewInteger.k = NUM
  theNewInteger.q.a = bigInt(n)
  theNewInteger.q.b = bigInt(1)
  return theNewInteger

# n an integer
push_integer = (n) ->
  if DEBUG then console.log "pushing integer " + n
  push new_integer(n)

# d a double
push_double = (d) ->
  save()
  p1 = new U()
  p1.k = DOUBLE
  p1.d = d
  push(p1)
  restore()

# a,b parts of a rational
push_rational = (a,b) ->
  ###
  save()
  p1 = new U()
  p1.k = NUM
  p1.q.a = bigInt(a)
  p1.q.b = bigInt(b)
  ## FIXME -- normalize ##
  push(p1)
  restore()
  ###

  p = new U()
  p.k = NUM
  p.q.a = bigInt(a)
  p.q.b = bigInt(b)
  push(p)

pop_integer = ->
  n = NaN

  save()

  p1 = pop()

  switch (p1.k)

    when NUM
      if (isinteger(p1) && isSmall(p1.q.a))
        n = p1.q.a.toJSNumber()

    when DOUBLE
      if DEBUG
        console.log "popping integer but double is found"
      if Math.floor(p1.d) == p1.d
        if DEBUG
          console.log "...altough it's an integer"
        n = p1.d

  restore()
  return n

# p is a U, flag is an int
print_double = (p,flag) ->
  accumulator = ""
  buf = doubleToReasonableString(p.d)
  if (flag == 1 && buf == '-')
    accumulator += print_str(buf + 1)
  else
    accumulator += print_str(buf)
  return accumulator

# s is a string
bignum_scan_integer = (s) ->
  #unsigned int *a
  #char sign

  save()
  scounter = 0

  sign_ = s[scounter]

  if (sign_ == '+' || sign_ == '-')
    scounter++

  # !!!! some mess in here, added an argument
  a = bigInt(s.substring(scounter))

  p1 = new U()

  p1.k = NUM

  p1.q.a = a
  p1.q.b = bigInt(1)

  push(p1)

  if (sign_ == '-')
    negate()

  restore()

# s a string
bignum_scan_float = (s) ->
  push_double(parseFloat(s))

# gives the capability of printing the unsigned
# value. This is handy because printing of the sign
# might be taken care of "upstream"
# e.g. when printing a base elevated to a negative exponent
# prints the inverse of the base powered to the unsigned
# exponent.
# p is a U
print_number = (p, signed) ->
  accumulator = ""

  denominatorString = ""
  buf = ""
  switch (p.k)
    when NUM
      aAsString = p.q.a.toString()
      if !signed
        if aAsString[0] == "-"
          aAsString = aAsString.substring(1)

      if (printMode == PRINTMODE_LATEX and isfraction(p))
        aAsString = "\\frac{"+aAsString+"}{"

      accumulator += aAsString

      if (isfraction(p))
        if printMode != PRINTMODE_LATEX
          accumulator += ("/")
        denominatorString = p.q.b.toString()
        if printMode == PRINTMODE_LATEX then denominatorString += "}"

        accumulator += denominatorString

    when DOUBLE
      aAsString = doubleToReasonableString(p.d)
      if !signed
        if aAsString[0] == "-"
          aAsString = aAsString.substring(1)

      accumulator += aAsString

  return accumulator

gcd_numbers = ->
  save()

  p2 = pop()
  p1 = pop()

#  if (!isinteger(p1) || !isinteger(p2))
#    stop("integer args expected for gcd")

  p3 = new U()

  p3.k = NUM

  p3.q.a = mgcd(p1.q.a, p2.q.a)
  p3.q.b = mgcd(p1.q.b, p2.q.b)

  p3.q.a = setSignTo(p3.q.a,1)

  push(p3)

  restore()

pop_double = ->
  d = 0.0
  save()
  p1 = pop()
  switch (p1.k)
    when NUM
      d = convert_rational_to_double(p1)
    when DOUBLE
      d = p1.d
    else
      d = 0.0
  restore()
  return d

bignum_float = ->
  d = 0.0
  d = convert_rational_to_double(pop())
  push_double(d)

#static unsigned int *__factorial(int)

# n is an int
bignum_factorial = (n) ->
  save()
  p1 = new U()
  p1.k = NUM
  p1.q.a = __factorial(n)
  p1.q.b = bigInt(1)
  push(p1)
  restore()

# n is an int
__factorial = (n) ->
  i = 0
  #unsigned int *a, *b, *t

  if (n == 0 || n == 1)
    a = bigInt(1)
    return a

  a = bigInt(2)

  b = bigInt(0)

  if 3 <= n
    for i in [3..n]
      b = bigInt(i)
      t = mmul(a, b)
      a = t


  return a

mask = [
  0x00000001,
  0x00000002,
  0x00000004,
  0x00000008,
  0x00000010,
  0x00000020,
  0x00000040,
  0x00000080,
  0x00000100,
  0x00000200,
  0x00000400,
  0x00000800,
  0x00001000,
  0x00002000,
  0x00004000,
  0x00008000,
  0x00010000,
  0x00020000,
  0x00040000,
  0x00080000,
  0x00100000,
  0x00200000,
  0x00400000,
  0x00800000,
  0x01000000,
  0x02000000,
  0x04000000,
  0x08000000,
  0x10000000,
  0x20000000,
  0x40000000,
  0x80000000,
]

# unsigned int *x, unsigned int k
mp_set_bit = (x, k) ->
  console.log "not implemented yet"
  debugger
  x[k / 32] |= mask[k % 32]

# unsigned int *x, unsigned int k
mp_clr_bit = (x,k) ->
  console.log "not implemented yet"
  debugger
  x[k / 32] &= ~mask[k % 32]

# unsigned int *a
mshiftright = (a) ->
  a = a.shiftRight()

