/**
 * \file      decInfinite.h
 * \author    Lifepillar
 * \copyright Copyright (c) 2019 Lifepillar.
 *            This program is free software; you can redistribute it and/or
 *            modify it under the terms of the Simplified BSD License (also
 *            known as the "2-Clause License" or "FreeBSD License".)
 * \copyright This program 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.
 *
 * \brief     Decimal Infinite public interface
 */

#include "autoconfig.h"

#if !defined(DECINFINITE)

#define DECINFINITE
#define DECINF_NAME "decInfinite"                 /**< Short name.        */
#define DECINF_FULLNAME "Decimal Infinite Module" /**< Full name.         */
#define DECINF_AUTHOR "Lifepillar"                /**< Who to bl… praise. */

#if HAVE_LITTLE_ENDIAN
#define DECLITEND 1         /**< 1=little-endian, 0=big-endian. */
#else
#define DECLITEND 0
#endif

#ifndef DECNUMDIGITS
/**
 * \brief Maximum number of digits that a decNumber can have.
 *
 * \note  #DECNUMDIGITS **must** be a multiple of three, because before
 *        encoding a decNumber its digits may be shifted towards the most
 *        significant unit (and, correspondingly, trailing zeroes may be added)
 *        so that each #Unit contains three digits.
 *
 * \note According to decNumber's manual, the theoretical upper limit for this
 *       constant is 999,999,999. Given the way #DECINF_MAXSIZE is defined,
 *       however, the maximum allowed value is "only" 99,999,999.
 */
#define DECNUMDIGITS 39
#endif

#if DECNUMDIGITS < 3
#error DECNUMDIGITS must be at least 3
#endif

#if DECNUMDIGITS % 3 != 0
#error DECNUMDIGITS must be a multiple of 3
#endif


#ifndef DECINF_EXPSIZE
/**
 * \brief Maximum size of the absolute value of an adjusted exponent, in bits.
 *
 * This must be at least 5 and no greater than 30. The lower bound is
 * determined by the fact that this implementation must be able to pack at
 * least those exponents that fit in one byte (i.e., 5 bits, once the bits for
 * the sign and padding are factored out). The upper limit depends on the fact
 * that the adjusted exponent of a decNumber must be in
 * [-999,999,999,999,999,999].
 */
#define DECINF_EXPSIZE 30
#endif

#if DECINF_EXPSIZE < 5
#error DECINF_EXPSIZE must be at least 5
#endif


/**
 * \brief Maximum size of a Decimal Infinite encoded number, in bytes.
 *
 * The encoding consists of:
 *
 * - `2` bits for the sign;
 * - `1` bit of padding (unused);
 * - At most `2 * #DECINF_EXPSIZE - 1` bits for the encoded exponent (sign and
 *   value);
 * - At most `10 * #DECNUMDIGITS / 3` bits for the mantissa.
 *
 * The number is rounded up to the nearest integer.
 */
#define DECINF_MAXSIZE (1 + (2 + 1 + (2 * DECINF_EXPSIZE - 1) + (10 * DECNUMDIGITS / 3) - 1) / 8)

#include "decNumber/decNumber.h"
#include "decNumber/decNumberLocal.h"

#if DECDPUN != 3
#error decInfinite assumes DECDPUN == 3
#endif

/**
 * \brief Encodes a decNumber into a stream of bytes.
 *
 * \param len The length of the output stream of bytes
 * \param result The output stream of bytes
 * \param decnum The input number
 *
 * \return The size of the result, in bytes
 *
 * \note This function does not check for buffer overflows; rather, it assumes
 *       that the output buffer is large enough to hold the encoded number.
 *       The maximum space an encoded number can use is #DECINF_MAXSIZE
 *       bytes. This function also assumes that the exponent of the input
 *       number is within the valid range (adjusted exponent in
 *       [-999,999,999,999,999,999]).
 *
 * \note The input number is **modified** by this function. If you need to use
 *       the number after invoking this function, **make a copy first.**
 */
