module Implicit.Decl.Trans where

open import Implicit.Language.All
open import Implicit.Decl.Subtyping


s-trans' : Γ ⊢d j # A  B
         Γ ⊢d j # B  C
         Γ ⊢d j # A  C
s-trans' (s-refl regΔ cloA) (s-refl regΔ₁ cloA₁) = s-refl regΔ cloA₁
s-trans' (s-int regΔ) (s-int regΔ₁) = s-int regΔ
s-trans' (s-var-∙ regΔ inΔ) (s-var-∙ regΔ₁ inΔ₁) = s-var-∙ regΔ inΔ₁
s-trans' (s-arr₁ s1 s3) (s-arr₁ s2 s4) = s-arr₁ (s-trans' s2 s1) (s-trans' s3 s4)
s-trans' (s-arr₂ s1 s3) (s-arr₂ s2 s4) = s-arr₂ (s-trans' s2 s1) (s-trans' s3 s4)
s-trans' (s-arr₃ regA s1) (s-arr₃ regA₁ s2) = s-arr₃ regA (s-trans' s1 s2)
s-trans' (s-∀ s1) (s-∀ s2) = s-∀ (s-trans' s1 s2)
s-trans' (s-∀l regB st s1 fd) (s-arr₂ s2 s3) = s-∀l regB st (s-trans' s1 (s-arr₂ s2 s3)) fd
s-trans' (s-∀l regB st s1 fd) (s-arr₃ regA s2) = s-∀l regB st (s-trans' s1 (s-arr₃ regA s2)) fd
s-trans' (s-∀l-no-appear regB st s1 fd) (s-arr₂ s2 s3) = s-∀l-no-appear regB st (s-trans' s1 (s-arr₂ s2 s3)) fd
s-trans' (s-∀l-no-appear regB st s1 fd) (s-arr₃ regA s2) = s-∀l-no-appear regB st (s-trans' s1 (s-arr₃ regA s2)) fd


infix 3 _≋_
data _≋_ : Mask  Mask  Set where
  Z≋ :  {nj}
        `■  nj
  S≋ :  {nj}
        j  nj
      (i · j)  (i · nj)
  refl≋ : j  j

≋-isoinf :  {nj}
          j  nj
          □like j
          □like nj
≋-isoinf (S≋ refl≋) □like-Z = □like-Z
≋-isoinf (S≋ nj) (□like-S wlike) = □like-S (≋-isoinf nj wlike)
≋-isoinf refl≋ wlike = wlike

find-≋ :  {nj}
        find A k j
        j  nj
        find A k nj
find-≋ (f-arr-l x) (S≋ ~j) = f-arr-l x
find-≋ (f-arr-r ¬inA fd) (S≋ ~j) = f-arr-r ¬inA (find-≋ fd ~j)
find-≋ (f-∀ fd) (S≋ {nj = nj} ~j)
  = f-∀ (find-≋ fd (S≋ ~j))
find-≋ (f-iso iso) (S≋ ~j) = f-iso (≋-isoinf (S≋ ~j) iso)
find-≋ (f-iso iso) refl≋ = f-iso iso
find-≋ fd refl≋ = fd

s-trans-∞ : Γ ⊢d `□ # A  B
           Γ ⊢d `□ # B  C
           Γ ⊢d `□ # A  C
s-trans-∞ (s-int regΔ) (s-int regΔ₁) = s-int regΔ
s-trans-∞ (s-var-∙ regΔ inΔ) s2 = s2
s-trans-∞ (s-arr₁ s1 s3) (s-arr₁ s2 s4) = s-arr₁ (s-trans-∞ s2 s1) (s-trans-∞ s3 s4)
s-trans-∞ (s-∀ s1) (s-∀ s2) = s-∀ (s-trans-∞ s1 s2)

s-trans-∞-eq : Γ ⊢d `□ # A  B
              A  B
s-trans-∞-eq (s-int regΔ) = refl
s-trans-∞-eq (s-var-∙ regΔ inΔ) = refl
s-trans-∞-eq (s-arr₁ s s₁) = cong₂ _`→_ (sym (s-trans-∞-eq s)) (s-trans-∞-eq s₁)
s-trans-∞-eq (s-∀ s) = cong `∀_ (s-trans-∞-eq s)


s-refl-∞ : SRegular Γ
          Γ ⊢r A
          Γ ⊢d `□ # A  A
s-refl-∞ regΓ ⊢r-int = s-int regΓ
s-refl-∞ regΓ (⊢r-var-∙ inΓ) = s-var-∙ regΓ inΓ
s-refl-∞ regΓ (⊢r-arr regA regA₁) = s-arr₁ (s-refl-∞ regΓ regA) (s-refl-∞ regΓ regA₁)
s-refl-∞ regΓ (⊢r-∀ regA) = s-∀ (s-refl-∞ (reg-S∙ regΓ) regA)

s-trans : Γ ⊢d j # A  B
         j  j'
         Γ ⊢d j' # B  C
         Γ ⊢d j' # A  C
s-trans (s-refl regΔ cloA) ~j s2 = s2
s-trans (s-arr₂ s1 s3) (S≋ ~j) (s-arr₂ s2 s4) = s-arr₂ (s-trans-∞ s2 s1) (s-trans s3 ~j s4)
s-trans (s-arr₃ regA s1) (S≋ ~j) (s-arr₃ regA₁ s2) = s-arr₃ regA (s-trans s1 ~j s2)
s-trans (s-∀l regB st s1 fd) (S≋ {nj = nj} ~j) (s-arr₂ s2 s3)
  = s-∀l regB st (s-trans s1 (S≋ ~j) (s-arr₂ s2 s3)) (find-≋ fd (S≋ ~j))
s-trans (s-∀l-no-appear regB st s1 fd) (S≋ ~j) (s-arr₃ regA s3)
  = s-∀l-no-appear regB st (s-trans s1 (S≋ ~j) (s-arr₃ regA s3)) fd
s-trans s1 refl≋ s2 = s-trans' s1 s2
s-trans (s-∀l regB st x fd) (S≋ x₁) (s-arr₃ regA x₂)
  = s-∀l regB st (s-trans x (S≋ x₁) (s-arr₃ regA x₂)) (find-≋ fd (S≋ x₁))
s-trans (s-∀l-no-appear regB st x fd) (S≋ x₁) (s-arr₂ x₂ x₃)
  = s-∀l-no-appear regB st (s-trans x (S≋ x₁) (s-arr₂ x₂ x₃)) fd