module Chapter.Fun.Division where

open import Library.Nat
open import Library.Nat.Properties
open import Library.List
open import Library.Logic
open import Library.Equality
open import Library.Equality.Reasoning
open import Library.LessThan
open import Library.LessThan.Reasoning renaming (begin_ to <=begin_; _end to _<=end) hiding (_==⟨_⟩_)
open import Library.WellFounded

+-minus-assoc : (x y z : ) -> z <= y -> x + (y - z) == (x + y) - z
+-minus-assoc x y 0 le-zero =
  begin
    x + (y - 0) ==⟨ cong (x +_) (minus-zero y) 
    x + y       ==⟨ symm (minus-zero (x + y)) 
    (x + y) - 0
  end
+-minus-assoc x (succ y) (succ z) (le-succ le) =
  begin
    x + (succ y - succ z) ==⟨⟩
    x + (y - z)           ==⟨ +-minus-assoc x y z le 
    (x + y) - z           ==⟨ refl 
    succ (x + y) - succ z ==⟨ refl 
    (succ x + y) - succ z ==⟨ cong (_- succ z) (+-succ x y) 
    (x + succ y) - succ z
  end

{-# TERMINATING #-}
nt-division : (x y : ) -> (0 < y) -> ∃[ q ] ∃[ r ] (r < y)  (q * y + r == x)
nt-division x y 0<y with x <? y
... | inr lt = 0 , x , lt , refl
... | inl nlt with not-lt-ge nlt
... | ge with nt-division (x - y) y 0<y
... | q , r , r<y , qy=x = succ q , r , r<y , eq
  where
    eq : succ q * y + r == x
    eq = begin
           succ q * y + r  ==⟨⟩
           y + q * y + r   ==⟨ symm (+-assoc y (q * y) r) 
           y + (q * y + r) ==⟨ cong (y +_) qy=x 
           y + (x - y)     ==⟨ +-minus-assoc y x y ge 
           (y + x) - y     ==⟨ +-minus y x 
           x
         end
open import Library.LessThan.Alternative

accessible<' : (x y : ) -> y <' x -> Accessible _<'_ y
accessible<' (succ y) _ le-refl'      = acc (accessible<' y)
accessible<' (succ y) z (le-succ' lt) = accessible<' y z lt

well-founded-lt' : WellFounded _<'_
well-founded-lt' x = acc (accessible<' x)

_<'?_ : (x y : ) -> Decidable (x <' y)
x <'? y with x <? y
... | inr x<y = inr (<=to<=' x<y)
... | inl ¬x<y = inl λ x<y -> ¬x<y (<='to<= x<y)

minus-succ : {x y : } -> (y < x) -> (x - succ y < x - y)
minus-succ {succ x} {zero} p rewrite minus-zero x = le-refl
minus-succ {succ x} {succ y} (le-succ p) = minus-succ p

minus-le : (x y : ) -> (x - y <= x)
minus-le zero     _        = le-zero
minus-le (succ _) zero     = le-refl
minus-le (succ x) (succ y) = le-succ-r (minus-le x y)

minus-lt : {x y : } -> (0 < y) -> (y <= x) -> (x - y < x)
minus-lt {x} {succ y} _ q =
  <=begin
    x - succ y <⟨ minus-succ q 
    x - y      <=⟨ minus-le x y 
    x
  <=end

minus-lt' : {x y : } -> (0 <' y) -> (y <=' x) -> (x - y <' x)
minus-lt' p q = <=to<=' (minus-lt (<='to<= p) (<='to<= q))

not-lt-ge' : {x y : } -> ¬ (x <' y) -> (y <=' x)
not-lt-ge' p = <=to<=' (not-lt-ge λ q -> p (<=to<=' q))

div-rem-aux : (x y : ) -> 0 <' y -> Accessible _<'_ x -> ∃[ q ] ∃[ r ] r <' y  q * y + r == x
div-rem-aux x y p (acc f) with x <'? y
... | inr lt = 0 , x , lt , refl
... | inl nlt with not-lt-ge' nlt
... | ge with div-rem-aux (x - y) y p (f (x - y) (minus-lt' p ge))
... | q , r , r<y , qy=x =
  succ q , r , r<y , (
    begin
      succ q * y + r  ==⟨⟩
      y + q * y + r   ==⟨ symm (+-assoc y (q * y) r) 
      y + (q * y + r) ==⟨ cong (y +_) qy=x 
      y + (x - y)     ==⟨ +-minus-assoc y x y (<='to<= ge) 
      (y + x) - y     ==⟨ +-minus y x 
      x
    end)

division : (x y : ) -> (0 < y)-> ∃[ q ] ∃[ r ] (r < y)  (q * y + r == x)
division x y 0<y with div-rem-aux x y (<=to<=' 0<y) (well-founded-lt' x)
... | q , r , r<y , qy=x = q , r , <='to<= r<y , qy=x