/*
 * readcon-core C API.
 *
 * Memory ownership
 *   - Opaque handles (RKRConFrame, RKRConFrameWriter, RKRConFrameBuilder,
 *     CConFrameIterator) are caller-owned. Free each with its dedicated
 *     destructor: free_rkr_frame, free_rkr_frame_writer,
 *     free_rkr_frame_builder, free_con_frame_iterator.
 *   - rkr_read_all_frames returns a heap-allocated array of RKRConFrame*
 *     handles together with the frame count via the *num_frames out-param.
 *     The array's capacity equals the count (shrunk to fit). Free with
 *     free_rkr_frame_array(frames, *num_frames). Each individual frame is
 *     released by free_rkr_frame_array; do NOT also call free_rkr_frame.
 *   - char* values returned by rkr_frame_metadata_json,
 *     rkr_frame_potential_type, and rkr_frame_get_header_line_cpp are heap
 *     allocated; free them with rkr_free_string. rkr_free_string is safe
 *     to call with NULL (no-op).
 *   - const char* returned by rkr_library_version is process-static; do
 *     NOT free it.
 *   - rkr_frame_to_c_frame returns a CFrame whose `atoms` array is owned
 *     by the caller; release with free_c_frame.
 *
 * Sentinel values for absent metadata
 *   - Floating-point getters (rkr_frame_energy, rkr_frame_time,
 *     rkr_frame_timestep, etc.) return NaN when the metadata key is
 *     absent. Test with isnan() from <math.h>.
 *   - Unsigned-integer getters (rkr_frame_frame_index, rkr_frame_neb_bead,
 *     rkr_frame_neb_band) return UINT64_MAX when absent.
 *   - String getters return NULL when absent.
 *
 * Thread safety
 *   - Opaque handles are NOT Sync. Do not share a single
 *     RKRConFrame/RKRConFrameWriter/RKRConFrameBuilder across threads
 *     without external synchronization. Distinct handles are independent.
 *   - rkr_read_all_frames internally uses sequential parsing; the
 *     `parallel` Cargo feature is exposed only through the Rust API and
 *     is not surfaced via this C header.
 */


#ifndef READCON_H
#define READCON_H

#pragma once

/* Generated with cbindgen:0.29.2 */

/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */

#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

