module Data.Text.Sized where

open import Level using (Level)
open import Level.Bounded using ([_]; lower; lift)
open import Data.Empty.Irrelevant
open import Data.Unit
open import Data.Nat.Base
import Data.Nat.Properties as ℕₚ
open import Data.Char.Base
open import Data.String.Base using (String; length; uncons)
open import Data.String.Unsafe
open import Data.Maybe.Base
open import Data.Product
open import Data.List.Sized.Interface
open import Function.Base using (_$_; _∘′_; case_of_)
open import Relation.Binary.PropositionalEquality as Eq using (_≡_; refl)

private
  variable l : Level

record Text (n : ℕ) : Set where
  constructor mkText
  field
    value  : String
    .proof : length value ≡ n
open Text

record Split (n : ℕ) (str : String) : Set where
  constructor mkSplit
  field
    head   : Char
    tail   : String
    .size  : length tail ≡ n
    .proof : uncons str ≡ just (head , tail)

length-uncons : ∀ str {mcs} → uncons str ≡ mcs →
                length str ≡ maybe′ (suc ∘′ length ∘′ proj₂) zero mcs
length-uncons str eq with uncons str | length-tail str
length-uncons str refl | nothing | p = p
length-uncons str refl | just _  | p = p

split : ∀ str {n} → .(_ : length str ≡ suc n) → Split n str
split str {n} lgth with uncons str in eq
... | just (c , s) = mkSplit c s (prf lgth) eq where

  .prf : length str ≡  suc n → length s ≡ n
  prf lgth = ℕₚ.suc-injective $ begin
    suc (length s) ≡˘⟨ length-uncons str eq ⟩
    length str     ≡⟨ lgth ⟩
    suc n          ∎ where open Eq.≡-Reasoning

... | nothing      = ⊥-elim (case prf lgth of λ ()) where

  .prf : length str ≡ suc n → 0 ≡ suc n
  prf lgth = begin
    0          ≡˘⟨ length-uncons str eq ⟩
    length str ≡⟨ lgth ⟩
    suc n      ∎ where open Eq.≡-Reasoning

instance

  text : Sized {l} [ Char ] (λ n → [ Text n ])
  Sized.view text {zero}  t = _
  Sized.view text {suc n} (Level.lift (mkText val prf)) =
    let (mkSplit hd tl prf _) = split val prf in
    lift (hd , mkText tl prf)