module ListExtras where

open import Data.List
open import Data.Nat
open import Data.Fin using (Fin; zero; suc)
open import Data.Product

open import Data.List.Properties using (++-assoc) renaming (++-identityʳ to ++-id-right; ∷-injectiveˡ to ∷-inj₁; ∷-injectiveʳ to ∷-inj₂) public

open import Relation.Binary.PropositionalEquality using (_≡_; refl; sym; cong; trans; subst) public

open import Simple-list-solver using (list-solve; bla) renaming (id to :[]; _⊕_ to _:++_; _⊜_ to _:≡_) public

nil-cons-absurd :  {a b} {A : Set a} {B : Set b} (xs : List A) {y zs}
   []  xs ++ y  zs
   B
nil-cons-absurd [] ()
nil-cons-absurd (x  Γ) ()

singleton-lemma :  {a} {A : Set a} (ys : List A) {x₁ x₂ zs}
   [ x₁ ]  ys ++ x₂  zs
   ys  [] × x₁  x₂ × zs  []
singleton-lemma [] refl   = refl , refl , refl
singleton-lemma (_  Γ) p = nil-cons-absurd Γ (∷-inj₂ p)

data MatchCons {a} {A : Set a}
  (xs : List A) (y : A) (zs : List A)
  (us : List A) (v : A) (ws : List A) : Set a where
  here
    : xs  us
     y   v
     zs  ws
     MatchCons xs y zs us v ws
  before : (ms : List A)
     xs  us ++ v  ms
     ms ++ y  zs  ws
     MatchCons xs y zs us v ws
  after : (ms : List A)
     zs  ms ++ v  ws
     us  xs ++ y  ms
     MatchCons xs y zs us v ws

match-cons :  {a} {A : Set a}
   (xs us : List A)
   {zs ws : List A}
   {y v : A}
   xs ++ y  zs  us ++ v  ws
   MatchCons xs y zs us v ws
match-cons []       []       refl = here refl refl refl
match-cons []       (u  us) p    = after us (∷-inj₂ p) (cong  i  i  us) (sym (∷-inj₁ p)))
match-cons (x  xs) []       p    = before xs (cong  i  i  xs) (∷-inj₁ p)) (∷-inj₂ p)
match-cons (x  xs) (u  us) p with ∷-inj₁ p | match-cons xs us (∷-inj₂ p)
... | refl | here refl refl refl = here refl refl refl
... | refl | before ms refl refl = before ms refl refl
... | refl | after  ms refl refl = after  ms refl refl

match-cons-2 :  {a} {A : Set a}
   (xs xs′ us : List A)
   {zs ws : List A}
   {y v : A}
   xs ++ xs′ ++ y  zs  us ++ v  ws
   MatchCons (xs ++ xs′) y zs us v ws
match-cons-2 [] [] [] refl = here refl refl refl
match-cons-2 [] (x  xs′) [] p = before xs′ (cong  i  i  xs′) (∷-inj₁ p)) (∷-inj₂ p)
match-cons-2 (x  xs) xs′ [] p = before
  (xs ++ xs′)
  (cong  i  i  xs ++ xs′) (∷-inj₁ p))
  (trans (++-assoc xs xs′ _) (∷-inj₂ p))
match-cons-2 [] [] (u  us) p = after
  us
  (∷-inj₂ p)
  (sym (cong  i  i  us) (∷-inj₁ p)))
match-cons-2 [] (x  xs′) (u  us) p with ∷-inj₁ p | match-cons xs′ us (∷-inj₂ p)
... | refl | here refl refl refl = here refl refl refl
... | refl | before ms refl refl = before ms refl refl
... | refl | after  ms refl refl = after ms refl refl
match-cons-2 (x  xs) xs′ (u  us) p with ∷-inj₁ p | match-cons-2 xs xs′ us (∷-inj₂ p)
... | refl | here refl refl refl = here refl refl refl
... | refl | before ms pf   refl = before ms (cong  is  x  is) pf) refl
... | refl | after  ms refl refl = after ms refl refl

data FindCons {a} {A : Set a}
  (xs : List A) (ys : List A)
  (us : List A) (v : A) (ws : List A) : Set a where
  in-first : (ms : List A)
     xs  us ++ v  ms
     ms ++ ys  ws
     FindCons xs ys us v ws
  in-second : (ms : List A)
     ys  ms ++ v  ws
     xs ++ ms  us
     FindCons xs ys us v ws

find-cons :  {a} {A : Set a}
   (xs : List A) {ys : List A}
   (us : List A) {v : A} {ws : List A}
   xs ++ ys  us ++ v  ws
   FindCons xs ys us v ws
find-cons []       []       refl = in-second [] refl refl
find-cons []       (u  us) refl = in-second (u  us) refl refl
find-cons (x  xs) []       refl = in-first xs refl refl
find-cons (x  xs) (x₁  us) p with ∷-inj₁ p | find-cons xs us (∷-inj₂ p)
... | refl | in-first  ms refl refl = in-first ms refl refl
... | refl | in-second ms refl refl = in-second ms refl refl