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

open import Cubical.Foundations.Prelude
open import Cubical.HITs.SetTruncation
open import Cubical.Foundations.HLevels

private
  variable
     : Level
    A : Type 

infixr 5 _∷_

data FMSet (A : Type ) : Type  where
  []    : FMSet A
  _∷_   : (x : A)  (xs : FMSet A)  FMSet A
  comm  :  x y xs  x  y  xs  y  x  xs
  trunc : isSet (FMSet A)

pattern [_] x = x  []

module Elim {ℓ'} {B : FMSet A  Type ℓ'}
  ([]* : B []) (_∷*_ : (x : A) {xs : FMSet A}  B xs  B (x  xs))
  (comm* : (x y : A) {xs : FMSet A} (b : B xs)
          PathP  i  B (comm x y xs i)) (x ∷* (y ∷* b)) (y ∷* (x ∷* b)))
  (trunc* : (xs : FMSet A)  isSet (B xs)) where

  f : (xs : FMSet A)  B xs
  f [] = []*
  f (x  xs) = x ∷* f xs
  f (comm x y xs i) = comm* x y (f xs) i
  f (trunc xs zs p q i j) =
    isOfHLevel→isOfHLevelDep 2 trunc*  (f xs) (f zs) (cong f p) (cong f q) (trunc xs zs p q) i j

module ElimProp {ℓ'} {B : FMSet A  Type ℓ'} (BProp : {xs : FMSet A}  isProp (B xs))
  ([]* : B []) (_∷*_ : (x : A) {xs : FMSet A}  B xs  B (x  xs)) where

  f : (xs : FMSet A)  B xs
  f = Elim.f []* _∷*_
         x y {xs} b 
          toPathP (BProp (transp  i  B (comm x y xs i)) i0 (x ∷* (y ∷* b))) (y ∷* (x ∷* b))))
         xs  isProp→isSet BProp)

module Rec {ℓ'} {B : Type ℓ'} (BType : isSet B)
  ([]* : B) (_∷*_ : A  B  B)
  (comm* : (x y : A) (b : B)  x ∷* (y ∷* b)  y ∷* (x ∷* b)) where

  f : FMSet A  B
  f = Elim.f []*  x b  x ∷* b)  x y b  comm* x y b)  _  BType)