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

open import lib.Base
open import lib.PathGroupoid
open import lib.PathFunctor
open import lib.PathOver
open import lib.NType

module lib.cubical.PathPathOver where

module _ {i j} {A : Type i} {B : A  Type j} where

  -- fillers of a hollow closed cylinder wrapped by two pathovers
  PPOver : {x y : A} {p₁ p₂ : x == y} (q : p₁ == p₂) {u : B x} {v : B y}
    (d : u == v [ B  p₁ ]) (e : u == v [ B  p₂ ])  Type j
  PPOver idp d e = d == e

  {-
    One may also view PPOver as the type of
    fillers of the 2-sphere with its two poles
    pinched together.
  -}

  -- PPOver for a family of sets is always inhabited.
  PPOver-0type : {{ρ : {a : A}  has-level 0 (B a)}}
    {x y : A} {p₁ p₂ : x == y} {q : p₁ == p₂}
    {u : B x} {v : B y}
    (d : u == v [ B  p₁ ]) (e : u == v [ B  p₂ ])
     PPOver q d e
  PPOver-0type {p₁ = idp} {q = idp} d e = prop-has-all-paths d e

  apᶜ² : {x y : A} {p₁ p₂ : x == y} {q : p₁ == p₂} {u : B x} {v : B y}
    {d₁ d₂ : u == v [ B  p₁ ]} {e₁ e₂ : u == v [ B  p₂ ]}
     d₁ == d₂  e₁ == e₂  PPOver q d₁ e₁  PPOver q d₂ e₂
  apᶜ² {q = idp} c₁ c₂ po = ! c₁  po  c₂

  apdd : (f : (a : A)  B a) {x y : A} {τ₁ τ₂ : x == y}
    (p : τ₁ == τ₂)  PPOver p (apd f τ₁) (apd f τ₂)
  apdd f {τ₁ = idp} idp = idp

  apdd-∙ᵈ : (f : (a : A)  B a) {x y z : A} {τ₃ : x == z} (τ₁ : x == y) (τ₂ : y == z)
    (p : τ₁  τ₂ == τ₃)  PPOver p (apd f τ₁ ∙ᵈ apd f τ₂) (apd f τ₃)
  apdd-∙ᵈ f idp idp idp = idp

  -- associativity of pathovers (similar to ∙ᵈ-assoc in PathGroupoid.agda)
  ∙ᵈ-assoc-ppo : {x y z w : A} {p₁ : x == y} {p₂ : y == z} {p₃ : z == w}
    {b₀ : B x} {b₁ : B y} {b₂ : B z} {b₃ : B w}
    (d₁ : b₀ == b₁ [ B  p₁ ]) (d₂ : b₁ == b₂ [ B  p₂ ]) (d₃ : b₂ == b₃ [ B  p₃ ])
     PPOver (∙-assoc p₁ p₂ p₃) ((d₁ ∙ᵈ d₂) ∙ᵈ d₃) (d₁ ∙ᵈ (d₂ ∙ᵈ d₃))
  ∙ᵈ-assoc-ppo {p₁ = idp} {p₂ = idp} {p₃ = idp} d₁ d₂ d₃ = ∙-assoc d₁ d₂ d₃

  -- small generalization of PPOver (fillers of a hollow closed 3-dim triangle)
  PPOverTri : {x y : A} {p₁ p₂ : x == y} {u : B x} {v₁ v₂ : B y} (r : v₁ == v₂)
    (q : p₁ == p₂) (d : u == v₁ [ B  p₁ ]) (e : u == v₂ [ B  p₂ ])  Type j
  PPOverTri idp q d e = PPOver q d e

  -- basic operations on PPOver

  infixr 50 _∙ᶜ_
  _∙ᶜ_ : {x y : A} {p₁ p₂ p₃ : x == y} {q₁ : p₁ == p₂} {q₂ : p₂ == p₃}
    {u : B x} {v : B y}
    {d : u == v [ B  p₁ ]} {e : u == v [ B  p₂ ]} {j : u == v [ B  p₃ ]}
     PPOver q₁ d e  PPOver q₂ e j  PPOver (q₁  q₂) d j
  _∙ᶜ_ {q₁ = idp} {q₂ = idp} po₁ po₂ = po₁  po₂

  !ᶜ : {x y : A} {p₁ p₂ : x == y} {q : p₁ == p₂} {u : B x} {v : B y}
    {d : u == v [ B  p₁ ]} {e : u == v [ B  p₂ ]}
     PPOver q d e  PPOver (! q) e d
  !ᶜ {q = idp} po = ! po

  ap-∙-preᶜ : {x y z : A} {p₁ p₂ : x == y} {r : z == x} {q : p₁ == p₂}
    {u : B x} {v : B y} {w : B z}
    {d₁ : u == v [ B  p₁ ]} {d₂ : u == v [ B  p₂ ]} (e : w == u [ B  r ])
     PPOver q d₁ d₂  PPOver (ap  p  r  p) q) (e ∙ᵈ d₁) (e ∙ᵈ d₂)
  ap-∙-preᶜ {p₁ = idp} {r = idp} {q = idp} e po = ap  p  e  p) po
  
  ap-∙-postᶜ : {x y z : A} {p₁ p₂ : x == y} {r : y == z} {q : p₁ == p₂}
    {u : B x} {v : B y} {w : B z}
    {d₁ : u == v [ B  p₁ ]} {d₂ : u == v [ B  p₂ ]} (e : v == w [ B  r ])
     PPOver q d₁ d₂  PPOver (ap  p  p  r) q) (d₁ ∙ᵈ e) (d₂ ∙ᵈ e)
  ap-∙-postᶜ {p₁ = idp} {r = idp} {q = idp} e po = ap  p  p  e) po

  -- fillers of a hollow 3-dim closed cylinder wrapped by two double pathovers
  PPPOver : {x y : A} {p₁ p₂ : x == y} {q₁ q₂ : p₁ == p₂} {u : B x} {v : B y}
    (r : q₁ == q₂) {d : u == v [ B  p₁ ]} {e : u == v [ B  p₂ ]} 
     PPOver q₁ d e  PPOver q₂ d e  Type j
  PPPOver idp po₁ po₂ = po₁ == po₂

  -- PPPOver for a family of 1-types is always inhabited.
  PPPOver-1type : {{ρ : {a : A}  has-level 1 (B a)}}
    {x y : A} {p₁ p₂ : x == y} {q₁ q₂ : p₁ == p₂} {u : B x} {v : B y}
    (r : q₁ == q₂) {d : u == v [ B  p₁ ]} {e : u == v [ B  p₂ ]} 
    (po₁ : PPOver q₁ d e) (po₂ : PPOver q₂ d e)
     PPPOver r po₁ po₂
  PPPOver-1type {p₁ = idp} {q₁ = idp} idp po₁ po₂ =
    prop-has-all-paths po₁ po₂

  -- sanity check on our definition of apdd-∙ᵈ
  apdd-∙ᵈ=apdd : (f : (a : A)  B a) {x y z : A} {τ₃ : x == z}
    (τ₁ : x == y) (τ₂ : y == z) (p : τ₁  τ₂ == τ₃)
     apdd-∙ᵈ f τ₁ τ₂ p == ! (apd-∙ f τ₁ τ₂) ∙ᶜ apdd f p
  apdd-∙ᵈ=apdd f idp idp idp = idp

