{-# OPTIONS --type-in-type #-}

open import NeilPrelude

module CoreD where

import RealTime
open RealTime public

import SVDesc
open SVDesc public

import Decoupled
open Decoupled public

---------------------------------------------------------

data Node (as bs : SVDesc) : Dec  Set where
  cnode  :  {Q}  (Δt  Q   Sample as  Q  × Sample bs)   Q  Node as bs cau
  dnode  :  {Q}  (Δt  Q  (Sample as  Q) × Sample bs)   Q  Node as bs dec

stepNode :  {as bs d}  Δt  Node as bs d  Sample as  Node as bs d × Sample bs
stepNode δ (cnode f q) sa  = first (cnode f) (f δ q sa)
stepNode δ (dnode f q) sa  = first  g  dnode f (g sa)) (f δ q)

dstepNode :  {as bs}  Δt  Node as bs dec  (Sample as  Node as bs dec) × Sample bs
dstepNode δ (dnode f q) = first  g sa  dnode f (g sa)) (f δ q)

---------------------------------------------------------

data AtomicRouter : SVDesc  SVDesc  Set where
    sfId      :  {as}      AtomicRouter as as
    fstProj   :  {as bs}   AtomicRouter (as , bs) as
    sndProj   :  {as bs}   AtomicRouter (as , bs) bs

stepARouter :  {as bs}  AtomicRouter as bs  Sample as  Sample bs
stepARouter sfId    sa         = sa
stepARouter fstProj (sa₁ , _)  = sa₁
stepARouter sndProj (_ , sa₂)  = sa₂

---------------------------------------------------------

data SF : SVDesc  SVDesc  Dec  Set where
  cprim      :  {as bs}  (Sample as  Node as bs cau  × Sample bs)            SF as bs cau
  dprim      :  {as bs}  (Sample as  Node as bs dec)  Sample bs             SF as bs dec
  arouter    :  {as bs}  AtomicRouter as bs                                   SF as bs cau
  seq        :  {d₁ d₂ as bs cs}  SF as bs d₁  SF bs cs d₂                   SF as cs (d₁  d₂)
  fan        :  {d₁ d₂ as bs cs}  SF as bs d₁  SF as cs d₂                   SF as (bs , cs) (d₁  d₂)
  rswitcher  :  {d₁ d₂ as bs A}  SF as (bs , E A) d₁  (A  SF as (bs , E A) d₂)  SF as bs (d₁  d₂)
  freezer    :  {d as bs}  SF as bs d                                         SF as (bs , C (SF as bs d)) d
  looper     :  {d as bs cs}  SF (as , cs) bs d  SF bs cs dec                SF as bs d
  weakener   :  {d as bs}  SF as bs d                                         SF as bs cau

data SF' : SVDesc  SVDesc  Dec  Set where
  prim       :  {d as bs}  Node as bs d                                         SF' as bs d
  arouter    :  {as bs}  AtomicRouter as bs                                     SF' as bs cau
  seq        :  {d₁ d₂ as bs cs}  SF' as bs d₁  SF' bs cs d₂                   SF' as cs (d₁  d₂)
  fan        :  {d₁ d₂ as bs cs}  SF' as bs d₁  SF' as cs d₂                   SF' as (bs , cs) (d₁  d₂)
  rswitcher  :  {d₁ d₂ as bs A}  SF' as (bs , E A) d₁  (A  SF as (bs , E A) d₂)   SF' as bs (d₁  d₂)
  freezer    :  {d as bs}  SF' as bs d                                          SF' as (bs , C (SF as bs d)) d
  looper     :  {d as bs cs}  SF' (as , cs) bs d  SF' bs cs dec                SF' as bs d
  weakener   :  {d as bs}  SF' as bs d                                          SF' as bs cau

---------------------------------------------------------

weakenSwitch :  {as bs}  (d₁ d₂ : Dec)  SF' as bs (d₂  d₂)  SF' as bs (d₁  d₂)
weakenSwitch cau _   = weakener
weakenSwitch dec cau = id
weakenSwitch dec dec = id

---------------------------------------------------------

