namespace PhpefRuntimeNativeStandard {

    [CCode (cname = "fopen", cheader_filename = "stdio.h")]
    private extern static void* native_standard_fopen(string path, string mode);

    [CCode (cname = "tmpfile", cheader_filename = "stdio.h")]
    private extern static void* native_standard_tmpfile();

    [CCode (cname = "fwrite", cheader_filename = "stdio.h")]
    private extern static size_t native_standard_fwrite([CCode (array_length = false)] uint8[] data, size_t size, size_t nmemb, void* stream);

    [CCode (cname = "fflush", cheader_filename = "stdio.h")]
    private extern static int native_standard_fflush(void* stream);

    [CCode (cname = "fclose", cheader_filename = "stdio.h")]
    private extern static int native_standard_fclose(void* stream);

    /** Native Zval-compatible wrapper for PHP echo. */
    public void phpfunc_echo(PhpefRuntimeCore.Zval value) {
        uint8[] bytes = value.to_php_bytes();
        foreach (var b in bytes) {
            stdout.putc((char) b);
        }
        stdout.flush();
    }

    /** Native typed fast path for PHP microtime(). */
    public string phpfunc_microtime_typed_string() {
        return microtime_string_value();
    }

    /** Native typed fast path for PHP microtime(false). */
    public string phpfunc_microtime_typed_string_arg1_bool_false() {
        return microtime_string_value();
    }

    /** Native typed fast path for PHP microtime(true). */
    public double phpfunc_microtime_typed_double_arg1_bool_true() {
        return microtime_current_seconds();
    }

    /** Native typed fast path for PHP echo(string). */
    public void phpfunc_echo_typed_void_arg1_string(string value) {
        stdout.printf("%s", value);
        stdout.flush();
    }

    /** Native implementation of PHP fopen() for ordinary files and php://temp. */
    public PhpefRuntimeCore.Zval phpfunc_fopen(PhpefRuntimeCore.Zval filename, PhpefRuntimeCore.Zval mode) {
        string path = filename.to_php_string();
        string open_mode = mode.to_php_string();
        void* stream = null;
        if (path == "php://temp") {
            stream = native_standard_tmpfile();
        } else {
            stream = native_standard_fopen(path, open_mode);
        }
        if (stream == null) {
            return PhpefRuntimeCore.Zval.from_bool(false);
        }
        return PhpefRuntimeCore.Zval.from_resource_pointer(stream);
    }

    /** Native implementation of PHP fwrite(). */
    public PhpefRuntimeCore.Zval phpfunc_fwrite(PhpefRuntimeCore.Zval handle, PhpefRuntimeCore.Zval data, PhpefRuntimeCore.Zval? length = null) {
        void* pointer = handle.as_resource_pointer();
        if (pointer == null) {
            return PhpefRuntimeCore.Zval.from_bool(false);
        }
        uint8[] bytes = data.to_php_bytes();
        int64 max_length = length == null ? bytes.length : length.as_int();
        if (max_length < 0) {
            return PhpefRuntimeCore.Zval.from_bool(false);
        }
        if (max_length < bytes.length) {
            uint8[] limited = {};
            for (int i = 0; i < max_length; i++) {
                limited += bytes[i];
            }
            bytes = limited;
        }
        size_t written = native_standard_fwrite(bytes, 1, bytes.length, pointer);
        return PhpefRuntimeCore.Zval.from_int((int64) written);
    }

    /** Native implementation of PHP fflush(). */
    public PhpefRuntimeCore.Zval phpfunc_fflush(PhpefRuntimeCore.Zval handle) {
        void* pointer = handle.as_resource_pointer();
        if (pointer == null) {
            return PhpefRuntimeCore.Zval.from_bool(false);
        }
        return PhpefRuntimeCore.Zval.from_bool(native_standard_fflush(pointer) == 0);
    }

    /** Native implementation of PHP is_resource(). */
    public PhpefRuntimeCore.Zval phpfunc_is_resource(PhpefRuntimeCore.Zval value) {
        return PhpefRuntimeCore.Zval.from_bool(value.kind == PhpefRuntimeCore.ValueKind.RESOURCE && value.as_resource_pointer() != null);
    }

