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

open import Cubical.Foundations.Prelude hiding (empty)
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.Function
open import Cubical.Foundations.Univalence

open import Cubical.Data.List
open import Cubical.Data.Sigma hiding (empty)


module Queue.Base
  (ABS : Type) (ABS-isProp : isProp ABS)
  (E : Type) (e₀ : E) (ESet : isSet E) where

open import Modality.Abstract ABS ABS-isProp


record PreQueue : Type₁ where
  field
    X : Type
    empty : X
    enqueue : E  X  X
    dequeue : X  E × X
open PreQueue public

prequeue-path
  :  {P Q : PreQueue} (P≃Q : P .X  Q .X)
   (equivFun P≃Q (P .empty)  Q .empty)
   (∀ e p  equivFun P≃Q (P .enqueue e p)  Q .enqueue e (equivFun P≃Q p))
   (∀ p  fst (P .dequeue p)  fst (Q .dequeue (equivFun P≃Q p)))
   (∀ p  equivFun P≃Q (snd (P .dequeue p))  snd (Q .dequeue (equivFun P≃Q p)))
   P  Q
prequeue-path P≃Q _ _ _ _ i .X = ua P≃Q i
prequeue-path P≃Q h-empty _ _ _ i .empty = ua-gluePath P≃Q h-empty i
prequeue-path {P} {Q} P≃Q _ h-enqueue _ _ i .enqueue e = ua→ {e = P≃Q} {f₁ = Q .enqueue e} (ua-gluePath P≃Q  h-enqueue e) i
prequeue-path {P} {Q} P≃Q _ _ h-fst-dequeue _ i .dequeue p .fst = ua→ {e = P≃Q} {f₁ = fst  Q .dequeue} h-fst-dequeue i p
prequeue-path {P} {Q} P≃Q _ _ _ h-snd-dequeue i .dequeue p .snd = ua→ {e = P≃Q} {f₁ = snd  Q .dequeue} (ua-gluePath P≃Q  h-snd-dequeue) i p

listPreQueue : PreQueue
listPreQueue .X = List E
listPreQueue .empty = []
listPreQueue .enqueue e l = l ++ [ e ]
listPreQueue .dequeue [] = e₀ , []
listPreQueue .dequeue (e  l) = e , l

Queue : Type
Queue = spec listPreQueue

queue-isConcrete : isConcrete Queue
queue-isConcrete = isConcreteSpec listPreQueue

listQueue : Queue
listQueue .fst = listPreQueue
listQueue .snd = η∘ refl