mutual

  step₀ :  {d as bs}  SF as bs d  Sample as  SF' as bs d × Sample bs
  step₀ (cprim f) sa = first prim (f sa)
  step₀ (dprim f sb) sa = (prim (f sa) , sb)
  step₀ (arouter r) sa = (arouter r , stepARouter r sa)
  step₀ (seq sf₁ sf₂) sa with step₀ sf₁ sa
  ...  | (sf₁' , sb) with step₀ sf₂ sb
  ...     | (sf₂' , sc) = (seq sf₁' sf₂' , sc)
  step₀ (fan sf₁ sf₂) sa with step₀ sf₁ sa | step₀ sf₂ sa
  ... | (sf₁' , sb) | (sf₂' , sc) = (fan sf₁' sf₂' , (sb , sc))
  step₀ (rswitcher {d₁} {d₂} sf f) sa with step₀ sf sa
  ...  | (sf' , (sb , nothing)) = (rswitcher sf' f , sb)
  ...  | (_   , (_  , just e)) with step₀ (f e) sa
  ...     | (sf' , (sb , _)) = (weakenSwitch d₁ d₂ (rswitcher sf' f) , sb)
  step₀ (freezer sf) sa with step₀ sf sa
  ... | (sf' , sb) = (freezer sf' , (sb , sf))
  step₀ (looper sff sfb) sa with dstep₀ sfb
  ...  | (g , sc) with step₀ sff (sa , sc)
  ...     | (sff' , sb) = (looper sff' (g sb) , sb)
  step₀ (weakener sf) sa = first weakener (step₀ sf sa)

  dstep₀ :  {as bs}  SF as bs dec  (Sample as  SF' as bs dec) × Sample bs
  dstep₀ sf = dstepAux₀ sf refl

  dstepAux₀ :  {d as bs}  SF as bs d  d  dec  (Sample as  SF' as bs dec) × Sample bs

  dstepAux₀ (cprim f) ()

  dstepAux₀ (dprim f sb) refl = (prim  f , sb)

  dstepAux₀ (arouter r) ()

  dstepAux₀ (seq {dec} sf₁ sf₂) refl with dstep₀ sf₁
  ...  | (g , sb) with step₀ sf₂ sb
  ...     | (sf₂' , sc) = ((λ sa  seq (g sa) sf₂') , sc)
  dstepAux₀ (seq {cau} {.dec} {as} {bs} {cs} sf₁ sf₂) refl with dstep₀ sf₂
  ... | (g , sc) = (aux , sc)
                   where  aux : Sample as  SF' as cs dec
                          aux sa with step₀ sf₁ sa
                          ... | (sf₁' , sb) = seq sf₁' (g sb)

  dstepAux₀ (fan {cau} sf₁ sf₂) ()
  dstepAux₀ (fan {dec} sf₁ sf₂) refl with dstep₀ sf₁ | dstep₀ sf₂
  ... | (g₁ , sb) | (g₂ , sc) = ((λ sa  fan (g₁ sa) (g₂ sa)) , (sb , sc))

  dstepAux₀ (rswitcher {cau} sf f) ()
  dstepAux₀ (rswitcher {dec} sf f) refl with dstep₀ sf
  ...  | (g , (sb , nothing)) = ((λ sa  rswitcher (g sa) f) , sb)
  ...  | (_ , (_ , just e)) with dstep₀ (f e)
  ...     |  (g , (sb , _)) = ((λ sa  rswitcher (g sa) f) , sb)

  dstepAux₀ (freezer sf) refl with dstep₀ sf
  ... | (g , sb) = (freezer  g , (sb , sf))

  dstepAux₀ (looper sff sfb) refl with dstep₀ sff
  ...  | (g , sb) with step₀ sfb sb
  ...     | (sfb' , sc) = ((λ sa  looper (g (sa , sc)) sfb') , sb)

  dstepAux₀ (weakener sf) ()

---------------------------------------------------------

freezeSF :  {d as bs}  Δt  SF' as bs d  SF as bs d
freezeSF δ (arouter r)      = arouter r
freezeSF δ (seq sf₁ sf₂)    = seq (freezeSF δ sf₁) (freezeSF δ sf₂)
freezeSF δ (fan sf₁ sf₂)    = fan (freezeSF δ sf₁) (freezeSF δ sf₂)
freezeSF δ (rswitcher sf f) = rswitcher (freezeSF δ sf) f
freezeSF δ (freezer sf)     = freezer (freezeSF δ sf)
freezeSF δ (looper sff sfb) = looper (freezeSF δ sff) (freezeSF δ sfb)
freezeSF δ (weakener sf)    = weakener (freezeSF δ sf)
freezeSF {cau} δ (prim n)   = cprim (stepNode δ n)
freezeSF {dec} δ (prim n)   = uncurry dprim (dstepNode δ n)

---------------------------------------------------------

mutual

  step' :  {d as bs}  Δt  SF' as bs d  Sample as  SF' as bs d × Sample bs
  step' δ (prim n) sa = first prim (stepNode δ n sa)
  step' δ (arouter r) sa = (arouter r , stepARouter r sa)
  step' δ (seq sf₁ sf₂) sa with step' δ sf₁ sa
  ... | (sf₁' , sb) with step' δ sf₂ sb
  ...    | (sf₂' , sc) = (seq sf₁' sf₂' , sc)
  step' δ (fan sf₁ sf₂) sa with step' δ sf₁ sa | step' δ sf₂ sa
  ... | (sf₁' , sb) | (sf₂' , sc) = (fan sf₁' sf₂' , (sb , sc))
  step' δ (rswitcher {d₁} {d₂} sf f) sa with step' δ sf sa
  ... | (sf' , (sb , nothing)) = (rswitcher sf' f , sb)
  ... | (_   , (_  , just e)) with step₀ (f e) sa
  ...    | (sf' , (sb , _)) = (weakenSwitch d₁ d₂ (rswitcher sf' f) , sb)
  step' δ (freezer sf) sa with step' δ sf sa
  ... | (sf' , sb) = (freezer sf' , (sb , freezeSF δ sf))
  step' δ (looper sff sfb) sa with dstep' δ sfb
  ... | (g , sc) with step' δ sff (sa , sc)
  ...    | (sff' , sb) = (looper sff' (g sb) , sb)
  step' δ (weakener sf) sa = first weakener (step' δ sf sa)


  dstep' :  {as bs}  Δt  SF' as bs dec  (Sample as  SF' as bs dec) × Sample bs
  dstep' δ sf = dstepAux' δ sf refl

  dstepAux' :  {d as bs}  Δt  SF' as bs d  d  dec  (Sample as  SF' as bs dec) × Sample bs

  dstepAux' δ (prim n) refl = (first  result) prim (dstepNode δ n)

  dstepAux' δ (arouter r) ()

  dstepAux' δ (seq {dec} sf₁ sf₂) refl with dstep' δ sf₁
  ... | (g , sb) with step' δ sf₂ sb
  ...    | (sf₂' , sc) = ((λ sa  seq (g sa) sf₂') , sc)
  dstepAux' δ (seq {cau} {._} {as} {_} {cs} sf₁ sf₂) refl with dstep' δ sf₂
  ... | (g , sc) = (aux , sc)
                   where aux : Sample as  SF' as cs dec
                         aux sa with step' δ sf₁ sa
                         ... | (sf₁' , sb) = seq sf₁' (g sb)

  dstepAux' δ (fan {cau} sf₁ sf₂) ()
  dstepAux' δ (fan {dec} sf₁ sf₂) refl with dstep' δ sf₁ | dstep' δ sf₂
  ... | (g₁ , sb) | (g₂ , sc) = ((λ sa  fan (g₁ sa) (g₂ sa)) , (sb , sc))

  dstepAux' δ (rswitcher {cau} sf f) ()
  dstepAux' δ (rswitcher {dec} {cau} sf f) ()
  dstepAux' δ (rswitcher {dec} {dec} sf f) refl with dstep' δ sf
  ... | (g , (sb , nothing)) = ((λ sa  rswitcher (g sa) f) , sb)
  ... | (_ , (_ , just e)) with dstep₀ (f e)
  ...    | (g , (sb , _)) = ((λ sa  rswitcher (g sa) f) , sb)

  dstepAux' δ (freezer sf) refl with dstep' δ sf
  ... | (g , sb) = (freezer  g , (sb , freezeSF δ sf))

  dstepAux' δ (looper sff sfb) refl with dstep' δ sff
  ... | (g , sb) with step' δ sfb sb
  ...    | (sfb' , sc) = ((λ sa  looper (g (sa , sc)) sfb') , sb)

  dstepAux' δ (weakener sf) ()

---------------------------------------------------------