#ifdef __cplusplus
namespace readcon {
#endif  // __cplusplus

/**
 * CON/convel format spec version implemented by this build.
 *
 * - Version 1: column 5 present but semantics undefined. Readers MAY
 *   ignore it. No JSON metadata line.
 * - Version 2: column 5 is the original atom index before type-based
 *   grouping. Readers MUST parse and preserve it. Writers MUST write
 *   the stored value. Line 2 of the header carries a JSON object
 *   with at least `{"con_spec_version": 2}`.
 *
 * See `docs/orgmode/spec.org` for the full specification.
 */
#define CON_SPEC_VERSION 2

/**
 * CON/convel format spec version. Use `#if RKR_CON_SPEC_VERSION >= 2` in C/C++
 * to gate code that depends on atom_index semantics.
 *
 * Tracks `crate::CON_SPEC_VERSION` (which the Rust API exposes as
 * `CON_SPEC_VERSION`). Both macros are emitted into the C header for
 * the convenience of either naming convention; they always carry the
 * same value.
 */
#define RKR_CON_SPEC_VERSION 2

/**
 * Error codes for RKR functions.
 */
typedef enum RKRStatus {
    /**
     * Function completed successfully.
     */
    RKR_STATUS_SUCCESS = 0,
    /**
     * A null pointer was passed for a required argument.
     */
    RKR_STATUS_NULL_POINTER = -1,
    /**
     * An input string was not valid UTF-8.
     */
    RKR_STATUS_INVALID_UTF8 = -2,
    /**
     * JSON parsing or serialization failed.
     */
    RKR_STATUS_INVALID_JSON = -3,
    /**
     * File I/O error.
     */
    RKR_STATUS_IO_ERROR = -4,
    /**
     * Index out of bounds.
     */
    RKR_STATUS_INDEX_OUT_OF_BOUNDS = -5,
    /**
     * The destination buffer cannot hold a null-terminated string.
     */
    RKR_STATUS_BUFFER_TOO_SMALL = -6,
    /**
     * An internal logic error or unhandled state.
     */
    RKR_STATUS_INTERNAL_ERROR = -7,
} RKRStatus;

/**
 * An iterator that lazily parses simulation frames from a `.con` or `.convel`
 * file's contents.
 *
 * This struct wraps an iterator over the lines of a string and, upon each iteration,
 * attempts to parse a complete `ConFrame`. Velocity sections are detected
 * automatically: if a blank line follows the coordinate blocks, the velocity
 * data is parsed into the atoms.
 *
 * The iterator yields items of type `Result<ConFrame, ParseError>`, allowing for
 * robust error handling for each frame.
 */
typedef struct ConFrameIterator ConFrameIterator;

typedef struct String String;

/**
 * An opaque handle to a full, lossless Rust `ConFrame` object.
 * The C/C++ side needs to treat this as a void pointer
 */
typedef struct RKRConFrame {
    uint8_t _private[0];
} RKRConFrame;

typedef struct CConFrameIterator {
    struct ConFrameIterator *iterator;
    struct String *file_contents;
} CConFrameIterator;

/**
 * Transparent atom record extracted via [`rkr_frame_to_c_frame`].
 *
 * `is_fixed` is the OR of `fixed_x`, `fixed_y`, `fixed_z`; it is kept
 * for source compatibility with pre-spec-v2 callers that did not have
 * per-axis flags. New code should use the per-axis fields.
 *
 * `vx`/`vy`/`vz` and `fx`/`fy`/`fz` carry meaningful values only when
 * `has_velocity` or `has_forces` is true respectively; the values are
 * zeroed otherwise.
 */
typedef struct CAtom {
    uint64_t atomic_number;
    double x;
    double y;
    double z;
    uint64_t atom_id;
    double mass;
    /**
     * True when any of `fixed_x`, `fixed_y`, `fixed_z` is true.
     * Kept for source compatibility; prefer the per-axis fields.
     */
    bool is_fixed;
    bool fixed_x;
    bool fixed_y;
    bool fixed_z;
    double vx;
    double vy;
    double vz;
    bool has_velocity;
    double fx;
    double fy;
    double fz;
    bool has_forces;
} CAtom;

/**
 * A transparent, "lossy" C-struct containing only the core atomic data.
 * This can be extracted from an `RKRConFrame` handle for direct data access.
 * The caller is responsible for freeing the `atoms` array using `free_c_frame`.
 */
typedef struct CFrame {
    struct CAtom *atoms;
    uintptr_t num_atoms;
    double cell[3];
    double angles[3];
    bool has_velocities;
    bool has_forces;
} CFrame;

/**
 * An opaque handle to a Rust `ConFrameWriter` object.
 * The C/C++ side needs to treat this as a void pointer
 */
typedef struct RKRConFrameWriter {
    uint8_t _private[0];
} RKRConFrameWriter;

/**
 * An opaque handle to a Rust `ConFrameBuilder` object.
 */
typedef struct RKRConFrameBuilder {
    uint8_t _private[0];
} RKRConFrameBuilder;

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

/**
 * Returns the spec version at runtime (for dynamically linked consumers).
 */
uint32_t rkr_con_spec_version(void);

/**
 * Returns a pointer to a static, null-terminated library version string.
 * The returned pointer is valid for the lifetime of the process. Do NOT free it.
 */
const char *rkr_library_version(void);

/**
 * Returns the spec version stored in a parsed frame's header.
 * Returns 0 on error (null handle).
 */
uint32_t rkr_frame_spec_version(const struct RKRConFrame *frame_handle);

/**
 * Returns the JSON metadata line from a parsed frame as a heap-allocated
 * null-terminated C string. The caller MUST free with `rkr_free_string`.
 * Returns NULL on error.
 *
 * # Safety
 * frame_handle must be valid. The caller takes ownership of the returned string.
 */
char *rkr_frame_metadata_json(const struct RKRConFrame *frame_handle);

/**
 * Returns the per-frame energy from metadata, or NaN if absent.
 */
double rkr_frame_energy(const struct RKRConFrame *frame_handle);

/**
 * Returns the potential type string from metadata as a heap-allocated
 * null-terminated C string. The caller MUST free with `rkr_free_string`.
 * Returns NULL if absent or on error.
 *
 * # Safety
 * frame_handle must be valid. The caller takes ownership of the returned string.
 */
char *rkr_frame_potential_type(const struct RKRConFrame *frame_handle);

/**
 * Returns the zero-based frame index from metadata, or UINT64_MAX if absent.
 */
uint64_t rkr_frame_frame_index(const struct RKRConFrame *frame_handle);

/**
 * Returns the simulation time from metadata, or NaN if absent.
 */
double rkr_frame_time(const struct RKRConFrame *frame_handle);

/**
 * Returns the integration timestep from metadata, or NaN if absent.
 */
double rkr_frame_timestep(const struct RKRConFrame *frame_handle);

/**
 * Returns the NEB bead index from metadata, or UINT64_MAX if absent.
 */
uint64_t rkr_frame_neb_bead(const struct RKRConFrame *frame_handle);

/**
 * Returns the NEB band index from metadata, or UINT64_MAX if absent.
 */
uint64_t rkr_frame_neb_band(const struct RKRConFrame *frame_handle);

/**
 * Returns a stable, static message for a status code.
 * The returned pointer is valid for the lifetime of the process. Do NOT free it.
 */
const char *rkr_status_message(enum RKRStatus status);

/**
 * Creates a new iterator for a .con or .convel file.
 *
 * Returns NULL if the file cannot be read (missing, unreadable, or
 * not valid UTF-8). A successfully-opened file with zero frames
 * returns a non-NULL iterator that yields NULL on the first call to
 * [`con_frame_iterator_next`]. The caller OWNS the returned pointer
 * and MUST call [`free_con_frame_iterator`].
 *
 * # Safety
 * filename_c must be a valid null-terminated string. The caller takes
 * ownership of the returned iterator.
 */
struct CConFrameIterator *read_con_file_iterator(const char *filename_c);

/**
 * Reads the next frame from the iterator, returning an opaque handle.
 * The caller OWNS the returned handle and must free it with `free_rkr_frame`.
 *
 * # Safety
 * iterator must be valid. The caller takes ownership of the returned frame.
 */
struct RKRConFrame *con_frame_iterator_next(struct CConFrameIterator *iterator);

/**
 * Frees the memory for an opaque `RKRConFrame` handle.
 *
 * # Safety
 * frame_handle must be valid or null.
 */
void free_rkr_frame(struct RKRConFrame *frame_handle);

/**
 * Frees the memory for a `CConFrameIterator`.
 *
 * # Safety
 * iterator must be valid or null.
 */
void free_con_frame_iterator(struct CConFrameIterator *iterator);

/**
 * Extracts the core atomic data into a transparent `CFrame` struct.
 * The caller OWNS the returned pointer and MUST call `free_c_frame` on it.
 *
 * # Safety
 * frame_handle must be valid. The caller takes ownership of the returned CFrame.
 */
struct CFrame *rkr_frame_to_c_frame(const struct RKRConFrame *frame_handle);

/**
 * Frees the memory of a `CFrame` struct, including its internal atoms array.
 *
 * # Safety
 * frame must be valid or null.
 */
void free_c_frame(struct CFrame *frame);

/**
 * Copies a header string line into a caller-provided buffer.
 *
 * `is_prebox=true` selects from the two prebox lines (line 0 = user
 * text, line 1 = JSON metadata); `false` selects from the two postbox
 * lines. Strings longer than `buffer_len - 1` bytes are truncated; the
 * final byte is always set to NUL.
 *
 * Returns `RKR_STATUS_SUCCESS` on success,
 * `RKR_STATUS_INDEX_OUT_OF_BOUNDS` if `line_index >= 2`,
 * `RKR_STATUS_NULL_POINTER` if `frame_handle` or `buffer` is NULL,
 * `RKR_STATUS_BUFFER_TOO_SMALL` if `buffer_len == 0`.
 *
 * Pair with [`rkr_frame_get_header_line_cpp`] when the caller prefers
 * an allocated string with no fixed length cap; that variant returns
 * NULL for the same out-of-bounds condition.
 *
 * # Safety
 * frame_handle must be valid. buffer must be at least buffer_len bytes.
 */
enum RKRStatus rkr_frame_get_header_line(const struct RKRConFrame *frame_handle,
                                         bool is_prebox,
                                         uintptr_t line_index,
                                         char *buffer,
                                         uintptr_t buffer_len);

/**
 * Gets a header string line as a newly allocated, null-terminated C string.
 *
 * The caller OWNS the returned pointer and MUST call `rkr_free_string`
 * on it to prevent a memory leak. Returns NULL on error or if the
 * index is invalid (use [`rkr_frame_get_header_line`] when a status
 * code is preferred to NULL-vs-success disambiguation).
 *
 * The `_cpp` suffix is historical; the function is callable from both
 * C and C++.
 *
 * # Safety
 * frame_handle must be valid. The caller takes ownership of the returned string.
 */
char *rkr_frame_get_header_line_cpp(const struct RKRConFrame *frame_handle,
                                    bool is_prebox,
                                    uintptr_t line_index);

/**
 * Frees a C string that was allocated by Rust (e.g., from
 * `rkr_frame_metadata_json`, `rkr_frame_potential_type`, or
 * `rkr_frame_get_header_line_cpp`). Safe to call with NULL (no-op).
 *
 * # Safety
 * s must be either NULL or a pointer previously returned by an
 * allocating Rust FFI function in this crate.
 */
void rkr_free_string(char *s);

/**
 * Creates a new frame writer for the specified file.
 * The caller OWNS the returned pointer and MUST call `free_rkr_writer`.
 *
 * # Safety
 * filename_c must be valid. The caller takes ownership of the returned writer.
 */
struct RKRConFrameWriter *create_writer_from_path_c(const char *filename_c);

/**
 * Frees the memory for an `RKRConFrameWriter`, closing the associated file.
 *
 * # Safety
 * writer_handle must be valid or null.
 */
void free_rkr_writer(struct RKRConFrameWriter *writer_handle);

/**
 * Writes multiple frames from an array of handles to the file managed by the writer.
 * Returns `RKR_STATUS_SUCCESS` on success, or an error code.
 *
 * # Safety
 * writer_handle and frame_handles must be valid.
 */
enum RKRStatus rkr_writer_extend(struct RKRConFrameWriter *writer_handle,
                                 const struct RKRConFrame *const *frame_handles,
                                 uintptr_t num_frames);

/**
 * Creates a new frame writer with custom floating-point precision.
 * The caller OWNS the returned pointer and MUST call `free_rkr_writer`.
 *
 * # Safety
 * filename_c must be valid. The caller takes ownership of the returned writer.
 */
struct RKRConFrameWriter *create_writer_from_path_with_precision_c(const char *filename_c,
                                                                   uint8_t precision);

/**
 * Attaches a velocity vector to the most recently added atom on a builder.
 * No-op if no atom has been added yet.
 *
 * # Safety
 * builder_handle must be valid. velocity must point to 3 contiguous f64 values.
 */
enum RKRStatus rkr_frame_builder_set_last_velocity(struct RKRConFrameBuilder *builder_handle,
                                                   const double *velocity);

/**
 * Attaches a force vector to the most recently added atom on a builder.
 * No-op if no atom has been added yet.
 *
 * # Safety
 * builder_handle must be valid. force must point to 3 contiguous f64 values.
 */
enum RKRStatus rkr_frame_builder_set_last_force(struct RKRConFrameBuilder *builder_handle,
                                                const double *force);

/**
 * Adds an atom with optional per-axis fixed mask, velocity, and force vectors.
 *
 * `velocity` and `force` are pointers to 3 contiguous f64 values, or NULL if
 * absent. This is the unified entry point that replaces the eight
 * `rkr_frame_add_atom_*` convenience functions; callers may continue using
 * those for source compatibility.
 *
 * # Safety
 * builder_handle and symbol must be valid. velocity (if non-null) must point
 * to 3 contiguous f64 values, and force (if non-null) likewise.
 */
enum RKRStatus rkr_frame_add_atom_full(struct RKRConFrameBuilder *builder_handle,
                                       const char *symbol,
                                       double x,
                                       double y,
                                       double z,
                                       bool fixed_x,
                                       bool fixed_y,
                                       bool fixed_z,
                                       uint64_t atom_id,
                                       double mass,
                                       const double *velocity,
                                       const double *force);

/**
 * Creates a new frame builder with the given cell dimensions, angles,
 * and header lines.
 *
 * `prebox1` is accepted for source compatibility but ignored: the
 * JSON metadata line is regenerated by the writer from the builder's
 * `spec_version`, `metadata`, and `sections`. Pass NULL or any string.
 * The caller OWNS the returned pointer and MUST call
 * `free_rkr_frame_builder` or consume it via `rkr_frame_builder_build`.
 * Returns NULL on error.
 *
 * # Safety
 * cell and angles must point to 3 doubles. prebox0, postbox0, and
 * postbox1 must be NULL or valid null-terminated strings; prebox1 is
 * not dereferenced. The caller takes ownership of the returned
 * builder.
 */
struct RKRConFrameBuilder *rkr_frame_new(const double *cell,
                                         const double *angles,
                                         const char *prebox0,
                                         const char *prebox1,
                                         const char *postbox0,
                                         const char *postbox1);

/**
 * Parses and sets JSON metadata on an existing frame builder.
 * Returns `RKR_STATUS_SUCCESS` on success, or an error code.
 *
 * # Safety
 * builder_handle and metadata_json must be valid.
 */
enum RKRStatus rkr_frame_builder_set_metadata_json(struct RKRConFrameBuilder *builder_handle,
                                                   const char *metadata_json);

/**
 * Sets a numeric metadata key on an existing frame builder.
 * Returns `RKR_STATUS_SUCCESS` on success, or an error code.
 *
 * # Safety
 * builder_handle and key must be valid.
 */
enum RKRStatus rkr_frame_builder_set_scalar_metadata(struct RKRConFrameBuilder *builder_handle,
                                                     const char *key,
                                                     double value);

/**
 * Sets a string metadata key on an existing frame builder.
 * Returns `RKR_STATUS_SUCCESS` on success, or an error code.
 *
 * # Safety
 * builder_handle, key, and value must be valid.
 */
enum RKRStatus rkr_frame_builder_set_string_metadata(struct RKRConFrameBuilder *builder_handle,
                                                     const char *key,
                                                     const char *value);

/**
 * Sets the per-frame total energy metadata on an existing frame builder.
 * Returns `RKR_STATUS_SUCCESS` on success, or an error code.
 *
 * # Safety
 * builder_handle must be valid.
 */
enum RKRStatus rkr_frame_builder_set_energy(struct RKRConFrameBuilder *builder_handle,
                                            double energy);

/**
 * Sets the zero-based frame index metadata on an existing frame builder.
 * Returns `RKR_STATUS_SUCCESS` on success, or an error code.
 *
 * # Safety
 * builder_handle must be valid.
 */
enum RKRStatus rkr_frame_builder_set_frame_index(struct RKRConFrameBuilder *builder_handle,
                                                 uint64_t idx);

/**
 * Sets the simulation time metadata on an existing frame builder.
 * Returns `RKR_STATUS_SUCCESS` on success, or an error code.
 *
 * # Safety
 * builder_handle must be valid.
 */
enum RKRStatus rkr_frame_builder_set_time(struct RKRConFrameBuilder *builder_handle,
                                          double time);

/**
 * Sets the timestep metadata on an existing frame builder.
 * Returns `RKR_STATUS_SUCCESS` on success, or an error code.
 *
 * # Safety
 * builder_handle must be valid.
 */
enum RKRStatus rkr_frame_builder_set_timestep(struct RKRConFrameBuilder *builder_handle,
                                              double dt);

/**
 * Sets the NEB bead index metadata on an existing frame builder.
 * Returns `RKR_STATUS_SUCCESS` on success, or an error code.
 *
 * # Safety
 * builder_handle must be valid.
 */
enum RKRStatus rkr_frame_builder_set_neb_bead(struct RKRConFrameBuilder *builder_handle,
                                              uint64_t bead);

/**
 * Sets the NEB band index metadata on an existing frame builder.
 * Returns `RKR_STATUS_SUCCESS` on success, or an error code.
 *
 * # Safety
 * builder_handle must be valid.
 */
enum RKRStatus rkr_frame_builder_set_neb_band(struct RKRConFrameBuilder *builder_handle,
                                              uint64_t band);

/**
 * **Deprecated**: prefer `rkr_frame_add_atom_full` with NULL velocity
 * and force pointers. Adds an atom (no velocity, no forces) to the
 * builder using a single uniform fixed flag.
 * Returns `RKR_STATUS_SUCCESS` on success, or an error code.
 *
 * # Safety
 * builder_handle and symbol must be valid.
 */
enum RKRStatus rkr_frame_add_atom(struct RKRConFrameBuilder *builder_handle,
                                  const char *symbol,
                                  double x,
                                  double y,
                                  double z,
                                  bool is_fixed,
                                  uint64_t atom_id,
                                  double mass);

/**
 * **Deprecated**: prefer `rkr_frame_add_atom_full`. Adds an atom (no
 * velocity, no forces) using per-axis fixed flags.
 * Returns `RKR_STATUS_SUCCESS` on success, or an error code.
 *
 * # Safety
 * builder_handle and symbol must be valid.
 */
enum RKRStatus rkr_frame_add_atom_with_fixed_mask(struct RKRConFrameBuilder *builder_handle,
                                                  const char *symbol,
                                                  double x,
                                                  double y,
                                                  double z,
                                                  bool fixed_x,
                                                  bool fixed_y,
                                                  bool fixed_z,
                                                  uint64_t atom_id,
                                                  double mass);

/**
 * **Deprecated**: prefer `rkr_frame_add_atom_full`. Adds an atom with
 * a velocity vector and a single uniform fixed flag.
 * Returns `RKR_STATUS_SUCCESS` on success, or an error code.
 *
 * # Safety
 * builder_handle and symbol must be valid.
 */
enum RKRStatus rkr_frame_add_atom_with_velocity(struct RKRConFrameBuilder *builder_handle,
                                                const char *symbol,
                                                double x,
                                                double y,
                                                double z,
                                                bool is_fixed,
                                                uint64_t atom_id,
                                                double mass,
                                                double vx,
                                                double vy,
                                                double vz);

/**
 * **Deprecated**: prefer `rkr_frame_add_atom_full`. Adds an atom with
 * a velocity vector and per-axis fixed flags.
 * Returns `RKR_STATUS_SUCCESS` on success, or an error code.
 *
 * # Safety
 * builder_handle and symbol must be valid.
 */
enum RKRStatus rkr_frame_add_atom_with_velocity_fixed_mask(struct RKRConFrameBuilder *builder_handle,
                                                           const char *symbol,
                                                           double x,
                                                           double y,
                                                           double z,
                                                           bool fixed_x,
                                                           bool fixed_y,
                                                           bool fixed_z,
                                                           uint64_t atom_id,
                                                           double mass,
                                                           double vx,
                                                           double vy,
                                                           double vz);

/**
 * **Deprecated**: prefer `rkr_frame_add_atom_full`. Adds an atom with
 * a force vector and a single uniform fixed flag.
 * Returns `RKR_STATUS_SUCCESS` on success, or an error code.
 *
 * # Safety
 * builder_handle and symbol must be valid.
 */
enum RKRStatus rkr_frame_add_atom_with_forces(struct RKRConFrameBuilder *builder_handle,
                                              const char *symbol,
                                              double x,
                                              double y,
                                              double z,
                                              bool is_fixed,
                                              uint64_t atom_id,
                                              double mass,
                                              double fx,
                                              double fy,
                                              double fz);

/**
 * **Deprecated**: prefer `rkr_frame_add_atom_full`. Adds an atom with
 * a force vector and per-axis fixed flags.
 * Returns `RKR_STATUS_SUCCESS` on success, or an error code.
 *
 * # Safety
 * builder_handle and symbol must be valid.
 */
enum RKRStatus rkr_frame_add_atom_with_forces_fixed_mask(struct RKRConFrameBuilder *builder_handle,
                                                         const char *symbol,
                                                         double x,
                                                         double y,
                                                         double z,
                                                         bool fixed_x,
                                                         bool fixed_y,
                                                         bool fixed_z,
                                                         uint64_t atom_id,
                                                         double mass,
                                                         double fx,
                                                         double fy,
                                                         double fz);

/**
 * **Deprecated**: prefer `rkr_frame_add_atom_full`. Adds an atom with
 * both velocity and force vectors and a single uniform fixed flag.
 * Returns `RKR_STATUS_SUCCESS` on success, or an error code.
 *
 * # Safety
 * builder_handle and symbol must be valid.
 */
enum RKRStatus rkr_frame_add_atom_with_velocity_and_forces(struct RKRConFrameBuilder *builder_handle,
                                                           const char *symbol,
                                                           double x,
                                                           double y,
                                                           double z,
                                                           bool is_fixed,
                                                           uint64_t atom_id,
                                                           double mass,
                                                           double vx,
                                                           double vy,
                                                           double vz,
                                                           double fx,
                                                           double fy,
                                                           double fz);

/**
 * **Deprecated**: prefer `rkr_frame_add_atom_full`. Adds an atom with
 * both velocity and force vectors and per-axis fixed flags.
 * Returns `RKR_STATUS_SUCCESS` on success, or an error code.
 *
 * # Safety
 * builder_handle and symbol must be valid.
 */
enum RKRStatus rkr_frame_add_atom_with_velocity_and_forces_fixed_mask(struct RKRConFrameBuilder *builder_handle,
                                                                      const char *symbol,
                                                                      double x,
                                                                      double y,
                                                                      double z,
                                                                      bool fixed_x,
                                                                      bool fixed_y,
                                                                      bool fixed_z,
                                                                      uint64_t atom_id,
                                                                      double mass,
                                                                      double vx,
                                                                      double vy,
                                                                      double vz,
                                                                      double fx,
                                                                      double fy,
                                                                      double fz);

/**
 * Consumes the builder and returns a finalized RKRConFrame handle.
 * The builder handle is invalidated after this call.
 * The caller OWNS the returned frame and MUST call `free_rkr_frame`.
 * Returns NULL on error.
 *
 * # Safety
 * builder_handle must be valid. The caller takes ownership of the returned frame.
 */
struct RKRConFrame *rkr_frame_builder_build(struct RKRConFrameBuilder *builder_handle);

/**
 * Frees a frame builder without building.
 *
 * # Safety
 * builder_handle must be valid or null.
 */
void free_rkr_frame_builder(struct RKRConFrameBuilder *builder_handle);

/**
 * Creates a new gzip-compressed frame writer for the specified file.
 * The caller OWNS the returned pointer and MUST call `free_rkr_writer`.
 *
 * # Safety
 * filename_c must be valid. The caller takes ownership of the returned writer.
 */
struct RKRConFrameWriter *create_writer_gzip_c(const char *filename_c);

/**
 * Reads the first frame from a .con file.
 * Uses `read_to_string` for small files (< 64 KiB) and mmap for larger ones.
 * Stops after the first frame rather than parsing the entire file.
 * The caller OWNS the returned handle and MUST call `free_rkr_frame`.
 * Returns NULL on error.
 *
 * # Safety
 * filename_c must be valid. The caller takes ownership of the returned frame.
 */
struct RKRConFrame *rkr_read_first_frame(const char *filename_c);

/**
 * Reads all frames from a .con file using mmap.
 * Returns an array of frame handles and sets `num_frames` to the count.
 * The caller OWNS both the array and each frame handle.
 * Free frames with `free_rkr_frame` and the array with `free_rkr_frame_array`.
 * Returns NULL on error.
 *
 * # Safety
 * filename_c and num_frames must be valid. The caller takes ownership of the returned handles and array.
 */
struct RKRConFrame **rkr_read_all_frames(const char *filename_c,
                                         uintptr_t *num_frames);

/**
 * Frees an array of frame handles returned by `rkr_read_all_frames`.
 * Each frame is freed individually, then the array itself.
 *
 * # Safety
 * frames must be valid or null.
 */
void free_rkr_frame_array(struct RKRConFrame **frames, uintptr_t num_frames);

#ifdef __cplusplus
}  // extern "C"
#endif  // __cplusplus

#ifdef __cplusplus
}  // namespace readcon
#endif  // __cplusplus

#endif  /* READCON_H */