module _ {i j k} {A : Type i} {B : A  Type j} {X : Type k} where

  -- applying an X-indexed family of pathovers to a path in X  
  apd-po : {a₁ a₂ : A} {p : X  a₁ == a₂} {u : B a₁} {v : B a₂}
    (f : (x : X)  u == v [ B  p x ]) {x₁ x₂ : X} (q : x₁ == x₂)
     PPOver (ap p q) (f x₁) (f x₂)
  apd-po f idp = idp

-- behavior of higher-dimensional pathovers for constant type families

module _ {i j} {A : Type i} {B : Type j} where

  ppo-cst-in-∙-aux : {y z : A} (p₁ : y == z) (p₂ : y == z)
    {a b c : B} (τ₁ : a == b) {τ₂ : b == c}
     τ₁ ∙ᵈ ↓-cst-in {p = p₁} τ₂ == ↓-cst-in (τ₁  τ₂)
  ppo-cst-in-∙-aux idp p₂ τ₁ = idp

  ppo-cst-in-∙ : {x y z : A} (p₁ : x == y) {p₂ : y == z}
    {p₃ : x == z} {a b c : B} {τ₁ : a == b} {τ₂ : b == c}
    {τ₃ : a == c} (q : p₁  p₂ == p₃) (r : τ₁  τ₂ == τ₃)
     PPOver q (↓-cst-in {p = p₁} τ₁ ∙ᵈ ↓-cst-in τ₂) (↓-cst-in τ₃)
  ppo-cst-in-∙ idp {p₂} {p₃} {τ₁ = τ₁} idp idp = ppo-cst-in-∙-aux p₂ p₃ τ₁

  pppo-cst-in-word-aux2 : {v₁ v₂ v₃ : B} (c₁ : v₁ == v₂) {c₂ : v₂ == v₃} {c₃ : v₃ == v₃}
    {a₀ a₁ a₂ a₃ : A} (d₁ : a₀ == a₁) {d₂ : a₁ == a₂} {d₃ : a₂ == a₃}
    {q : (d₁  d₂)  d₃ == d₁  (d₂  d₃)}
    (r : ∙-assoc d₁ d₂ d₃ == q)
     
    PPPOver (ap  p  p  idp) r)
    (∙ᵈ-assoc-ppo (↓-cst-in {p = d₁} c₁) (↓-cst-in c₂) (↓-cst-in c₃) ∙ᶜ
     ap-∙-preᶜ (↓-cst-in {p = d₁} c₁) (ppo-cst-in-∙ d₂ idp idp) 
     ppo-cst-in-∙ d₁ idp idp)
    (ap-∙-postᶜ (↓-cst-in c₃) (ppo-cst-in-∙ d₁ idp idp) ∙ᶜ
     ppo-cst-in-∙ (d₁  d₂) q (∙-assoc c₁ c₂ c₃  idp) ∙ᶜ idp)
  pppo-cst-in-word-aux2 idp {c₂ = idp} idp {d₂ = idp} {d₃ = idp} idp = idp

  pppo-cst-in-word-aux : {v : B} (c₁ c₂ c₃ : v == v)
    {a : A} (d₁ : a == a) {d₂ d₃ d₄ d₅ d₆ : a == a}
    (q₁ : d₁  d₂ == d₃) (q₂ : d₂  d₅ == d₄)
    (q₃ : d₁  d₄ == d₆) (q₄ : d₃  d₅ == d₆)
    {m : v == v} (e₃ : c₁  c₂  c₃ == m) {e₄ : (c₁  c₂)  c₃ == m}
    (r : ∙-assoc d₁ d₂ d₅  ap  s  d₁  s) q₂  q₃
         == ap  z  z  d₅) q₁  q₄  idp)
     
    ∙-assoc c₁ c₂ c₃  e₃ == e₄ 
    PPPOver r
    (∙ᵈ-assoc-ppo (↓-cst-in {p = d₁} c₁) (↓-cst-in c₂) (↓-cst-in c₃) ∙ᶜ
     ap-∙-preᶜ (↓-cst-in c₁) (ppo-cst-in-∙ d₂ q₂ idp) ∙ᶜ
     ppo-cst-in-∙ d₁ q₃ e₃)
    (ap-∙-postᶜ (↓-cst-in c₃) (ppo-cst-in-∙ d₁ q₁ idp) ∙ᶜ
     ppo-cst-in-∙ d₃ q₄ e₄ ∙ᶜ idp)
  pppo-cst-in-word-aux c₁ c₂ c₃ d₁ {d₂} idp idp idp q₄ idp r idp =
    ∙-id-ind
       r  PPPOver r
        (∙ᵈ-assoc-ppo (↓-cst-in {p = d₁} c₁) (↓-cst-in c₂) (↓-cst-in c₃) ∙ᶜ
        ap-∙-preᶜ (↓-cst-in {p = d₁} c₁) (ppo-cst-in-∙ d₂ idp idp) 
        ppo-cst-in-∙ d₁ idp idp)
        (ap-∙-postᶜ (↓-cst-in c₃) (ppo-cst-in-∙ d₁ idp idp) ∙ᶜ
          ppo-cst-in-∙ (d₁  d₂) q₄ (∙-assoc c₁ c₂ c₃  idp) ∙ᶜ idp))
      (pppo-cst-in-word-aux2 c₁ d₁) r 

  pppo-cst-in-word :  {k} {X : Type k} {a : A} {x y z w u t₁ t₂ : X}
    (τ : X  a == a) {v : B} (f : X  v == v)
    (ρ : t₁ == t₂)
    (q₁ : τ x  τ y == τ w) (q₂ : τ y  τ z == τ u)
    (q₃ : τ x  τ u == τ t₁) (q₄ : τ w  τ z == τ t₂)
    {d₁ d₂ : v == v} (e₁ : f x  f y == d₁) (e₂ : f y  f z == d₂)
    (e₃ : f x  d₂ == f t₁) (e₄ : d₁  f z == f t₂)
    (r : ∙-assoc (τ x) (τ y) (τ z)  ap  s   τ x  s) q₂  q₃
         == ap  s  s  τ z) q₁  q₄  ! (ap τ ρ))
    
    ∙-assoc (f x) (f y) (f z)  ap  p  f x  p) e₂  e₃
      ==
    ap  p  p  f z) e₁  e₄ ∙' ! (ap f ρ)
     
    PPPOver r
    (∙ᵈ-assoc-ppo (↓-cst-in {p = τ x} (f x)) (↓-cst-in {p = τ y} (f y)) (↓-cst-in {p = τ z} (f z))
     ∙ᶜ
     ap-∙-preᶜ (↓-cst-in (f x)) (ppo-cst-in-∙ (τ y) q₂ e₂)
     ∙ᶜ
     ppo-cst-in-∙ (τ x) q₃ e₃)
    (ap-∙-postᶜ (↓-cst-in (f z)) (ppo-cst-in-∙ (τ x) q₁ e₁)
     ∙ᶜ
     ppo-cst-in-∙ (τ w) q₄ e₄
     ∙ᶜ
     !ᶜ (apd-po {p = τ}  s  ↓-cst-in (f s)) ρ))
  pppo-cst-in-word {x = x} {y} {z} τ f idp q₁ q₂ q₃ q₄ idp idp e₃ e₄ r =
    pppo-cst-in-word-aux (f x) (f y) (f z) (τ x) q₁ q₂ q₃ q₄ e₃ r

  ppo-cst-in-∙ᵈ : (f : A  B) {a₀ a a₁ : A} (p₁ : a₀ == a) {p₂ : a == a₁}
    {p₃ : a₀ == a₁} {q₁ : f a₀ == f a} {q₂ : f a == f a₁}
    {q₃ : f a₀ == f a₁} (ρ : p₁  p₂ == p₃) (τ : q₁  q₂ == q₃)
    (r₁ : apd f p₁ == ↓-cst-in q₁) (r₂ : apd f p₂ == ↓-cst-in q₂)
    (r₃ : apd f p₃ == ↓-cst-in q₃) 
    apdd-∙ᵈ f p₁ p₂ ρ
      ==
    apᶜ² (! r₁ ∙ᵈ= ! r₂) (! r₃) (ppo-cst-in-∙ p₁ ρ τ)
    
    τ ==
    ! (ap2 (_∙_) (apd=cst-in r₁) (apd=cst-in r₂)) 
    (∙-ap f p₁ p₂  ap (ap f) ρ) 
    apd=cst-in r₃ 
  ppo-cst-in-∙ᵈ f {a₀} idp {p₂ = idp} idp idp r₁ r₂ r₃ = lemma r₁ r₂ r₃ 
    where
      lemma : {z₁ z₂ : f a₀ == f a₀}
        (s₁ : idp == z₁) (s₂ : idp == z₂) (s₃ : idp == z₁  z₂) 
        idp == ! (_∙ᵈ=_ {A = A} {B = λ _  B} {x = a₀} (! s₁) (! s₂))  ! s₃ 
        idp == ! (ap2 _∙_ s₁ s₂)  s₃
      lemma idp idp s₃ v = ap ! v  !-! s₃