module Vec.Relation.FirstOrNot where

open import Level
open import Function
open import Data.Bool
open import Data.Product
open import Data.Maybe as Maybe
open import Data.Nat
open import Data.Fin
open import Data.Vec as Vec
open import Relation.Nullary

private variable
   ℓ1 : Level
  A : Set 
  a : A
  b : Bool
  n : 
  P : A  Set 
  xs : Vec A n

data FirstOrNot {A : Set } (P : A  Set ℓ1) : Vec A n  Bool  Set ( Level.⊔ ℓ1) where
  notHere : FirstOrNot P [] false
  here    : (p : P a) (xs : Vec A n)  FirstOrNot P (a  xs) true
  there   : (¬p : ¬ P a) {xs : Vec A n} (firstOrNot : FirstOrNot P xs b)  FirstOrNot P (a  xs) b

FirstOrNotΣ : {A : Set } (P : A  Set ℓ1) (xs : Vec A n)  Set ( Level.⊔ ℓ1)
FirstOrNotΣ P xs = Σ Bool $ FirstOrNot P xs

firstOrNotPosition :  {xs : Vec A n}  FirstOrNot P xs true  Fin n
firstOrNotPosition (here p xs) = Fin.zero
firstOrNotPosition (there ¬p xs) = Fin.suc (firstOrNotPosition xs)

firstOrNotPositionMaybe :  {xs : Vec A n}  FirstOrNot P xs b  Maybe $ Fin n
firstOrNotPositionMaybe {b = false} fxs = nothing
firstOrNotPositionMaybe {b = true} fxs = just $ firstOrNotPosition fxs

vReflect : (P : A  Set )    Set _
vReflect P n = Vec (Σ[ x  _ ] Σ[ b  Bool ] Reflects (P x) b) n

boolVec→firstOrNot : (P : A  Set ) (xs : vReflect P n)  FirstOrNotΣ P $ Vec.map proj₁ xs
boolVec→firstOrNot P [] = false , notHere
boolVec→firstOrNot P ((x , false , ofⁿ ¬p)  xs) = _ , there ¬p (boolVec→firstOrNot P xs .proj₂)
boolVec→firstOrNot P ((x , true , ofʸ p)  xs) = true , here p (Vec.map proj₁ xs)

firstOfVReflect : vReflect P n  Maybe $ Fin n
firstOfVReflect [] = nothing
firstOfVReflect ((_ , false , _)  xs) = Maybe.map Fin.suc $ firstOfVReflect xs
firstOfVReflect ((_ , true , _)  xs) = just $ Fin.zero

firstOrNotFromDec : (P? :  a  Dec $ P a) (xs : Vec A n)  FirstOrNotΣ P xs
firstOrNotFromDec P? [] = _ , notHere
firstOrNotFromDec P? (x  xs) with P? x
... | yes p = true , here p xs
... | no ¬p = _ , there ¬p (proj₂ $ firstOrNotFromDec P? xs)

firstTrue : Vec Bool n  Maybe $ Fin n
firstTrue [] = nothing
firstTrue (true  xs) = just $ Fin.zero
firstTrue (false  xs) = Maybe.map Fin.suc (firstTrue xs)