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

    [CCode (cname = "valaphp_embed_syntax_check_file", cheader_filename = "php_embed_runtime.h")]
    private extern static bool syntax_check_file (string path, out string? error_message);

    [CCode (cname = "valaphp_embed_call_zval_array_to_zval", cheader_filename = "call/zval_array_to_zval.h")]
    private extern static Php.zval? call_zval_array_to_zval (string function_name, Php.zval args, out string? error_message);

    [CCode (cname = "valaphp_embed_call_zval_array_output_to_string", cheader_filename = "call/zval_array_to_zval.h")]
    private extern static string? call_zval_array_output_to_string (string function_name, Php.zval args, out string? error_message);

    public bool syntax_check_file_static (string path, out string? error_message) {
        return syntax_check_file (path, out error_message);
    }

    internal Php.zval string_zval (string value) {
        return Php.zval.string_value (value);
    }

    internal Php.zval int_zval (int64 value) {
        return Php.zval.integer (value);
    }

    internal Php.zval double_zval (double value) {
        return Php.zval.double_number (value);
    }

    internal Php.zval bool_zval (bool value) {
        return Php.zval.boolean (value);
    }

    private Php.zval php_call_args (Php.zval[] values) {
        var args = Php.zval.array ();
        foreach (Php.zval value in values) {
            args.append (value);
        }
        return args;
    }

    private Php.zval php_call_zval_array (string function_name, string php_file, int php_line, Php.zval[] values) throws Error {
        string? error_message = null;
        Php.zval? result = call_zval_array_to_zval (function_name, php_call_args (values), out error_message);
        if (result == null) {
            StacktraceError.throw (Php.with_php_source (error_message ?? "PHP %s failed".printf (function_name), php_file, php_line));
        }
        return result;
    }

    public Php.zval call_zval (string function_name, Php.zval args, string php_file, int php_line) throws Error {
        string? error_message = null;
        Php.zval? result = call_zval_array_to_zval (function_name, args, out error_message);
        if (result == null) {
            StacktraceError.throw (Php.with_php_source (error_message ?? "PHP %s failed".printf (function_name), php_file, php_line));
        }
        return result;
    }

    public Php.zval call_zval_params (string function_name, string php_file, int php_line, params Php.zval[] values) throws Error {
        return php_call_zval_array (function_name, php_file, php_line, values);
    }

    internal Php.zval call_zval_values (string function_name, string php_file, int php_line, Php.zval[] values) throws Error {
        return php_call_zval_array (function_name, php_file, php_line, values);
    }

    internal Php.zval php_call_zval (string function_name, string php_file, int php_line, params Php.zval[] values) throws Error {
        return php_call_zval_array (function_name, php_file, php_line, values);
    }

    internal string php_call_string (string function_name, string php_file, int php_line, params Php.zval[] values) throws Error {
        return Php.zval_to_string (php_call_zval_array (function_name, php_file, php_line, values));
    }

    internal int php_call_int (string function_name, string php_file, int php_line, params Php.zval[] values) throws Error {
        return (int) Php.zval_to_int (php_call_zval_array (function_name, php_file, php_line, values));
    }

    internal double php_call_double (string function_name, string php_file, int php_line, params Php.zval[] values) throws Error {
        return Php.zval_to_double (php_call_zval_array (function_name, php_file, php_line, values));
    }

    internal bool php_call_bool (string function_name, string php_file, int php_line, params Php.zval[] values) throws Error {
        return Php.truthy (php_call_zval_array (function_name, php_file, php_line, values));
    }

    internal string php_call_output_string (string function_name, string php_file, int php_line, params Php.zval[] values) throws Error {
        string? error_message = null;
        string? result = call_zval_array_output_to_string (function_name, php_call_args (values), out error_message);
        if (result == null) {
            StacktraceError.throw (Php.with_php_source (error_message ?? "PHP %s failed".printf (function_name), php_file, php_line));
        }
        return result;
    }
}
