
#include <limits.h>

#include <grass/gis.h>
#include <grass/raster.h>
#include "globals.h"
#include "expression.h"
#include "func_proto.h"

/**********************************************************************
round(x)

  rounds x to nearest integer.

  if input is CELL (which is an integer already)
  the input argument (argv[0]) is simply copied to the output cell.

  if the input is double, the input is rounded by adding .5 to positive
  numbers, and subtracting .5 from negatives.
**********************************************************************/

/* i_round(x) rounds x to nearest CELL value, handles negative correctly */

static int i_round(double x)
{
    int n;

    if (IS_NULL_D(&x))
	SET_NULL_C(&n);
    else if (x > INT_MAX || x < -INT_MAX) {
	SET_NULL_C(&n);
	if (!IS_NULL_D(&x))
	    overflow_occurred = 1;
    }
    else if (x >= 0.0)
	n = x + .5;
    else {
	n = -x + .5;
	n = -n;
    }

    return n;
}

/**********************************************************************/

int f_round(int argc, const int *argt, void **args)
{
    int *res = args[0];
    int i;

    if (argc < 1)
	return E_ARG_LO;
    if (argc > 1)
	return E_ARG_HI;

    if (argt[0] != CELL_TYPE)
	return E_RES_TYPE;

    switch (argt[1]) {
    case CELL_TYPE:
	{
	    CELL *arg1 = args[1];

	    for (i = 0; i < columns; i++)
		if (IS_NULL_C(&arg1[i]))
		    SET_NULL_C(&res[i]);
		else
		    res[i] = arg1[i];
	    return 0;
	}
    case FCELL_TYPE:
	{
	    FCELL *arg1 = args[1];

	    for (i = 0; i < columns; i++)
		if (IS_NULL_F(&arg1[i]))
		    SET_NULL_C(&res[i]);
		else
		    res[i] = i_round(arg1[i]);
	    return 0;
	}
    case DCELL_TYPE:
	{
	    DCELL *arg1 = args[1];

	    for (i = 0; i < columns; i++)
		if (IS_NULL_D(&arg1[i]))
		    SET_NULL_C(&res[i]);
		else
		    res[i] = i_round(arg1[i]);
	    return 0;
	}
    default:
	return E_INV_TYPE;
    }
}

int c_round(int argc, int *argt)
{
    if (argc < 1)
	return E_ARG_LO;
    if (argc > 1)
	return E_ARG_HI;

    argt[0] = CELL_TYPE;
    /*      argt[1] = argt[1];      */

    return 0;
}