    /** Native implementation of PHP fclose(). */
    public PhpefRuntimeCore.Zval phpfunc_fclose(PhpefRuntimeCore.Zval handle) {
        void* pointer = handle.as_resource_pointer();
        if (pointer == null) {
            return PhpefRuntimeCore.Zval.from_bool(false);
        }
        bool ok = native_standard_fclose(pointer) == 0;
        handle.replace_with(PhpefRuntimeCore.Zval.from_null());
        return PhpefRuntimeCore.Zval.from_bool(ok);
    }

    /** Native implementation of PHP standard microtime(). */
    public PhpefRuntimeCore.Zval phpfunc_microtime(PhpefRuntimeCore.Zval? as_float = null) {
        bool wants_float = as_float != null && as_float.to_bool();
        if (wants_float) {
            return PhpefRuntimeCore.Zval.from_float(microtime_current_seconds());
        }

        return PhpefRuntimeCore.Zval.from_string(microtime_string_value());
    }

    /** Native implementation of PHP constant() for native-known constants. */
    public PhpefRuntimeCore.Zval phpfunc_constant(PhpefRuntimeCore.Zval name) {
        return native_standard_constant_by_name(name.to_php_string());
    }

    /** Native typed fast path for PHP constant(string): mixed/Zval. */
    public PhpefRuntimeCore.Zval phpfunc_constant_typed_zval_arg1_string(string name) {
        return native_standard_constant_by_name(name);
    }

    /** Native implementation of PHP floatval(). */
    public PhpefRuntimeCore.Zval phpfunc_floatval(PhpefRuntimeCore.Zval value) {
        return value.to_float_zval();
    }

    /** Native implementation of PHP floor(). */
    public PhpefRuntimeCore.Zval phpfunc_floor(PhpefRuntimeCore.Zval num) {
        return PhpefRuntimeCore.Zval.from_float((double) native_floor_to_int64(native_zval_to_double(num)));
    }

    /** Native implementation of PHP round() using the default half-up mode. */
    public PhpefRuntimeCore.Zval phpfunc_round(PhpefRuntimeCore.Zval num, PhpefRuntimeCore.Zval? precision = null, PhpefRuntimeCore.Zval? mode = null) {
        int64 precision_value = precision == null ? 0 : native_zval_to_int64(precision);
        return PhpefRuntimeCore.Zval.from_float(native_round_half_up(native_zval_to_double(num), precision_value));
    }

    /** Native implementation of PHP number_format(). */
    public PhpefRuntimeCore.Zval phpfunc_number_format(PhpefRuntimeCore.Zval num, PhpefRuntimeCore.Zval? decimals = null, PhpefRuntimeCore.Zval? decimal_separator = null, PhpefRuntimeCore.Zval? thousands_separator = null) {
        int64 decimals_value = decimals == null ? 0 : native_zval_to_int64(decimals);
        if (decimals_value < 0) {
            decimals_value = 0;
        }

        string decimal_separator_value = decimal_separator == null ? "." : decimal_separator.to_php_string();
        string thousands_separator_value = thousands_separator == null ? "," : thousands_separator.to_php_string();

        double factor_double = native_pow10(decimals_value);
        int64 factor = (int64) factor_double;
        double value = native_zval_to_double(num);
        bool negative = value < 0.0;
        double abs_value = negative ? -value : value;
        int64 scaled = native_floor_to_int64((abs_value * factor_double) + 0.5);
        int64 integer_part = factor == 0 ? scaled : scaled / factor;
        int64 fraction_part = factor == 0 ? 0 : scaled % factor;

        string text = native_group_integer_string(integer_part.to_string(), thousands_separator_value);
        if (negative && (integer_part != 0 || fraction_part != 0)) {
            text = "-" + text;
        }
        if (decimals_value > 0) {
            text += decimal_separator_value + native_pad_fraction(fraction_part, decimals_value);
        }
        return PhpefRuntimeCore.Zval.from_string(text);
    }

}
