// Copyright (C) 1999-2005 Open Source Telecom Corporation.
// Copyright (C) 2006-2014 David Sugar, Tycho Softworks.
// Copyright (C) 2015-2020 Cherokees of Idaho.
//
// This file is part of GNU uCommon C++.
//
// GNU uCommon C++ is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GNU uCommon C++ is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with GNU uCommon C++.  If not, see <http://www.gnu.org/licenses/>.

#include <ucommon-config.h>
#include <ucommon/export.h>
#include <ucommon/numbers.h>
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

namespace ucommon {

Number::Number(char *buf, unsigned width)
{
    if(width > 10)
        width = 10;
    if(width < 1)
        width = 1;
    size = width;

    buffer = buf;
}

long Number::get(void) const
{
    int count = size;
    bool sign = false;
    long ret = 0;
    char *bp = buffer;

    if(*bp == '-') {
        --count;
        ++bp;
        sign = true;
    }
    else if(*bp == '+') {
        --count;
        ++bp;
    }
    while(count && *bp >='0' && *bp <='9') {
        ret = ret * 10l + (*bp - '0');
        --count;
        ++bp;
    }

    if(sign)
        ret = -ret;
    return ret;
}

void Number::set(long value)
{
    int count = size;
    char *bp = buffer;
    long max = 1;
    int exp;
    bool z = false;

    if(value < 0) {
        value = -value;
        --count;
        *(bp++) = '-';
    }

    exp = count;
    while(--exp)
        max *= 10;

    while(max) {
        if(value >= max || z) {
            --count;
            *(bp++) = '0' + ((char)(value / max));
        }
        if(value >= max) {
            z = true;
            value -= (value / max) * max;
        }
        max /= 10;
    }
    while(count-- && *bp >= '0' && *bp <='9')
        *(bp++) = ' ';
}

long Number::operator=(long value)
{
    set(value);
    return value;
}

long Number::operator=(const Number& num)
{
    set(num.get());
    return get();
}

long Number::operator+=(long value)
{
    long value1 = get() + value;
    set(value1);
    return value1;
}

long Number::operator-=(long value)
{
    long value1 = get() - value;
    set(value1);
    return value1;
}

long Number::operator--()
{
    long val = get();
    set(--val);
    return val;
}

long Number::operator++()
{
    long val = get();
    set(++val);
    return val;
}

ZNumber::ZNumber(char *buf, unsigned chars) :
Number(buf, chars)
{}

void ZNumber::set(long value)
{
    int count = size;
    char *bp = buffer;
    long max = 1;
    int exp;

    if(value < 0) {
        value = -value;
        --count;
        *(bp++) = '-';
    }

    exp = count;
    while(--exp)
        max *= 10;

    while(max) {
        --count;
        *(bp++) = '0' + (char)(value / max);
        value -= (value / max) * max;
        max /= 10;
    }
}

long ZNumber::operator=(long value)
{
    set(value);
    return value;
}

} // namespace ucommon
