#include "postgres.h"
#include "utils/numeric.h"

PG_MODULE_MAGIC;

PG_FUNCTION_INFO_V1(display_numeric);
Datum display_numeric(PG_FUNCTION_ARGS)
{
    Numeric num = PG_GETARG_NUMERIC(0);
    NumericVar arg;

    init_var(&arg);
    set_var_from_num(num, &arg);

    ereport(NOTICE, errmsg("weight=%d", arg.weight));
    ereport(NOTICE, errmsg("dscale=%d", arg.dscale));

    switch(arg.sign)
    {
    case NUMERIC_POS:
        ereport(NOTICE, errmsg("Pos"));
        break;
    case NUMERIC_NEG:
        ereport(NOTICE, errmsg("Neg"));
        break;
    case NUMERIC_NAN:
        ereport(NOTICE, errmsg("NaN"));
        break;
    case NUMERIC_PINF:
        ereport(NOTICE, errmsg("+Inf"));
        break;
    case NUMERIC_NINF:
        ereport(NOTICE, errmsg("-Inf"));
        break;
    default:
        ereport(NOTICE, errmsg("SIGN=0x%x", arg.sign));
        break;
    }

    for (int i = 0; i < arg.ndigits; i++)
        ereport(NOTICE, errmsg(" %04d", arg.digits[i]));

    free_var(&arg);

    PG_RETURN_VOID();
}

PG_FUNCTION_INFO_V1(negate_numeric);
Datum negate_numeric(PG_FUNCTION_ARGS)
{
    Numeric num = PG_GETARG_NUMERIC(0);
    NumericVar arg;

    init_var(&arg);
    set_var_from_num(num, &arg);

    NumericVar result;
    init_var(&result);
    alloc_var(&result, arg.ndigits);

    switch(arg.sign)
    {
    case NUMERIC_POS:
        result.sign = NUMERIC_NEG;
        break;
    case NUMERIC_NEG:
        result.sign = NUMERIC_POS;
        break;
    case NUMERIC_NAN:
        result.sign = NUMERIC_NAN;
        break;
    case NUMERIC_PINF:
        result.sign = NUMERIC_NINF;
        break;
    case NUMERIC_NINF:
        result.sign = NUMERIC_PINF;
        break;
    default:
        ereport(ERROR, errmsg("Unknown sign"));
        break;
    }

    if(result.sign == NUMERIC_POS || result.sign == NUMERIC_NEG)
    {
        result.weight = arg.weight;
        result.dscale = arg.dscale;
    
        for (int i = 0; i < arg.ndigits; i++)
            result.digits[i] = arg.digits[i];
    }

    free_var(&arg);
    PG_RETURN_NUMERIC(make_result(&result));
}
