using Php;

namespace PhpNative {
    public enum RoundMode {
        HALF_UP = 1,
        HALF_DOWN = 2,
        HALF_EVEN = 3,
        HALF_ODD = 4
    }

    private bool is_even_integer (double value) {
        int64 integer = (int64) value;
        return integer % 2 == 0;
    }

    private double round_positive_scaled (double value, RoundMode mode) {
        double lower = Math.floor (value);
        double fraction = value - lower;
        double epsilon = 1e-12;

        if (fraction > 0.5 + epsilon)
            return lower + 1.0;

        if (fraction < 0.5 - epsilon)
            return lower;

        switch (mode) {
        case RoundMode.HALF_DOWN:
            return lower;
        case RoundMode.HALF_EVEN:
            return is_even_integer (lower) ? lower : lower + 1.0;
        case RoundMode.HALF_ODD:
            return is_even_integer (lower) ? lower + 1.0 : lower;
        case RoundMode.HALF_UP:
        default:
            return lower + 1.0;
        }
    }

    public double round_static (double value, int precision, RoundMode mode, string php_file, int php_line) throws Error {
        double factor = Math.pow (10.0, precision);
        double sign = value < 0.0 ? -1.0 : 1.0;
        double scaled = Math.fabs (value * factor);
        double rounded = round_positive_scaled (scaled, mode);
        return sign * rounded / factor;
    }

    public zval round_zval (zval value, zval precision, string php_file, int php_line) throws Error {
        return zval.double_number (round_static (zval_to_double (value), zval_to_int (precision), RoundMode.HALF_UP, php_file, php_line));
    }
}
