{-# OPTIONS --cubical --safe #-}

open import Relation.Binary
open import Prelude hiding (Decidable)

module Data.List.Relation.Binary.Lexicographic {e ℓ₁ ℓ₂} {E : Type e} (ord : TotalOrder E ℓ₁ ℓ₂) where

open import Data.List
import Path as 

open TotalOrder ord renaming (refl to ≤-refl)

import Data.Empty.UniversePolymorphic as Poly
import Data.Unit.UniversePolymorphic as Poly

infix 4 _<′_
_<′_ : List E  List E  Type (e ℓ⊔ ℓ₁ ℓ⊔ ℓ₂)
xs <′ []     = Poly.⊥
[] <′ y  ys = Poly.⊤
x  xs <′ y  ys = (x < y)  ((x  y) × (xs <′ ys))

infix 4 _≤′_
_≤′_ : List E  List E  Type (e ℓ⊔ ℓ₁ ℓ⊔ ℓ₂)
[]     ≤′ ys     = Poly.⊤
x  xs ≤′ []     = Poly.⊥
x  xs ≤′ y  ys = (x < y)  ((x  y) × (xs ≤′ ys))


<′-trans : Transitive _<′_
<′-trans {[]}     {y  ys} {z  zs} p q = Poly.tt
<′-trans {x  xs} {y  ys} {z  zs} (inl p) (inl q) = inl (<-trans p q)
<′-trans {x  xs} {y  ys} {z  zs} (inl p) (inr q) = inl (subst (_ <_) (fst q) p)
<′-trans {x  xs} {y  ys} {z  zs} (inr p) (inl q) = inl (subst (_< _) (sym (fst p)) q)
<′-trans {x  xs} {y  ys} {z  zs} (inr (p , ps)) (inr (q , qs)) = inr (p ; q , <′-trans ps qs)

≤′-trans : Transitive _≤′_
≤′-trans {[]} {ys} {zs} p q = Poly.tt
≤′-trans {x  xs} {y  ys} {z  zs} (inl p) (inl q) = inl (<-trans p q)
≤′-trans {x  xs} {y  ys} {z  zs} (inl p) (inr q) = inl (subst (_ <_) (fst q) p)
≤′-trans {x  xs} {y  ys} {z  zs} (inr p) (inl q) = inl (subst (_< _) (sym (fst p)) q)
≤′-trans {x  xs} {y  ys} {z  zs} (inr (p , ps)) (inr (q , qs)) = inr (p ; q , ≤′-trans ps qs)

≤′-antisym : Antisymmetric _≤′_
≤′-antisym {[]} {[]} p q = refl
≤′-antisym {x  xs} {y  ys} (inl p) (inl q) = ⊥-elim (asym p q)
≤′-antisym {x  xs} {y  ys} (inl p) (inr q) = ⊥-elim (irrefl (subst (_< _) (sym (fst q)) p))
≤′-antisym {x  xs} {y  ys} (inr p) (inl q) = ⊥-elim (irrefl (subst (_< _) (sym (fst p)) q))
≤′-antisym {x  xs} {y  ys} (inr (p , ps)) (inr (_ , qs)) = cong₂ _∷_ p (≤′-antisym ps qs)

≤′-refl : Reflexive _≤′_
≤′-refl {[]} = Poly.tt
≤′-refl {x  xs} = inr (refl , ≤′-refl)

<′-asym : Asymmetric _<′_
<′-asym {x  xs} {y  ys} (inl p) (inl q) = asym p q
<′-asym {x  xs} {y  ys} (inl p) (inr q) = irrefl (subst (_< _) (sym (fst q)) p)
<′-asym {x  xs} {y  ys} (inr p) (inl q) = irrefl (subst (_< _) (sym (fst p)) q)
<′-asym {x  xs} {y  ys} (inr p) (inr q) = <′-asym (snd p) (snd q)


≮′⇒≥′ :  {xs ys}  ¬ (xs <′ ys)  ys ≤′ xs
≮′⇒≥′ {xs} {[]} p = Poly.tt
≮′⇒≥′ {[]} {y  ys} p = ⊥-elim (p _)
≮′⇒≥′ {x  xs} {y  ys} xs≮ys with compare x y
≮′⇒≥′ {x  xs} {y  ys} xs≮ys | lt x<y = ⊥-elim (xs≮ys (inl x<y))
≮′⇒≥′ {x  xs} {y  ys} xs≮ys | eq x≡y = inr (sym x≡y , ≮′⇒≥′ (xs≮ys  inr  _,_ x≡y))
≮′⇒≥′ {x  xs} {y  ys} xs≮ys | gt x>y = inl x>y

<′-conn : Connected _<′_
<′-conn xs≮ys ys≮xs = ≤′-antisym (≮′⇒≥′ ys≮xs) (≮′⇒≥′ xs≮ys)

<′-irrefl : Irreflexive _<′_
<′-irrefl {x  xs} (inl x<x) = irrefl x<x
<′-irrefl {x  xs} (inr xs<xs) = <′-irrefl (snd xs<xs)

≰′⇒>′ :  {xs ys}  ¬ (xs ≤′ ys)  ys <′ xs
≰′⇒>′ {[]} xs≰ys = ⊥-elim (xs≰ys _)
≰′⇒>′ {x  xs} {[]} xs≰ys = Poly.tt
≰′⇒>′ {x  xs} {y  ys} xs≰ys with compare x y
≰′⇒>′ {x  xs} {y  ys} xs≰ys | lt x<y = ⊥-elim (xs≰ys (inl x<y))
≰′⇒>′ {x  xs} {y  ys} xs≰ys | eq x≡y = inr (sym x≡y , ≰′⇒>′ (xs≰ys  inr  _,_ x≡y))
≰′⇒>′ {x  xs} {y  ys} xs≰ys | gt x>y = inl x>y

≮′-cons :  {x y xs ys}  x  y  ¬ (xs <′ ys)  ¬ (x  xs <′ y  ys)
≮′-cons x≡y xs≮ys (inl x<y) = irrefl (subst (_< _) x≡y x<y)
≮′-cons x≡y xs≮ys (inr (x≡y₁ , x∷xs<y∷ys)) = xs≮ys x∷xs<y∷ys

_<′?_ : Decidable _<′_
xs <′? [] = no  ())
[] <′? (y  ys) = yes Poly.tt
(x  xs) <′? (y  ys) with compare x y
((x  xs) <′? (y  ys)) | lt x<y = yes (inl x<y)
((x  xs) <′? (y  ys)) | eq x≡y = map-dec (inr  _,_ x≡y) (≮′-cons x≡y) (xs <′? ys)
((x  xs) <′? (y  ys)) | gt x>y = no (<′-asym (inl x>y))

listOrd : TotalOrder (List E) _ _
StrictPreorder._<_   (StrictPartialOrder.strictPreorder (TotalOrder.strictPartialOrder listOrd)) = _<′_
StrictPreorder.trans (StrictPartialOrder.strictPreorder (TotalOrder.strictPartialOrder listOrd)) = <′-trans
StrictPreorder.irrefl  (StrictPartialOrder.strictPreorder (TotalOrder.strictPartialOrder listOrd)) = <′-irrefl
StrictPartialOrder.conn (TotalOrder.strictPartialOrder listOrd) = <′-conn
Preorder._≤_   (PartialOrder.preorder (TotalOrder.partialOrder listOrd)) = _≤′_
Preorder.refl  (PartialOrder.preorder (TotalOrder.partialOrder listOrd)) = ≤′-refl
Preorder.trans (PartialOrder.preorder (TotalOrder.partialOrder listOrd)) = ≤′-trans
PartialOrder.antisym (TotalOrder.partialOrder listOrd) = ≤′-antisym
TotalOrder._<?_ listOrd = _<′?_
TotalOrder.≰⇒> listOrd = ≰′⇒>′
TotalOrder.≮⇒≥ listOrd = ≮′⇒≥′