{-# OPTIONS --without-K --rewriting #-}

module Pi.Common.LList where

open import lib.Base
open import lib.types.Nat using (_+_)
open import lib.types.Sigma
open import lib.NType
open import lib.PathGroupoid
open import lib.Equivalence
open import lib.PathOver
open import lib.types.Fin

open import Pi.Common.Arithmetic
open import Pi.Common.ListN
open import Pi.Common.InequalityEquiv

data _>>_ :  -> Listℕ -> Type₀ where
  nil : {n : } -> n >> nil
  _:⟨_⟩:_ : {n : } -> {l : Listℕ} -> (k : ) -> (k < n) -> n >> l -> n >> (k  l)

extract-proof : {n : } -> {l : Listℕ} -> {a : } -> (n >> (a  l)) -> (a < n)
extract-proof (_ :⟨ p ⟩: _) = p

>>-↓ : (n k r : ) -> (r + k  n) -> (n >> (k  r))
>>-↓ n k 0 p = nil
>>-↓ n k (S r) p = (r + k) :⟨ p ⟩: (>>-↓ n k r (≤-down p))

>>-++ : {n : } -> {l1 l2 : Listℕ} -> n >> l1 -> n >> l2 -> n >> (l1 ++ l2)
>>-++ {n} {nil} {l2} ll1 ll2 = ll2
>>-++ {n} {x  l1} {l2} (.x :⟨ p ⟩: ll1) ll2 = x :⟨ p ⟩: (>>-++ ll1 ll2)

>>-S : {n : } -> {l : Listℕ} -> (n >> l) -> ((S n) >> l)
>>-S  nil = nil
>>-S  (k :⟨ p ⟩: l') = k :⟨ ≤-up p ⟩: >>-S l'

>>-rev : {n : } -> {l : Listℕ} -> (n >> l) -> (n >> rev l)
>>-rev {n} nil = nil
>>-rev {n} (k :⟨ x ⟩: lp) = >>-++ (>>-rev lp) (k :⟨ x ⟩: nil)

LList :   Type₀
LList n = Σ _  l  n >> l)

>>-implies-> : {n a : } -> {l l1 r1 : Listℕ} -> (n >> l) -> (l == l1 ++ a  r1) -> (a < n)
>>-implies-> {n} {l = .(k  _)} {nil} {r1} (k :⟨ x ⟩: nl) p = transport  e -> e < n) (cut-tail p) x
>>-implies-> {n} {l = x₁  l} {x  l1} {r1} (_ :⟨ _ ⟩: nl) p = >>-implies-> nl (cut-head p)

>>-implies->> : {n : } -> {l l1 m1 r1 : Listℕ} -> (n >> l) -> (l == l1 ++ (m1 ++ r1)) -> n >> m1
>>-implies->> {l = l} {l1 = nil} {m1 = nil} nl p = nil
>>-implies->> {n} {l = .(k  _)} {l1 = nil} {m1 = x  m1} (k :⟨ x₁ ⟩: nl) p = 
  x :⟨ transport  e -> e < n) (cut-tail p) x₁ ⟩: >>-implies->> {_} {_} {nil} {m1} {_} nl (cut-head p)
>>-implies->> {l = x₁  l} {l1 = x  l1} {m1 = m1} (.x₁ :⟨ x₂ ⟩: nl) p = >>-implies->> {_} {l} {l1} {m1} nl (cut-head p)

-- _:⟨⟩:_ : {m : ℕ} -> Fin m -> LList m -> LList m
-- (x , xp) :⟨⟩: (xs , xsp) = (x ∷ xs) , (x :⟨ –> <N≃< xp ⟩: xsp)

head+tail>> : {n a : } -> (ap1 : a < n) -> (ap2 : a < n) -> {l : Listℕ} -> {lp1 : n >> l} -> {lp2 : n >> l} -> (lp1 == lp2) -> (a :⟨ ap1 ⟩: lp1) == (a :⟨ ap2 ⟩: lp2)
head+tail>> {a = a} ap1 ap2 {lp1 = lp1} {lp2 = lp2} pl = ap  e -> (a :⟨ ap1 ⟩: e)) pl  ap  e -> a :⟨ e ⟩: lp2) (≤-has-all-paths ap1 ap2)

>>-eq : {n : } -> {l : Listℕ} -> (lp1 : n >> l) -> (lp2 : n >> l) -> (lp1 == lp2)
>>-eq nil nil = idp
>>-eq (k :⟨ kp1 ⟩: lp1) (.k :⟨ kp2 ⟩: lp2) = head+tail>> kp1 kp2 (>>-eq lp1 lp2)

>>-eq-d : {n : } -> {l1 l2 : Listℕ} -> (p : l1 == l2) -> (lp1 : n >> l1) -> (lp2 : n >> l2) -> PathOver (_>>_ n) p lp1 lp2
>>-eq-d {n} idp lp1 lp2 = >>-eq lp1 lp2

LList-eq : {n : } -> {l1 l2 : LList n} -> ((l1 .fst) == (l2 .fst)) -> (l1 == l2)
LList-eq {n} {l1} {l2} p = pair= p (>>-eq-d p (l1 .snd) (l2 .snd))

LList-rev : {n : } -> (l1 : LList n) -> LList n
LList-rev (l , lp) = (rev l) , (>>-rev lp)