/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Markus Himmel
-/
module

prelude
public import Init.Data.String.Modify
import all Init.Data.String.Modify
import Init.Data.String.Lemmas.Basic

/-!
# Lemmas for `Init.Data.String.Modify`

This file contains lemmas for the operations defined in `Init.Data.String.Modify`.

Note that `Init.Data.String.Modify` already proves a few lemmas which are needed immediately.
-/

public section

namespace String

/-- You might want to invoke `Pos.Splits.exists_eq_singleton_append` to be able to apply this. -/
theorem Pos.Splits.pastSet {s : String} {p : s.Pos} {t₁ t₂ : String}
    {c d : Char} (h : p.Splits t₁ (singleton c ++ t₂)) :
    (p.pastSet d h.ne_endPos_of_singleton).Splits (t₁ ++ singleton d) t₂ := by
  generalize h.ne_endPos_of_singleton = hp
  obtain ⟨rfl, rfl, rfl⟩ := by simpa using h.eq (p.splits_next_right hp)
  apply splits_pastSet

/-- You might want to invoke `Pos.Splits.exists_eq_singleton_append` to be able to apply this. -/
theorem Pos.Splits.pastModify {s : String} {p : s.Pos} {t₁ t₂ : String}
    {c : Char} (h : p.Splits t₁ (singleton c ++ t₂)) :
    (p.pastModify f h.ne_endPos_of_singleton).Splits
    (t₁ ++ singleton (f (p.get h.ne_endPos_of_singleton))) t₂ :=
  h.pastSet

theorem toList_mapAux {f : Char → Char} {s : String} {p : s.Pos}
    (h : p.Splits t₁ t₂) : (mapAux f s p).toList = t₁.toList ++ t₂.toList.map f := by
  fun_induction mapAux generalizing t₁ t₂ with
  | case1 s => simp_all
  | case2 s p hp ih =>
    obtain ⟨c, rfl⟩ := h.exists_eq_singleton_append hp
    simp [ih h.pastModify]

@[simp]
theorem toList_map {f : Char → Char} {s : String} : (s.map f).toList = s.toList.map f := by
  simp [map, toList_mapAux s.splits_startPos]

/-
  Used internally by the `cbv` tactic.
-/
@[cbv_eval]
theorem map_eq_internal {f : Char → Char} {s : String} : s.map f = .ofList (s.toList.map f) := by
  apply String.toList_injective
  simp only [toList_map, toList_ofList]

@[simp]
theorem length_map {f : Char → Char} {s : String} : (s.map f).length = s.length := by
  simp [← length_toList]

@[simp]
theorem map_eq_empty {f : Char → Char} {s : String} : s.map f = "" ↔ s = "" := by
  simp [← toList_eq_nil_iff]

@[simp]
theorem map_map {f g : Char → Char} {s : String} : String.map g (String.map f s) = String.map (g ∘ f) s  := by
  apply String.ext
  simp [List.map_map]

@[simp]
theorem map_id {s : String} : String.map id s = s := by
  apply String.ext
  simp [List.map_id]

end String