size_t decInfiniteFromNumber(size_t len, uint8_t result[len], decNumber* decnum);

/**
 * \brief Decodes a Decimal Infinite byte stream into a \c decNumber.
 *
 * \param len The number of bytes of the encoded number
 * \param bytes The encoded number
 * \param decnum The output decNumber
 *
 * \return \a decnum unless a decoding error occurs, in which case the returned
 *         value is `0`.
 */
decNumber* decInfiniteToNumber(size_t len, uint8_t const bytes[len], decNumber* decnum);

/**
 * \brief Determines whether an encoded number is special.
 *
 * A special number is any of `-Inf`, `+Inf`, or `NaN`.
 *
 * \param len The number of bytes of the encoded number
 * \param bytes The encoded number
 *
 * \return `1` if the number is recognized as a special number; `0` otherwise.
 */
int decInfiniteIsSpecial(size_t len, uint8_t const bytes[len]);

/**
 * \brief Returns the sign of an encoded decimal.
 *
 * The sign is returned also for special numbers.
 *
 * \param bytes A non-null pointer to the encoded number
 *
 * \return `1` if the sign is positive, `-1` if the sign is negative.
 */
int decInfiniteSign(uint8_t const* bytes);

/**
 * \brief Returns the exponent of a decimal.
 *
 * \param len The number of bytes of the encoded decimal number
 * \param bytes The encoded decimal number
 *
 * \return The adjusted exponent of the decimal, i.e., the exponent of the
 *         number when expressed in scientific notation. If the decimal is
 *         a special number (`-NaN`, `-Inf`, `+Inf`, `+NaN`), the returned
 *         value is `-2^#DECINF_EXPSIZE` or `+2^#DECINF_EXPSIZE` (i.e., an
 *         out-of-range exponent).
 *
 */
int32_t decInfiniteExponent(size_t len, uint8_t const bytes[len]);

/**
 * \brief Returns the significand of a decimal as a string.
 *
 * \param len The number of bytes of the encoded number
 * \param bytes The encoded number
 * \param significand The output buffer: this is assumed to have enough space
 *        to hold the coefficient, i.e., at most `#DECNUMDIGITS + 2` bytes
 *        (#DECNUMDIGITS digits, a dot, the string terminator).
 *
 * \return \a significand, or `0` if a decoding error occurs.
 *
 * TODO: return the mantissa as a decInfinite integer instead?
 */
char* decInfiniteCoefficient(size_t len, uint8_t const bytes[len], char* significand);

/**
 * \brief Returns an encoded number as a hexadecimal string.
 *
 * This function is meant mostly for debugging (or for fun).
 *
 * \param len The number of bytes of the encoded number
 * \param bytes The encoded number
 * \param hexes A non-null pointer to a buffer for the output string. This
 *              function asssumes that the buffer has enough space, which is at
 *              most `3 * #DECINF_MAXSIZE` bytes.
 *
 * \return \a hexes unless \a len exceeds #DECINF_MAXSIZE, in which case the
 *         returned value is `0`.
 */
char* decInfiniteToBytes(size_t len, uint8_t const bytes[len], char* hexes);

/**
 * \brief Returns an encoded number as a formatted string of bits.
 *
 * This function is meant mostly for debugging (or for fun).
 *
 * \param len The number of bytes of the encoded number
 * \param bytes The encoded number
 * \param bitstring A non-null pointer to a buffer for the output string. This
 *        must have enough space for the output string, which is at most
 *        (approximately) `#DECINF_MAXSIZE * 9 + 1` bytes.
 *
 * \return \a bitstring unless \a len exceeds #DECINF_MAXSIZE, in which case
 *         the returned value is `0`.
 */
char* decInfiniteToBits(size_t len, uint8_t const bytes[len], char* bitstring);

#endif

