module Implicit.Algo.Properties.OpenK where
open import Implicit.Language.All
open import Implicit.Algo.Base
open import Implicit.Algo.Properties.Extension
open import Implicit.Algo.Properties.Regularity
open import Implicit.Algo.Properties.Irrelevance
infix 3 _∤_⊢oˣ_
data _∤_⊢oˣ_ : Env n m → Fin (1 + m) → Fin m → Set where
opnx= : Γ ∋= X
→ Γ ∤ k ⊢oˣ X
opnx∙ : Γ ∋∙ X
→ Γ ∤ k ⊢oˣ X
opnx^ : Γ ∋^ X
→ X #< k
→ Γ ∤ k ⊢oˣ X
infix 3 _∤_⊢o_
data _∤_⊢o_ : Env n m → Fin (1 + m) → Type m → Set where
opn-int : Γ ∤ k ⊢o Int
opn-var : Γ ∤ k ⊢oˣ X
→ Γ ∤ k ⊢o ‶ X
opn-arr : Γ ∤ k ⊢o A
→ Γ ∤ k ⊢o B
→ Γ ∤ k ⊢o A `→ B
opn-∀ : Γ ,∙ ∤ #S k ⊢o A
→ Γ ∤ k ⊢o `∀ A
⊢oˣ-∋^-#< : Γ ∤ k ⊢oˣ X
→ Γ ∋^ X
→ X #< k
⊢oˣ-∋^-#< (opnx= x) inΓ = ⊥-elim (∋^-∋=-false inΓ x)
⊢oˣ-∋^-#< (opnx∙ x) inΓ = ⊥-elim (∋^-∋∙-false inΓ x)
⊢oˣ-∋^-#< (opnx^ x x₁) inΓ = x₁
⊢oˣ-⊆ : Γ ∤ k ⊢oˣ X
→ Γ ⊆ Δ
→ Δ ∤ k ⊢oˣ X
⊢oˣ-⊆ (opnx= x) ext = opnx= (⊆-∋= x ext)
⊢oˣ-⊆ (opnx∙ x) ext = opnx∙ (⊆-∋∙ x ext)
⊢oˣ-⊆ {X = X} (opnx^ {k = k} x x₁) ext with s-⊆-exsol ext x
... | is-ex inΓ = opnx^ inΓ x₁
... | is-sol inΓ = opnx= inΓ
⊢ok-⊆ : Γ ∤ k ⊢o A
→ Γ ⊆ Δ
→ Δ ∤ k ⊢o A
⊢ok-⊆ opn-int ext = opn-int
⊢ok-⊆ (opn-var x) ext = opn-var (⊢oˣ-⊆ x ext)
⊢ok-⊆ (opn-arr opnA opnA₁) ext = opn-arr (⊢ok-⊆ opnA ext) (⊢ok-⊆ opnA₁ ext)
⊢ok-⊆ (opn-∀ opnA) ext = opn-∀ (⊢ok-⊆ opnA (uvar ext))
⊢c-⊢ok : Γ ⊢c A
→ Γ ∤ k ⊢o A
⊢c-⊢ok ⊢c-int = opn-int
⊢c-⊢ok (⊢c-var-∙ inΔ) = opn-var (opnx∙ inΔ)
⊢c-⊢ok (⊢c-var-= inΔ) = opn-var (opnx= inΔ)
⊢c-⊢ok (⊢c-arr cloA cloA₁) = opn-arr (⊢c-⊢ok cloA) (⊢c-⊢ok cloA₁)
⊢c-⊢ok (⊢c-∀ cloA) = opn-∀ (⊢c-⊢ok cloA)
⊢r-⊢ok : Γ ⊢r A
→ Γ ∤ k ⊢o A
⊢r-⊢ok regA = ⊢c-⊢ok (⊢r-⊢c regA)
◈-∋∙-⊢oˣ : Γ ∋∙ X
→ Γ ◈ k' ⇘ Γ'
→ k' #< k
→ Γ' ∤ k ⊢oˣ X
◈-∋∙-⊢oˣ Z ◈Z lt = opnx^ Z lt
◈-∋∙-⊢oˣ Z (◈S∙ new) lt = opnx∙ Z
◈-∋∙-⊢oˣ (S, inΓ) (◈S, new) lt with ◈-∋∙-⊢oˣ inΓ new lt
... | opnx= x = opnx= (S, x)
... | opnx∙ x = opnx∙ (S, x)
... | opnx^ x x₁ = opnx^ (S, x) x₁
◈-∋∙-⊢oˣ (S∙ inΓ) ◈Z lt = opnx∙ (S^ inΓ)
◈-∋∙-⊢oˣ {k = #S k} (S∙ inΓ) (◈S∙ new) (s≤s lt) with ◈-∋∙-⊢oˣ inΓ new lt
... | opnx= x = opnx= (S∙ x)
... | opnx∙ x = opnx∙ (S∙ x)
... | opnx^ x x₁ = opnx^ (S∙ x) (s≤s x₁)
◈-∋∙-⊢oˣ {k = #S k} (S= inΓ) (◈S= new) (s≤s lt) with ◈-∋∙-⊢oˣ inΓ new lt
... | opnx= x = opnx= (S= x)
... | opnx∙ x = opnx∙ (S= x)
... | opnx^ x x₁ = opnx^ (S= x) (s≤s x₁)
◈-∋∙-⊢oˣ {k = #S k} (S^ inΓ) (◈S^ new) (s≤s lt) with ◈-∋∙-⊢oˣ inΓ new lt
... | opnx= x = opnx= (S^ x)
... | opnx∙ x = opnx∙ (S^ x)
... | opnx^ x x₁ = opnx^ (S^ x) (s≤s x₁)
◈-∋= : Γ ∋= X
→ Γ ◈ k' ⇘ Γ'
→ Γ' ∋= X
◈-∋= Z (◈S= new) = Z
◈-∋= (S∙ inΓ) ◈Z = S^ inΓ
◈-∋= (S∙ inΓ) (◈S∙ new) = S∙ (◈-∋= inΓ new)
◈-∋= (S^ inΓ) (◈S^ new) = S^ (◈-∋= inΓ new)
◈-∋= (S= inΓ) (◈S= new) = S= (◈-∋= inΓ new)
◈-∋= (S, inΓ) (◈S, new) = S, (◈-∋= inΓ new)
◈-∋^ : Γ ∋^ X
→ Γ ◈ k' ⇘ Γ'
→ Γ' ∋^ X
◈-∋^ Z (◈S^ new) = Z
◈-∋^ (S∙ inΓ) ◈Z = S^ inΓ
◈-∋^ (S∙ inΓ) (◈S∙ new) = S∙ (◈-∋^ inΓ new)
◈-∋^ (S= inΓ) (◈S= new) = S= (◈-∋^ inΓ new)
◈-∋^ (S^ inΓ) (◈S^ new) = S^ (◈-∋^ inΓ new)
◈-∋^ (S, inΓ) (◈S, new) = S, (◈-∋^ inΓ new)
⊢oˣ-◈ : Γ ∤ k ⊢oˣ X
→ k' #< k
→ Γ ◈ k' ⇘ Γ'
→ Γ' ∤ k ⊢oˣ X
⊢oˣ-◈ (opnx= x) lt new = opnx= (◈-∋= x new)
⊢oˣ-◈ (opnx∙ x) lt new = ◈-∋∙-⊢oˣ x new lt
⊢oˣ-◈ (opnx^ x x₁) lt new = opnx^ (◈-∋^ x new) x₁
⊢ok-◈ : Γ ∤ k ⊢o A
→ k' #< k
→ Γ ◈ k' ⇘ Γ'
→ Γ' ∤ k ⊢o A
⊢ok-◈ opn-int lt new = opn-int
⊢ok-◈ (opn-var x) lt new = opn-var (⊢oˣ-◈ x lt new)
⊢ok-◈ (opn-arr opnA opnA₁) lt new = opn-arr (⊢ok-◈ opnA lt new) (⊢ok-◈ opnA₁ lt new)
⊢ok-◈ (opn-∀ opnA) lt new = opn-∀ (⊢ok-◈ opnA (s≤s lt) (◈S∙ new))
⊢ok-◈0 : Γ ,∙ ∤ #S k ⊢o A
→ Γ ,^ ∤ #S k ⊢o A
⊢ok-◈0 opnA = ⊢ok-◈ opnA (s≤s z≤n) ◈Z
∙⟹-∋= : Γ ∋= k
→ [ B / k' ] Γ ∙⟹ Γ'
→ Γ' ∋= k
∙⟹-∋= Z (∙⟹=S new up1) = Z
∙⟹-∋= (S∙ inΓ) (∙⟹^0 up regA) = S= inΓ
∙⟹-∋= (S∙ inΓ) (∙⟹∙S new up1) = S∙ (∙⟹-∋= inΓ new)
∙⟹-∋= (S^ inΓ) (∙⟹^S new up1) = S^ (∙⟹-∋= inΓ new)
∙⟹-∋= (S= inΓ) (∙⟹=S new up1) = S= (∙⟹-∋= inΓ new)
∙⟹-∋= (S, inΓ) (∙⟹,S new) = S, (∙⟹-∋= inΓ new)
∙⟹-∋^ : Γ ∋^ k
→ [ B / k' ] Γ ∙⟹ Γ'
→ Γ' ∋^ k
∙⟹-∋^ Z (∙⟹^S new up1) = Z
∙⟹-∋^ (S∙ inΓ) (∙⟹^0 up regA) = S= inΓ
∙⟹-∋^ (S∙ inΓ) (∙⟹∙S new up1) = S∙ (∙⟹-∋^ inΓ new)
∙⟹-∋^ (S= inΓ) (∙⟹=S new up1) = S= (∙⟹-∋^ inΓ new)
∙⟹-∋^ (S^ inΓ) (∙⟹^S new up1) = S^ (∙⟹-∋^ inΓ new)
∙⟹-∋^ (S, inΓ) (∙⟹,S new) = S, (∙⟹-∋^ inΓ new)
∙⟹-∋∙' : Γ ∋∙ k
→ [ A / k ] Γ ∙⟹ Γ'
→ Γ' ∋= k
∙⟹-∋∙' Z (∙⟹^0 up regA) = Z
∙⟹-∋∙' (S, inΓ) (∙⟹,S new) = S, (∙⟹-∋∙' inΓ new)
∙⟹-∋∙' (S∙ inΓ) (∙⟹∙S new up1) = S∙ (∙⟹-∋∙' inΓ new)
∙⟹-∋∙' (S= inΓ) (∙⟹=S new up1) = S= (∙⟹-∋∙' inΓ new)
∙⟹-∋∙' (S^ inΓ) (∙⟹^S new up1) = S^ (∙⟹-∋∙' inΓ new)
⊢ok-∙⟹ : Γ ∤ k ⊢o A
→ [ B / k' ] Γ ∙⟹ Γ'
→ Γ' ∤ k ⊢o A
⊢ok-∙⟹ opn-int new = opn-int
⊢ok-∙⟹ (opn-var (opnx= x)) new = opn-var (opnx= (∙⟹-∋= x new))
⊢ok-∙⟹ {k' = k'} (opn-var (opnx∙ {X = X} x)) new with X #≟ k'
... | yes refl = opn-var (opnx= (∙⟹-∋∙' x new))
... | no ¬p = opn-var (opnx∙ (∙⟹-∋∙ x ¬p new))
⊢ok-∙⟹ (opn-var (opnx^ x x₁)) new = opn-var (opnx^ (∙⟹-∋^ x new) x₁)
⊢ok-∙⟹ (opn-arr opnA opnA₁) new = opn-arr (⊢ok-∙⟹ opnA new) (⊢ok-∙⟹ opnA₁ new)
⊢ok-∙⟹ {B = B} (opn-∀ opnA) new = opn-∀ (⊢ok-∙⟹ opnA (∙⟹∙S new (proj₂ (↑ty0-total B))))
⊢ok-∙⟹0 : Γ ,∙ ∤ #S k ⊢o A
→ Γ ⊢r B
→ Γ ,= B ∤ #S k ⊢o A
⊢ok-∙⟹0 {B = B} opnA regB = ⊢ok-∙⟹ opnA (∙⟹^0 (proj₂ (↑ty0-total B)) regB)