module linear.Usage.Consumption where

open import Data.Nat
open import Data.Vec hiding (map ; [_] ; split ; _++_ ; tail)
open import Data.Product hiding (swap)
open import Function

open import linear.Type
open import linear.Scope as Sc
open import linear.Context as C hiding (_++_)
open import linear.Usage as U hiding (_++_ ; tail)
import Relation.Binary.PropositionalEquality as PEq

infix 3 _─_≡_─_
data _─_≡_─_ : {n : } {γ : Context n} (Γ Δ θ ξ : Usages γ)  Set where
  []  : []  []  []  []
  ─∷_ : {n : } {γ : Context n} {Γ Δ θ ξ : Usages γ} {a : Type} {A B : Usage a} 
        Γ  Δ  θ  ξ  A  Γ  A  Δ  B  θ  B  ξ
  _∷_ : {n : } {γ : Context n} {Γ Δ θ ξ : Usages γ} (a : Type) 
        Γ  Δ  θ  ξ  [ a ]  Γ  ] a [  Δ  [ a ]  θ  ] a [  ξ

tail : {n : } {γ : Context n} {Γ Δ θ ξ : Usages γ} {a : Type} {S T U V : Usage a} 
       S  Γ  T  Δ  U  θ  V  ξ  Γ  Δ  θ  ξ
tail (─∷ p)  = p
tail (a  p) = p

infix 3 _⊆_
_⊆_ : {n : } {γ : Context n} (Γ Δ : Usages γ)  Set
Γ  Δ = Γ  Δ  Γ  Δ

pure : {n : } (γ : Context n)  [[ γ ]]  ]] γ [[
pure []      = []
pure (a  γ) = a  pure γ

refl : {n : } {γ : Context n} (Γ : Usages γ)  Γ  Γ
refl []      = []
refl (_  Γ) = ─∷ refl Γ

trans : {n : } {γ : Context n} {Γ Δ θ : Usages γ}  Γ  Δ  Δ  θ  Γ  θ
trans []      []      = []
trans (─∷ p)  (─∷ q)  = ─∷ trans p q
trans (a  p) (─∷ q)  = a  trans p q
trans (─∷ p)  (a  q) = a  trans p q

antisym : {n : } {γ : Context n} {Γ Δ : Usages γ}  Γ  Δ  Δ  Γ  Γ PEq.≡ Δ
antisym []      []     = PEq.refl
antisym (─∷ p)  (─∷ q) = PEq.cong _ $ antisym p q
antisym (a  p) ()

irrelevance : {n : } {γ : Context n} {Γ Δ : Usages γ} (p q : Γ  Δ)  p PEq.≡ q
irrelevance []      []       = PEq.refl
irrelevance (─∷ p)  (─∷ q)   = PEq.cong ─∷_    $ irrelevance p q
irrelevance (a  p) (.a  q) = PEq.cong (a ∷_) $ irrelevance p q

infixr 3 _++_
_++_ : {m n : } {γ : Context m} {δ : Context n} {Γ Δ θ ξ : Usages γ} {χ Φ : Usages δ} 
       χ  Φ  Γ  Δ  θ  ξ  χ U.++ Γ  Φ U.++ Δ  χ U.++ θ  Φ U.++ ξ
[]    ++ q = q
─∷ p  ++ q = ─∷ (p ++ q)
a  p ++ q = a  (p ++ q)

swap : {n : } {γ : Context n} {Γ Δ θ : Usages γ}  Γ  Δ  Δ  θ 
        λ Δ′  Γ  Δ  Δ′  θ × Δ  θ  Γ  Δ′
swap []      []      = [] , [] , []
swap (─∷ p)  (─∷ q)  = map _ (map ─∷_    ─∷_)    $ swap p q
swap (─∷ p)  (a  q) = map _ (map ─∷_    (a ∷_)) $ swap p q
swap (a  p) (─∷ q)  = map _ (map (a ∷_) ─∷_)    $ swap p q

split : {m n : } {γ : Context m} {δ : Context n} (Γ₁ Γ₂ : Usages γ) {Δ₁ Δ₂ : Usages δ} 
        Γ₁ U.++ Δ₁  Γ₂ U.++ Δ₂  Γ₁  Γ₂ × Δ₁  Δ₂
split []      []      p       = [] , p
split (_  _) (_  _) (─∷ p)  = map ─∷_    id $ split _ _ p
split (_  _) (_  _) (a  p) = map (a ∷_) id $ split _ _ p

truncate : {m n : } (γ : Context m) {δ : Context n} {Δ₁ Δ₂ : Usages δ} 
           [[ γ ]] U.++ Δ₁  ]] γ [[ U.++ Δ₂  Δ₁  Δ₂
truncate γ = proj₂  split [[ γ ]] ]] γ [[

divide : {n : } {γ : Context n} {Γ Δ θ ξ χ : Usages γ}  Γ  Δ  θ  ξ  Γ  χ  χ  Δ 
         λ Φ  Γ  χ  θ  Φ × χ  Δ  Φ  ξ
divide []       []       []       = [] , [] , []
divide (a  eq) (─∷ p)   (.a  q) = map _ (map ─∷_    (a ∷_)) $ divide eq p q
divide (a  eq) (.a  p) (─∷ q)   = map _ (map (a ∷_) ─∷_)    $ divide eq p q
divide (─∷ eq)  (─∷ p)   (─∷ q)   = map _ (map ─∷_    ─∷_)    $ divide eq p q
divide (─∷ eq)  (a  p)  ()

weaken⁻¹ : {k l : } {γ : Context k} {m : Sc.Mergey k l} {M : C.Mergey m} (𝓜 : U.Mergey M)
           {Γ Δ : Usages γ} {χ : Usages (γ C.⋈ M)}  Γ U.⋈ 𝓜  χ  χ  Δ U.⋈ 𝓜 
            λ χ′  χ PEq.≡ (χ′ U.⋈ 𝓜)
weaken⁻¹ finish        p q = , PEq.refl
weaken⁻¹ (copy 𝓜) {T  Γ}        {.T  Δ}       (─∷ p)  (─∷ q)  = map (_ ∷_) (PEq.cong (_ ∷_)) $ weaken⁻¹ 𝓜 p q
weaken⁻¹ (copy 𝓜) {.([ a ])  Γ} {.(] a [)  Δ} (─∷ p)  (a  q) = map (_ ∷_) (PEq.cong (_ ∷_)) $ weaken⁻¹ 𝓜 p q
weaken⁻¹ (copy 𝓜) {.([ a ])  Γ} {.(] a [)  Δ} (a  p) (─∷ q)  = map (_ ∷_) (PEq.cong (_ ∷_)) $ weaken⁻¹ 𝓜 p q
weaken⁻¹ (insert A 𝓜) (─∷ p) (─∷ q) = map id (PEq.cong (_ ∷_)) $ weaken⁻¹ 𝓜 p q
weaken⁻¹ (insert .([ a ]) 𝓜) (a  p) ()

equality : {n : } {γ : Context n} {Γ θ ξ : Usages γ}  Γ  Γ  θ  ξ  θ PEq.≡ ξ
equality []     = PEq.refl
equality (─∷ p) = PEq.cong _ $ equality p

Consumption : {T :   Set} (𝓣 : Typing T)  Set
Consumption {T} 𝓣 = {n : } {γ : Context n} {t : T n} {A : Type} {Γ Δ : Usages γ}  𝓣 Γ t A Δ  Γ  Δ

Framing : {T :   Set} (𝓣 : Typing T)  Set
Framing {T} 𝓣 =
  {n : } {γ : Context n} {Γ Δ θ ξ : Usages γ} {t : T n} {A : Type} 
  Γ  Δ  θ  ξ  𝓣 Γ t A Δ  𝓣 θ t A ξ

consumptionFin : Consumption TFin
consumptionFin z     = _  refl _
consumptionFin (s k) = ─∷ consumptionFin k

framingFin : Framing TFin
framingFin (A  p) z rewrite equality p = z
framingFin (─∷ p) (s k) = s framingFin p k