/*
 * ReactOS Calc (Utility functions for IEEE-754 engine)
 *
 * Copyright 2007-2017, Carlo Bramini
 *
 * This program 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 2 of the License, or (at your option) any later version.
 *
 * This library 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 this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "calc.h"

void prepare_rpn_result_2(calc_number_t *rpn, TCHAR *buffer, int size, int base)
{
    calc_number_t tmp;
    int    width;

    switch (base) {
    case IDC_RADIO_HEX:
        StringCchPrintf(buffer, size, _T("%I64X"), rpn->i);
        break;
    case IDC_RADIO_DEC:
/*
 * Modified from 17 to 16 for fixing this bug:
 * 14+14+6.3+6.3= 40.5999999 instead of 40.6
 * So, it's probably better to leave the least
 * significant digit out of the display.
 */
#define MAX_LD_WIDTH    16
        /* calculate the width of integer number */
        width = (rpn->f==0) ? 1 : (int)log10(fabs(rpn->f))+1;
        if (calc.sci_out == TRUE || width > MAX_LD_WIDTH || width < -MAX_LD_WIDTH)
            StringCchPrintf(buffer, size, _T("%#.*e"), MAX_LD_WIDTH-1, rpn->f);
        else {
            TCHAR *ptr, *dst;

            StringCchPrintfEx(buffer, size, &ptr, NULL, 0, _T("%#*.*f"), width, ((MAX_LD_WIDTH-width-1)>=0) ? MAX_LD_WIDTH-width-1 : 0, rpn->f);
            /* format string ensures there is a '.': */
            dst = _tcschr(buffer, _T('.'));
            while (--ptr > dst)
                if (*ptr != _T('0'))
                    break;

            /* put the string terminator for removing the final '0' (if any) */
            ptr[1] = _T('\0');
            /* check if the number finishes with '.' */
            if (ptr == dst)
                /* remove the dot (it will be re-added later) */
                ptr[0] = _T('\0');
        }
#undef MAX_LD_WIDTH
        break;
    case IDC_RADIO_OCT:
        StringCchPrintf(buffer, size, _T("%I64o"), rpn->i);
        break;
    case IDC_RADIO_BIN:
        if (rpn->i == 0) {
            buffer[0] = _T('0');
            buffer[1] = _T('\0');
            break;
        }
        tmp = *rpn;
        buffer[0] = _T('\0');
        while (tmp.u) {
            memmove(buffer+1, buffer, (size-1)*sizeof(TCHAR));
            if (tmp.u & 1)
                buffer[0] = _T('1');
            else
                buffer[0] = _T('0');
            tmp.u >>= 1;
        }
        break;
    }
}

void convert_text2number_2(calc_number_t *a)
{
    TCHAR *ptr;

    switch (calc.base) {
    case IDC_RADIO_HEX:
        _stscanf(calc.buffer, _T("%I64X"), &(a->i));
        break;
    case IDC_RADIO_DEC:
        _stscanf(calc.buffer, _T("%lf"), &(a->f));
        break;
    case IDC_RADIO_OCT:
        _stscanf(calc.buffer, _T("%I64o"), &(a->i));
        break;
    case IDC_RADIO_BIN:
        ptr = calc.buffer;
        a->i = 0;
        while (*ptr != _T('\0')) {
            a->i <<= 1;
            if (*ptr++ == _T('1'))
                a->i |= 1;
        }
        break;
    }
}

void convert_real_integer(unsigned int base)
{
    switch (base) {
    case IDC_RADIO_DEC:
        calc.code.f = (double)calc.code.i;
        break;
    case IDC_RADIO_OCT:
    case IDC_RADIO_BIN:
    case IDC_RADIO_HEX:
        if (calc.base == IDC_RADIO_DEC) {
            calc.code.i = (__int64)calc.code.f;
            apply_int_mask(&calc.code);
        }
        break;
    }
}
