--  Copyright © 2026 Lingenic LLC. All rights reserved.
--  Licensed under the Lingenic Source-Available License v2.3.
--  Production use requires a separate license from Licensor.
--  See LICENSE.md and COPYRIGHT in the project root.
--

-------------------------------------------------------------------------------
--  Lingenic-Text
--  Formally Verified Unicode Text Processing Library
--
--  Generic text transformation.
--
--  One entry point for all modules that process UTF-8 input and produce
--  UTF-8 output: normalization, case mapping, or any future transform.
--
--  The generic handles:
--    - UTF-8 decoding of input bytes into codepoints
--    - Output buffer position tracking
--    - Per-codepoint dispatch to the module-specific callback
--    - End-of-input finalization
--
--  The module provides State_Type plus four formal subprograms:
--
--    Output_Valid    — final specification: what "correct output" means
--    Partial_Valid   — loop invariant: maintained across On_Codepoint calls
--    On_Codepoint    — per-codepoint processing (preserves Partial_Valid)
--    On_Finish       — finalization (bridges Partial_Valid → Output_Valid)
--
--  The generic carries Partial_Valid as its loop invariant.  On_Codepoint's
--  postcondition preserves it.  On_Finish's postcondition bridges from
--  Partial_Valid to Output_Valid.  The generic's postcondition asserts
--  Output_Valid holds on success.
--
--  Formal procedure contracts guarantee the output position never retreats
--  and never exceeds Output'Last + 1, so the generic loop invariants hold.
-------------------------------------------------------------------------------

generic
   type State_Type is private;

   with function Output_Valid
     (S      : State_Type;
      Output : Byte_Array;
      Last   : Natural) return Boolean;

   with function Partial_Valid
     (S      : State_Type;
      Output : Byte_Array;
      Pos    : Natural) return Boolean;

   with procedure On_Codepoint
     (State  : in out State_Type;
      CP     : Codepoint;
      Output : in out Byte_Array;
      Pos    : in out Natural;
      OK     : in out Boolean)
   with Pre  => Output'Last < Positive'Last
                and then Pos >= Output'First
                and then Pos <= Output'Last + 1
                and then OK
                and then Partial_Valid (State, Output, Pos),
        Post => Pos >= Pos'Old
                and then Pos <= Output'Last + 1
                and then (if OK then
                            Partial_Valid (State, Output, Pos));

   with procedure On_Finish
     (State  : in out State_Type;
      Output : in out Byte_Array;
      Pos    : in out Natural;
      OK     : in out Boolean)
   with Pre  => Output'Last < Positive'Last
                and then Pos >= Output'First
                and then Pos <= Output'Last + 1
                and then OK
                and then Partial_Valid (State, Output, Pos),
        Post => Pos >= Pos'Old
                and then Pos <= Output'Last + 1
                and then (if OK and then Pos > Output'First then
                            Output_Valid (State, Output, Pos - 1));

procedure Lingenic_Text.Text_Transform
  (Input  : Byte_Array;
   State  : in out State_Type;
   Output : in out Byte_Array;
   Last   : out Natural;
   OK     : out Boolean)
with SPARK_Mode,
     Pre  => Input'Length >= 1
             and then Output'Length >= 1
             and then Input'Last < Positive'Last
             and then Output'Last < Positive'Last
             and then Partial_Valid (State, Output, Output'First),
     Post => (if OK then Last in Output'First .. Output'Last
                         and then Output_Valid (State, Output, Last)
              else Last = Output'First - 1),
     Always_Terminates;