{-# OPTIONS --safe #-}
module Cubical.HITs.Join.Base where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.Pointed.Base

open import Cubical.HITs.S1
open import Cubical.HITs.S3

-- redtt version : https://github.com/RedPRL/redtt/blob/master/library/cool/s3-to-join.red

data join { ℓ'} (A : Type ) (B : Type ℓ') : Type (ℓ-max  ℓ') where
  inl : A  join A B
  inr : B  join A B
  push :  a b  inl a  inr b

join∙ :  { ℓ'} (A : Pointed ) (B : Pointed ℓ')
   Pointed _
fst (join∙ A B) = join (fst A) (fst B)
snd (join∙ A B) = inl (pt A)

facek01 : I  I  I  join  
facek01 i j k = hfill  l  λ { (j = i0)  push base base (~ l  ~ k)
                               ; (j = i1)  push base base (~ l  ~ k)
                               ; (k = i0)  push (loop j) base (~ l)
                               ; (k = i1)  inl base })
                      (inS (push base base (~ k))) i

border-contraction : I  I  I  I  join  
border-contraction i j k m =
  hfill  l  λ { (i = i0)  facek01 i1 j l
                 ; (i = i1)  push base (loop k) (~ l)
                 ; (j = i0)  push base (loop k) (i  ~ l)
                 ; (j = i1)  push base (loop k) (i  ~ l)
                 ; (k = i0)  facek01 (~ i) j l
                 ; (k = i1)  facek01 (~ i) j l })
        (inS (push (loop j) (loop k) i)) m

S³→joinS¹S¹ :   join  
S³→joinS¹S¹ base = inl base
S³→joinS¹S¹ (surf j k i) = border-contraction i j k i1

joinS¹S¹→S³ : join    
joinS¹S¹→S³ (inl x) = base
joinS¹S¹→S³ (inr x) = base
joinS¹S¹→S³ (push base b i) = base
joinS¹S¹→S³ (push (loop x) base i) = base
joinS¹S¹→S³ (push (loop i) (loop j) k) = surf i j k

connection : I  I  I  I  
connection i j k l =
  hfill  m  λ { (k = i0)  joinS¹S¹→S³ (facek01 m i j)
                 ; (k = i1)  base
                 ; (j = i0)  base
                 ; (j = i1)  base
                 ; (i = i0)  base
                 ; (i = i1)  base })
        (inS base) l

S³→joinS¹S¹→S³ :  x  joinS¹S¹→S³ (S³→joinS¹S¹ x)  x
S³→joinS¹S¹→S³ base l = base
S³→joinS¹S¹→S³ (surf j k i) l =
  hcomp  m  λ { (l = i0)  joinS¹S¹→S³ (border-contraction i j k m)
                 ; (l = i1)  surf j k i
                 ; (i = i0)  connection j m l i1
                 ; (i = i1)  base
                 ; (j = i0)  base
                 ; (j = i1)  base
                 ; (k = i0)  connection j m l (~ i)
                 ; (k = i1)  connection j m l (~ i) })
                 (surf j k i)

joinS¹S¹→S³→joinS¹S¹ :  x  S³→joinS¹S¹ (joinS¹S¹→S³ x)  x
joinS¹S¹→S³→joinS¹S¹ (inl base) l = inl base
joinS¹S¹→S³→joinS¹S¹ (inl (loop i)) l = facek01 i1 i (~ l)
joinS¹S¹→S³→joinS¹S¹ (inr base) l = push base base l
joinS¹S¹→S³→joinS¹S¹ (inr (loop i)) l = push base (loop i) l
joinS¹S¹→S³→joinS¹S¹ (push base base i) l = push base base (i  l)
joinS¹S¹→S³→joinS¹S¹ (push base (loop k) i) l = push base (loop k) (i  l)
joinS¹S¹→S³→joinS¹S¹ (push (loop k) base i) l = facek01 (~ i) k (~ l)
joinS¹S¹→S³→joinS¹S¹ (push (loop j) (loop k) i) l = border-contraction i j k (~ l)

S³IsojoinS¹S¹ : Iso  (join  )
Iso.fun S³IsojoinS¹S¹ = S³→joinS¹S¹
Iso.inv S³IsojoinS¹S¹ = joinS¹S¹→S³
Iso.rightInv S³IsojoinS¹S¹ = joinS¹S¹→S³→joinS¹S¹
Iso.leftInv S³IsojoinS¹S¹ = S³→joinS¹S¹→S³


S³≡joinS¹S¹ :   join  
S³≡joinS¹S¹ = isoToPath S³IsojoinS¹S¹