module linear.Usage.Mix where

open import Data.Product as Prod
open import Data.Vec as V hiding ([_] ; _∷ʳ_ ; fromList)
open import Function
open import Relation.Binary.PropositionalEquality hiding ([_])

open import linear.Context
open import linear.Context.Mix as CM hiding (_++ˡ_)
open import linear.Usage as U hiding ([_])
import linear.Usage.Erasure as UE
open import linear.Relation.Functional

infix 2 [_]_++_≅_
infixr 4 _∷ˡ_ _∷ʳ_
data [_]_++_≅_ :  {m n p} {γ : Context m} {δ : Context n} {θ : Context p} 
                 γ ++ δ  θ  Usages γ  Usages δ  Usages θ  Set where
  []   : [ [] ] [] ++ []  []
  _∷ˡ_ :  {m n p σ} {γ : Context m} {δ : Context n} {θ : Context p}
         {p : γ ++ δ  θ} {Γ Δ Θ} (S : Usage σ) 
         [ p ] Γ ++ Δ  Θ  [ σ ∷ˡ p ] S  Γ ++ Δ  S  Θ
  _∷ʳ_ :  {m n p σ} {γ : Context m} {δ : Context n} {θ : Context p}
         {p : γ ++ δ  θ} {Γ Δ Θ} (S : Usage σ) 
         [ p ] Γ ++ Δ  Θ  [ σ ∷ʳ p ] Γ ++ S  Δ  S  Θ

≅-inj :  {m n p} {γ : Context m} {δ : Context n} {θ : Context p}
  {Γ₁ Γ₂ Δ₁ Δ₂ Θ} (p : γ ++ δ  θ) 
  [ p ] Γ₁ ++ Δ₁  Θ  [ p ] Γ₂ ++ Δ₂  Θ 
  Γ₁  Γ₂ × Δ₁  Δ₂
≅-inj []       []         []          = refl , refl
≅-inj (a ∷ˡ p) (S ∷ˡ eq₁) (.S ∷ˡ eq₂) = Prod.map (cong (S ∷_)) id $ ≅-inj p eq₁ eq₂
≅-inj (σ ∷ʳ p) (S ∷ʳ eq₁) (.S ∷ʳ eq₂) = Prod.map id (cong (S ∷_)) $ ≅-inj p eq₁ eq₂

_++ˡ_ :  {m n p} {γ : Context m} {δ : Context n} {θ : Context p}
        {p : γ ++ δ  θ} {Γ Δ Θ} {o} {φ : Context o} (Φ : Usages φ) 
  [ p ] Γ ++ Δ  Θ  [ φ CM.++ˡ p ] Φ U.++ Γ ++ Δ  Φ U.++ Θ
[]      ++ˡ eq = eq
(S  Φ) ++ˡ eq = S ∷ˡ (Φ ++ˡ eq)

[[fromList]] :  {γ δ θ} (p : γ UE.++ δ  θ) 
               [ CM.fromList p ] [[ _ ]] ++ [[ _ ]]  [[ V.fromList θ ]]
[[fromList]] UE.[]       = []
[[fromList]] (a UE.∷ˡ p) = U.[ a ] ∷ˡ [[fromList]] p
[[fromList]] (a UE.∷ʳ p) = U.[ a ] ∷ʳ [[fromList]] p


]]fromList[[ :  {γ δ θ} (p : γ UE.++ δ  θ) 
               [ CM.fromList p ] ]] _ [[ ++ ]] _ [[  ]] V.fromList θ [[
]]fromList[[ UE.[]       = []
]]fromList[[ (a UE.∷ˡ p) = ] a [ ∷ˡ ]]fromList[[ p
]]fromList[[ (a UE.∷ʳ p) = ] a [ ∷ʳ ]]fromList[[ p

open import Data.Nat
open import Data.Unit

MixSplit :
  (ri : Σ[ γδθ   Context ×  Context ×  Context ]
        let ((_ , γ) , (_ , δ) , (_ , θ)) = γδθ in
        (γ ++ δ  θ) × Usages γ × Usages δ) 
  let ((_ , _ , (_ , θ)) , eq , Γ , Δ) = ri in Usages θ  Set
MixSplit (_ , eq , Γ , Δ) Θ = [ eq ] Γ ++ Δ  Θ

functionalMix : Functional′ MixSplit
functionalMix (_ , []        , _) [] [] = refl
functionalMix (_ , (σ ∷ˡ eq) , _) (_ ∷ˡ o₁) (_ ∷ˡ o₂) =
   cong _ (functionalMix (_ , eq , _) o₁ o₂)
functionalMix (_ , (σ ∷ʳ eq) , _) (_ ∷ʳ o₁) (_ ∷ʳ o₂) =
 cong _ (functionalMix (_ , eq , _) o₁ o₂)