!===========================================
! Author: Elmo Tempel (elmo.tempel@ut.ee)
!===========================================
!> The public API of parquet-fortran, and the only module a user needs to name:
!> a single `use parquet` brings the whole library into scope.
!>
!> This module is a facade. It re-exports, unchanged, every public entity of the
!> modules that actually implement the library:
!>
!>   * `parquet_io`      -- readers, writers, schemas, MAML parsing/validation,
!>                          filters, sort keys, read-time qc, file metadata.
!>                          Itself a facade over the internal `parquet_core`.
!>   * `parquet_tables`  -- the `parquet_table` container: lazy columnar reads,
!>                          slices, row handles, mutation, table write-out.
!>   * `parquet_columns` -- the `parquet_column` foundation and the `PK_*` kind
!>                          constants.
!>   * `parquet_strings` -- `parquet_string_column`/`parquet_string`.
!>   * `parquet_temporal`-- `parquet_date`/`parquet_time`/`parquet_timestamp`
!>                          and the `parquet_unit_*`/`parquet_ns_*` constants.
!>   * `parquet_sorting` -- `pf_sort`/`pf_argsort`/`pf_permute`/`pf_is_sorted`
!>                          and the `pf_sort_keys` multi-key builder.
!>   * `parquet_random` -- counter-based random numbers: `pf_random_at` and
!>                          friends, reproducible under any OpenMP schedule.
!>   * `parquet_settings`-- process-global settings: thread caps, writer
!>                          defaults, terminal verbosity and message stream,
!>                          plus the read-only `parquet_max_*` limits.
!>   * `parquet_maml_base` -- `parquet_maml_file`, for embedded MAML schemas.
!>   * `parquet_version` -- `parquet_get_version`, this library's own version
!>                          string. This facade is the ONLY module that
!>                          re-exports it: an Arrow-free tier deliberately does
!>                          not, so a program importing one of those writes its
!>                          own `use parquet_version` line.
!>
!> Those modules remain individually usable (`use parquet_temporal` still works
!> and still costs less to compile against), but nothing requires it -- every
!> name they export is reachable through this one. The exception is
!> `parquet_bindings`, the raw C interop layer, which is deliberately NOT
!> re-exported: it is an implementation detail, not user API.
!>
!> This module holds no code of its own. Both version queries are re-exported
!> from elsewhere: `parquet_get_version` from the leaf `parquet_version`, and
!> `parquet_get_arrow_version` -- the linked Arrow/Parquet C++ versions, which
!> need the C++ boundary -- from `parquet_settings`.
module parquet
    use parquet_io
    use parquet_tables
    use parquet_columns
    use parquet_strings
    use parquet_temporal
    use parquet_sorting
    use parquet_random
    use parquet_sampling
    ! Only the test hook: the transform itself and its contract check are internal.
    use parquet_expkey, only: parquet_debug_exp_key, parquet_debug_set_exp_key_contract
    use parquet_settings
    ! The library's own version string, which lives in a leaf module of its own so that a program
    ! built on an Arrow-free tier can report it without importing anything else. This bare `use` is
    ! the one re-export of it in the library -- see src/parquet_version.f90's header for why no
    ! sibling module carries it.
    use parquet_version
    ! parquet_maml_base is the one sibling imported with an `only:` list rather than in full. Its
    ! other public names (get_parquet_maml and the parquet_maml_maml_example* accessors) return
    ! THIS library's own embedded MAML test fixtures -- they were never part of the public surface,
    ! and a downstream project gets its own generated parquet_maml module from
    ! tools/generate_parquet_maml.sh instead. Only the three types below are user API.
    use parquet_maml_base, only: parquet_maml_file, parquet_maml_missing_column, parquet_maml_col_map_entry
    implicit none
    !
    ! Default accessibility is deliberately PUBLIC here, unlike every other module in this
    ! library: a bare `use <sibling>` with no `only:` list re-exports that module's whole
    ! public surface, which is exactly what a facade wants and what avoids maintaining a
    ! ~120-name `public ::` list that would go stale on every addition. The private
    ! statements below are what keep the siblings' cross-module plumbing out of the namespace a
    ! user gets from `use parquet`. The C interop layer needs no statement: parquet_bindings is
    ! simply never imported here.
    ! `parquet_split_name_list` and `parquet_parse_sort_key` need NO statement here: parquet_core
    ! makes both public so the sibling parquet_tables module can share the library's one name-list
    ! tokenizer and its one sort-key direction grammar rather than keeping second copies, and
    ! `parquet_io` -- the facade this one now re-exports in place of parquet_core -- already hides
    ! them. Adding a `private ::` for either here is an ERROR, not a redundancy: the name is not
    ! accessible in this scope at all, and nagfor reports it as an implicitly-typed local.
    ! parquet_settings has to make these two public so the write path (a submodule of parquet_core,
    ! a different module) can reach them -- Fortran has no package scope. They are plumbing, not
    ! API, so the facade keeps them out of the namespace `use parquet` hands a user, exactly as the
    ! statements below do for the other cross-module plumbing.
    private :: parquet_valid_compressions, parquet_resolve_writer_compression
    ! The three output channels and the suppression query are the same case: every module that
    ! emits has to reach them, so parquet_settings makes them public, and the facade hides them.
    private :: parquet_emit_info, parquet_emit_warning, parquet_emit_error_context
    private :: parquet_output_is_suppressed
    private :: parquet_clamp_to_affinity
    ! The Fortran->C++ mirror push, and the validity bitmap's block width. Both are public from
    ! their own module because a sibling needs them -- parquet_read/parquet_write/
    ! parquet_sorting_oracle call the push when a reader, writer or sort opens, and
    ! parquet_tables_read needs the block width to trim a threaded paste to whole blocks rather
    ! than copying the constant (CLAUDE.md, "Disjoint ROWS are not disjoint BITS"). Publishing to
    ! a SIBLING and publishing to every user of the library are different decisions, and only the
    ! first was ever taken. Row 30's code issues 2 and 3.
    private :: parquet_push_settings_to_cpp
    private :: parquet_validity_block_bits
    ! parquet_columns' typed per-cell accessor tier, hidden for the same reason again. These are
    ! how parquet_tables reaches a column's storage without a type-bound call -- which is what
    ! keeps ifx from building a runtime type descriptor in the caller's prologue on every access
    ! (feature_ifx.md). They duplicate no user-facing capability: the identical operations are
    ! already on parquet_column as %get_at/%set_at/%get_elem/%set_elem/%is_null/%set_null/
    ! %clear_null/%data_ptr/%string_column, which is what a user calls. Adding a typed accessor
    ! means adding a line here too.
    private :: parquet_column_get_at, parquet_column_set_at
    private :: parquet_column_get_elem, parquet_column_set_elem
    private :: parquet_column_data_ptr, parquet_column_string_column
    private :: parquet_column_is_null, parquet_column_set_null, parquet_column_clear_null
    ! Not part of that per-cell tier, hidden here for the same reason: it is the non-mutating
    ! `any_null` the table's read accessors must use, and a user already has `%any_null()`.
    private :: parquet_column_any_null
    ! parquet_strings' typed tier, hidden for the same reason once more. These are how
    ! parquet_columns reaches a column's embedded parquet_string_column without a type-bound
    ! call, and they duplicate no user-facing capability: every one of them is already a binding
    ! on parquet_string_column (%is_null, %get, %set, ...), which is what a user calls. Adding a
    ! typed string accessor means adding a line here too.
    private :: parquet_string_column_clear
    private :: parquet_string_column_shrink_to_fit, parquet_string_column_capacity
    private :: parquet_string_column_character_capacity, parquet_string_column_size
    private :: parquet_string_column_character_size, parquet_string_column_null_count
    private :: parquet_string_column_has_validity, parquet_string_column_reserve_validity
    private :: parquet_string_column_append_column, parquet_string_column_append_null
    private :: parquet_string_column_append_values, parquet_string_column_delete_by_mask
    private :: parquet_string_column_reserve, parquet_string_column_get, parquet_string_column_copy_to
    private :: parquet_string_column_is_null, parquet_string_column_append_from, parquet_string_column_set
    private :: parquet_string_column_set_null, parquet_string_column_reindex, parquet_string_column_reindex_trusted
    private :: parquet_string_column_gather, parquet_string_column_append_nulls
    !
    ! ---- The sorting tiers' internals need NO `private ::` here, and that is worth stating ----
    !
    ! `parquet_argsort` exports its engine, `sort_key_buf`, the six intrinsic extractors and the
    ! oracle plumbing so that `parquet_sorting` and `parquet_sorting_oracle` can share one copy of
    ! each rather than keeping second copies that could disagree. None of it reaches this facade:
    ! `parquet_sorting` imports the tier with a bare `use` under its own default `private`
    ! accessibility and names only the `pf_` surface, the settings and the debug hooks in its
    ! `public ::` lines, so everything else stops there. `parquet_sorting_oracle` is not imported
    ! here at all -- `parquet_debug_use_fortran_sort_engine` is reachable only by a program that
    ! names that module itself, which is what keeps the C++ engine out of every other build.
    !

end module parquet
