/*
 * The contents of this file are subject to the Netscape Public
 * License Version 1.1 (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.mozilla.org/NPL/

 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.

 * The Original Code is Rhino code, released
 * May 6, 1999.

 * The Initial Developer of the Original Code is Netscape
 * Communications Corporation.  Portions created by Netscape are
 * Copyright (C) 1997-1999 Netscape Communications Corporation. All
 * Rights Reserved.

 * Contributor(s): 

 * Alternatively, the contents of this file may be used under the
 * terms of the GNU Public License (the "GPL"), in which case the
 * provisions of the GPL are applicable instead of those above.
 * If you wish to allow use of your version of this file only
 * under the terms of the GPL and not to allow others to use your
 * version of this file under the NPL, indicate your decision by
 * deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL.  If you do not delete
 * the provisions above, a recipient may use your version of this
 * file under either the NPL or the GPL.
 */
#ifdef DTOA

#ifndef _JS_BIG_INTEGER_H_
#define _JS_BIG_INTEGER_H_

#include "js-context.h"
#include "js-vector.h"

/* Classes */
class JSBigInteger {
    public:
        typedef uint32_t        Digit;

    protected:
        typedef uint64_t        DigitDBL;       // double of digit
        typedef int32_t         SDigit;
        typedef int64_t         SDigitDBL;      // signed double of digit

        typedef JSVector<Digit, JSContext::ZoneAllocator>       _Magnitude;
        class Magnitude: public _Magnitude {
            public:
                Magnitude(JSContext *cx)
                        : _Magnitude(&cx->allocator, 0) {
                }
                Digit *getElementData() {
                    return elementData;
                }
        } ;

    protected:
        static  const   int     MIN_RADIX = 2;
        static  const   int     MAX_RADIX = 36;
        static  const   int     BITS_PER_DIGIT = sizeof (Digit) * 8;
        static  const   Digit   DIGIT_MASK
                                        = ((DigitDBL) 1 << BITS_PER_DIGIT) - 1;

        JSContext       *cx;            // used in copy constructor
        int             signum;         // if 0 positive, if -1 negative
        Magnitude       magnitude;

    protected:
        static  int     magnitudeCmp(Magnitude *arg1, Magnitude *arg2);
        static  jsChar_t
                        forDigit(int digit, int radix);
        static  jsString_t
                        int64ToString(JSContext *cx, int64_t i, int radix);
        static  void    divideAndRemainder(JSContext *cx, JSBigInteger &x,
                                JSBigInteger &y, JSBigInteger &div,
                                JSBigInteger &rem);
        static  JSBigInteger
                        multiply(JSContext *cx, JSBigInteger &x,
                                JSBigInteger &y);
        static  JSBigInteger
                        subtract(JSContext *cx, JSBigInteger &x,
                                JSBigInteger &y);

        void    makePositive(Digit *val, int valLength);
        void    stripLeadingZeroBytes(Digit *val, int valLength);
        Digit   signDigit();
        Digit   getDigit(int n);
        void    normalize();

    public:
        static  JSBigInteger
                        valueOf(JSContext *cx, int64_t val);

        JSBigInteger(JSContext *cx, Digit *val, int valLength);
        JSBigInteger(const JSBigInteger &src);
        JSBigInteger(JSContext *cx);

        /* Arithmetic operattions */
        void    divideAndRemainder(JSContext *cx, JSBigInteger **result,
                        JSBigInteger &val);
        int     compareTo(JSBigInteger &val);
        JSBigInteger
                shiftLeft(JSContext *cx, int n);
        JSBigInteger
                shiftRight(JSContext *cx, int n);
        JSBigInteger
                multiply(JSContext *cx, JSBigInteger &val);
        JSBigInteger
                pow(JSContext *cx, int exponent);
        JSBigInteger
                subtract(JSContext *cx, JSBigInteger &val);
        JSBigInteger
                abs(JSContext *cx);
        JSBigInteger
                negate(JSContext *cx);
        jsBool_t
                equals(JSBigInteger &val);

        jsString_t
                toString(JSContext *cx, int radix);
        Digit *
                toDigitArray(JSContext *cx, int *length);
        int64_t int64Value();
        int     getSignum();

        /* c++ operator overload */
        JSBigInteger &
                operator=(const JSBigInteger &src);
} ;

/* Inlines */
inline int
JSBigInteger::getSignum()
{
    return signum;
}

#endif /* _JS_BIG_INTEGER_H_ */

#endif /* DTOA */

