module Implicit.Algo.Properties.Shift where

open import Implicit.Language.All
open import Implicit.Algo.Base

↑tmᶜ-total :  (Σ : Context n m) (k)
    λ Σ'
   Σ ↑tmᶜ k  Σ'
↑tmᶜ-total  k =   , ↑tmᶜ-□ 
↑tmᶜ-total (τ A) k =  τ A , ↑tmᶜ-τ 
↑tmᶜ-total ([ e ]↝ Σ) k with ↑tm-total e k | ↑tmᶜ-total Σ k
... |  e' , up-e  |  Σ' , up-Σ  =  [ e' ]↝ Σ' , ↑tmᶜ-e up-e up-Σ 

↑tmᶜ0-total :  (Σ : Context n m)
    λ Σ'
   ↑tmᶜ0 Σ  Σ'
↑tmᶜ0-total Σ = ↑tmᶜ-total Σ #0

↑tmᶜ-unique : Σ ↑tmᶜ k  Σ₁
             Σ ↑tmᶜ k  Σ₂
             Σ₁  Σ₂
↑tmᶜ-unique ↑tmᶜ-□ ↑tmᶜ-□ = refl
↑tmᶜ-unique ↑tmᶜ-τ ↑tmᶜ-τ = refl
↑tmᶜ-unique (↑tmᶜ-e up-e up1) (↑tmᶜ-e up-e₁ up2) rewrite ↑tm-unique up-e up-e₁ | ↑tmᶜ-unique up1 up2 = refl

↑tyᶜ-total :  (Σ : Context n m) (k)
    λ Σ'
   Σ ↑tyᶜ k  Σ'
↑tyᶜ-total  k =   , ↑tyᶜ-□ 
↑tyᶜ-total (τ A) k with ↑ty-total A k
... |  A' , upA  =  τ A' , ↑tyᶜ-τ upA 
↑tyᶜ-total ([ e ]↝ Σ) k with ↑tyᵉ-total e k | ↑tyᶜ-total Σ k
... |  e' , upe  |  Σ' , upΣ  =  [ e' ]↝ Σ' , ↑tyᶜ-e upe upΣ 

↑tyᶜ0-total :  (Σ : Context n m)
    λ Σ'
   ↑tyᶜ0 Σ  Σ'
↑tyᶜ0-total Σ = ↑tyᶜ-total Σ #0


↑tm-↑tyᵉ-comm' : e ↑tm k₁  e₁
                 e ↑tyᵉ k₂  e'
                 e' ↑tm k₁  e₂
                 e₁ ↑tyᵉ k₂  e₂
↑tm-↑tyᵉ-comm' ↑tm-lit ↑tyᵉ-lit ↑tm-lit = ↑tyᵉ-lit
↑tm-↑tyᵉ-comm' ↑tm-var ↑tyᵉ-var ↑tm-var = ↑tyᵉ-var
↑tm-↑tyᵉ-comm' (↑tm-ƛ up1) (↑tyᵉ-ƛ up2) (↑tm-ƛ up3) = ↑tyᵉ-ƛ (↑tm-↑tyᵉ-comm' up1 up2 up3)
↑tm-↑tyᵉ-comm' (↑tm-app up1 up4) (↑tyᵉ-app up2 up5) (↑tm-app up3 up6) = ↑tyᵉ-app (↑tm-↑tyᵉ-comm' up1 up2 up3) (↑tm-↑tyᵉ-comm' up4 up5 up6)
↑tm-↑tyᵉ-comm' (↑tm-⦂ up1) (↑tyᵉ-⦂ up2 up) (↑tm-⦂ up3) = ↑tyᵉ-⦂ (↑tm-↑tyᵉ-comm' up1 up2 up3) up
↑tm-↑tyᵉ-comm' (↑tm-Λ up1) (↑tyᵉ-Λ up2) (↑tm-Λ up3) = ↑tyᵉ-Λ (↑tm-↑tyᵉ-comm' up1 up2 up3)
↑tm-↑tyᵉ-comm' (↑tm-⓪ up1) (↑tyᵉ-⓪ up2 upA) (↑tm-⓪ up3) = ↑tyᵉ-⓪ (↑tm-↑tyᵉ-comm' up1 up2 up3) upA

