\import Data.List
\import Logic
\import Order.LinearOrder
\import Order.StrictOrder
\import Paths
\import Paths.Meta
\open LinearOrder

\instance LexicographicalProduct (A B : Dec) : Dec (\Sigma A B)
  | < a b => a.1 < b.1 || (\Sigma (a.1 = b.1) (a.2 < b.2))
  | <-irreflexive {t} => \case __ \with {
    | byLeft c => <-irreflexive c
    | byRight (_,c) => <-irreflexive c
  }
  | <-transitive => \case __, __ \with {
    | byLeft x<y, byLeft y<z => byLeft (x<y <∘ y<z)
    | byLeft x<y, byRight (y=z,_) => byLeft (rewriteI y=z x<y)
    | byRight (x=y,_), byLeft y<z => byLeft (rewrite x=y y<z)
    | byRight (x1=y1,x2<y2), byRight (y1=z1,y2<z2) => byRight (x1=y1 *> y1=z1, x2<y2 <∘ y2<z2)
  }
  | trichotomy t s => \case trichotomy t.1 s.1 \with {
    | less t1<s1 => less (byLeft t1<s1)
    | greater t1>s1 => greater (byLeft t1>s1)
    | equals t1=s1 => \case trichotomy t.2 s.2 \with {
      | less t2<s2 => less (byRight (t1=s1, t2<s2))
      | equals t2=s2 => equals (pmap2 (__,__) t1=s1 t2=s2)
      | greater t2>s2 => greater (byRight (inv t1=s1, t2>s2))
    }
  }

\instance LexicographicalList (A : Dec) : Dec (List A)
  | < => <L
  | <-irreflexive {l : List A} (p : l <L l) : Empty \elim l, p {
    | :: b bs, <head b<b => StrictPoset.<-irreflexive b<b
    | :: b bs, <tail _ bs<bs => <-irreflexive bs<bs
  }
  | <-transitive {as bs cs : List A} (as<bs : as <L bs) (bs<cs : bs <L cs) : as <L cs \elim as, bs, cs, as<bs, bs<cs {
    | nil, _, :: b bs, _, _ => nil<::
    | :: a as, :: b bs, :: c cs, <head a<b, <head b<c => <head (a<b <∘ b<c)
    | :: a as, :: b bs, :: c cs, <head a<b, <tail idp _ => <head a<b
    | :: a as, :: b bs, :: c cs, <tail idp _, <head b<c => <head b<c
    | :: a as, :: b bs, :: c cs, <tail a=b as<bs, <tail b=c bs<cs => <tail (a=b *> b=c) (<-transitive as<bs bs<cs)
  }
  | trichotomy (as bs : List A) : Tri {\new StrictPoset (List A) (<L) <-irreflexive <-transitive} as bs \with {
    | nil, nil => equals idp
    | nil, :: b bs => less nil<::
    | :: a as, nil => greater nil<::
    | :: a as, :: b bs => \case Dec.trichotomy a b \with {
      | less a<b => less (<head a<b)
      | equals a=b => \case trichotomy as bs \with {
        | less as<bs => less (<tail a=b as<bs)
        | equals as=bs => equals (pmap2 (::) a=b as=bs)
        | greater as>bs => greater (<tail (inv a=b) as>bs)
      }
      | greater a>b => greater (<head a>b)
    }
  }
  \where {
    \truncated \data \infix 4 <L {A : Dec} (l1 l2 : List A) : \Prop \elim l1, l2
      | nil, :: _ _ => nil<::
      | :: a as, :: b bs => {
        | <head (a < b)
        | <tail (a = b) (as <L bs)
      }
  }