↑tmᶜ-↑tyᶜ-comm' : Σ ↑tmᶜ k₁  Σ₁
                 Σ ↑tyᶜ k₂  Σ'
                 Σ' ↑tmᶜ k₁  Σ₂
                 Σ₁ ↑tyᶜ k₂  Σ₂
↑tmᶜ-↑tyᶜ-comm' ↑tmᶜ-□ ↑tyᶜ-□ ↑tmᶜ-□ = ↑tyᶜ-□
↑tmᶜ-↑tyᶜ-comm' ↑tmᶜ-τ (↑tyᶜ-τ up-t) ↑tmᶜ-τ = ↑tyᶜ-τ up-t
↑tmᶜ-↑tyᶜ-comm' (↑tmᶜ-e up-e up1) (↑tyᶜ-e up-e₁ up2) (↑tmᶜ-e up-e₂ up3) = ↑tyᶜ-e (↑tm-↑tyᵉ-comm' up-e up-e₁ up-e₂) (↑tmᶜ-↑tyᶜ-comm' up1 up2 up3)


↑tyᶜ-comm0' :  {Σ : Context n m} {Σₖ Σₖ₊₁ Σ₀ k}
               Σ ↑tyᶜ k  Σₖ
               ↑tyᶜ0 Σₖ  Σₖ₊₁
              ---------------------
               ↑tyᶜ0 Σ  Σ₀
               Σ₀ ↑tyᶜ #S k  Σₖ₊₁
↑tyᶜ-comm0' ↑tyᶜ-□ ↑tyᶜ-□ ↑tyᶜ-□ = ↑tyᶜ-□
↑tyᶜ-comm0' (↑tyᶜ-τ up-t) (↑tyᶜ-τ up-t₁) (↑tyᶜ-τ up-t₂) = ↑tyᶜ-τ (↑ty-comm0' up-t up-t₁ up-t₂)
↑tyᶜ-comm0' (↑tyᶜ-e up-e up1) (↑tyᶜ-e up-e₁ up2) (↑tyᶜ-e up-e₂ up3) = ↑tyᶜ-e (↑tyᵉ-comm0' up-e up-e₁ up-e₂) (↑tyᶜ-comm0' up1 up2 up3)


↑tm-↑tyᵉ-comm : e ↑tm k₁  e₁
              e₁ ↑tyᵉ k₂  e₂
              e ↑tyᵉ k₂  e'
              e' ↑tm k₁  e₂
↑tm-↑tyᵉ-comm ↑tm-lit ↑tyᵉ-lit ↑tyᵉ-lit = ↑tm-lit
↑tm-↑tyᵉ-comm ↑tm-var ↑tyᵉ-var ↑tyᵉ-var = ↑tm-var
↑tm-↑tyᵉ-comm (↑tm-ƛ up1) (↑tyᵉ-ƛ up2) (↑tyᵉ-ƛ up3) = ↑tm-ƛ (↑tm-↑tyᵉ-comm up1 up2 up3)
↑tm-↑tyᵉ-comm (↑tm-app up1 up4) (↑tyᵉ-app up2 up5) (↑tyᵉ-app up3 up6) = ↑tm-app (↑tm-↑tyᵉ-comm up1 up2 up3) (↑tm-↑tyᵉ-comm up4 up5 up6)
↑tm-↑tyᵉ-comm (↑tm-⦂ up1) (↑tyᵉ-⦂ up2 up) (↑tyᵉ-⦂ up3 up₁) with refl↑ty-unique up₁ up = ↑tm-⦂ (↑tm-↑tyᵉ-comm up1 up2 up3)
↑tm-↑tyᵉ-comm (↑tm-Λ up1) (↑tyᵉ-Λ up2) (↑tyᵉ-Λ up3) = ↑tm-Λ (↑tm-↑tyᵉ-comm up1 up2 up3)
↑tm-↑tyᵉ-comm (↑tm-⓪ up1) (↑tyᵉ-⓪ up2 upA) (↑tyᵉ-⓪ up3 upA₁) with refl↑ty-unique upA upA₁ = ↑tm-⓪ (↑tm-↑tyᵉ-comm up1 up2 up3)

↑tmᶜ-↑tyᶜ-comm : Σ ↑tmᶜ k₁  Σ₁
                Σ₁ ↑tyᶜ k₂  Σ₂
                Σ ↑tyᶜ k₂  Σ'
                Σ' ↑tmᶜ k₁  Σ₂
↑tmᶜ-↑tyᶜ-comm ↑tmᶜ-□ ↑tyᶜ-□ ↑tyᶜ-□ = ↑tmᶜ-□
↑tmᶜ-↑tyᶜ-comm ↑tmᶜ-τ (↑tyᶜ-τ up-t) (↑tyᶜ-τ up-t₁) with refl↑ty-unique up-t up-t₁ = ↑tmᶜ-τ
↑tmᶜ-↑tyᶜ-comm (↑tmᶜ-e up-e up1) (↑tyᶜ-e up-e₁ up2) (↑tyᶜ-e up-e₂ up3) = ↑tmᶜ-e (↑tm-↑tyᵉ-comm up-e up-e₁ up-e₂) (↑tmᶜ-↑tyᶜ-comm up1 up2 up3)

↑tmᶜ-comm' : k₁ #≤ k₂
            Σ ↑tmᶜ k₂  Σ₁
            Σ₁ ↑tmᶜ (inject₁ k₁)  Σ₂
           ----------------
            Σ ↑tmᶜ k₁  Σ'
            Σ' ↑tmᶜ #S k₂  Σ₂
↑tmᶜ-comm' lt ↑tmᶜ-□ ↑tmᶜ-□ ↑tmᶜ-□ = ↑tmᶜ-□
↑tmᶜ-comm' lt ↑tmᶜ-τ ↑tmᶜ-τ ↑tmᶜ-τ = ↑tmᶜ-τ
↑tmᶜ-comm' lt (↑tmᶜ-e up-e up1) (↑tmᶜ-e up-e₁ up2) (↑tmᶜ-e up-e₂ up3) = ↑tmᶜ-e (↑tm-comm' lt up-e up-e₁ up-e₂) (↑tmᶜ-comm' lt up1 up2 up3)

nonempty-↑tmᶜ' : NonEmpty Σ'
               Σ ↑tmᶜ k  Σ'
               NonEmpty Σ
nonempty-↑tmᶜ' ne-τ ↑tmᶜ-τ = ne-τ
nonempty-↑tmᶜ' ne-app (↑tmᶜ-e up-e upΣ) = ne-app

nonempty-↑tmᶜ : NonEmpty Σ
               Σ ↑tmᶜ k  Σ'
               NonEmpty Σ'
nonempty-↑tmᶜ ne-τ ↑tmᶜ-τ = ne-τ
nonempty-↑tmᶜ ne-app (↑tmᶜ-e up-e upΣ) = ne-app


nonempty-↑tyᶜ : NonEmpty Σ'
               Σ ↑tyᶜ k  Σ'
               NonEmpty Σ
nonempty-↑tyᶜ ne-τ (↑tyᶜ-τ up-t) = ne-τ
nonempty-↑tyᶜ ne-app (↑tyᶜ-e up-e upΣ) = ne-app

nonempty-↑tyᶜ' : NonEmpty Σ
                Σ ↑tyᶜ k  Σ'
                NonEmpty Σ'
nonempty-↑tyᶜ' ne-τ (↑tyᶜ-τ up-t) = ne-τ
nonempty-↑tyᶜ' ne-app (↑tyᶜ-e up-e upΣ) = ne-app

gc-↑tyᵉ : GenericConsumer e
         e ↑tyᵉ k  e'
         GenericConsumer e'
gc-↑tyᵉ gc-i ↑tyᵉ-lit = gc-i
gc-↑tyᵉ gc-var ↑tyᵉ-var = gc-var
gc-↑tyᵉ gc-ann (↑tyᵉ-⦂ upe up) = gc-ann
gc-↑tyᵉ gc-tlam (↑tyᵉ-Λ upe) = gc-tlam