{-# OPTIONS --safe #-}

open import Prelude hiding (_↔_)

module Data.Permutation.NonNorm {A : Type a} (_≟_ : Discrete A) where

open import Data.Permutation.Swap _≟_

open import Data.List hiding ([]; _∷_)
import Data.List as ConsR

Swaps : Type a
Swaps = List (A × A)

infixl 5 _∘⟨_⟩
pattern _∘⟨_⟩ xs x = x ConsR.∷ xs

pattern ⟨⟩ = ConsR.[]

infixr 4.5 _·_
_·_ : Swaps  A  A
_·_ = flip (foldl (flip (uncurry _↔_·_)))

-- We can't really compute the support without first removing ids from the list
-- 
-- supp-swaps : Swaps → List A
-- supp-swaps = foldr (λ { (x , y) xs → xs ∘⟨ y ⟩ ∘⟨ x ⟩ }) ⟨⟩

swap-inj :  x y z₁ z₂  x  y · z₁  x  y · z₂  z₁  z₂
swap-inj x y z₁ z₂ p with does (x  z₁)
                        | why  (x  z₁)
                        | does (x  z₂)
                        | why  (x  z₂)
                        | does (y  z₁)
                        | why  (y  z₁)
                        | does (y  z₂)
                        | why  (y  z₂)
... | true | x≡z₁ | true | x≡z₂ | _ | _ | _ | _ = sym x≡z₁ ; x≡z₂
... | _ | _ | _ | _ | true | y≡z₁ | true | y≡z₂ = sym y≡z₁ ; y≡z₂
... | false | _ | false | _ | false | _ | false | _ = p
... | false | x≢z₁ | false | _ | false | _ | true | _ = ⊥-elim (x≢z₁ (sym p))
... | false | _ | false | x≢z₂ | true | _ | false | _ = ⊥-elim (x≢z₂ p)
... | false | _ | true | _ | false | y≢z₁ | _ | _ = ⊥-elim (y≢z₁ (sym p))
... | false | x≢z₁ | true | _ | true | y≡z₁ | _ | _ = ⊥-elim (x≢z₁ (p ; y≡z₁))
... | true | _ | false | x≢z₁ | true | _ | false | y≢z₂ = ⊥-elim (y≢z₂ p)
... | true | _ | false | _ | false | _ | false | y≢z₂ = ⊥-elim (y≢z₂ p)
... | true | x≡z₁ | false | x≢z₂ | false | y≢z₁ | true | y≡z₂ = ⊥-elim (y≢z₁ (p ; x≡z₁))

perm-inj :  xs z₁ z₂  xs · z₁  xs · z₂  z₁  z₂
perm-inj ⟨⟩              z₁ z₂ p = p
perm-inj (xs ∘⟨ x , y ) z₁ z₂ p =
  swap-inj x y z₁ z₂ (perm-inj xs (x  y · z₁) (x  y · z₂) p)

infixl 6 _∙_
_∙_ : Swaps  Swaps  Swaps
xs  ys = ys ++ xs

open import Path.Reasoning
open import Data.List.Properties

∙-· :  xs ys n  xs  ys · n  xs · ys · n
∙-· xs ys n = foldl-++ (flip (uncurry _↔_·_)) n ys xs

neg : Swaps  Swaps
neg = reverse


open import Path.Reasoning

neg-id-lemma :  xs n  foldl (flip (uncurry _↔_·_)) (foldr (uncurry _↔_·_) n xs) xs  n
neg-id-lemma ⟨⟩ n = refl
neg-id-lemma (xs ∘⟨ x , y ) n =
  foldl (flip (uncurry _↔_·_)) (x  y · x  y · foldr (uncurry _↔_·_) n xs) xs ≡⟨ cong (flip (foldl (flip (uncurry _↔_·_))) xs) (swap-dup x y (foldr (uncurry _↔_·_) n xs)) 
  foldl (flip (uncurry _↔_·_)) (foldr (uncurry _↔_·_) n xs) xs ≡⟨ neg-id-lemma xs n 
  n 

neg-id-lemma₂ :  xs n  foldl (flip (uncurry _↔_·_)) n (foldl _∘⟨_⟩ ⟨⟩ xs)  foldr (uncurry _↔_·_) n xs
neg-id-lemma₂ xs n =
  foldl (flip (uncurry _↔_·_)) n (reverse xs) ≡˘⟨ foldr-reverse _ _ (reverse xs) 
  foldr (uncurry _↔_·_) n (reverse (reverse xs)) ≡⟨ cong (foldr (uncurry _↔_·_) n) (reverse-reverse xs) 
  foldr (uncurry _↔_·_) n xs 

neg-id :  xs n  xs  neg xs · n  n
neg-id xs n =
  xs  neg xs · n ≡⟨⟩
  neg xs ++ xs · n ≡⟨ foldl-++ (flip (uncurry _↔_·_)) n (neg xs) xs 
  foldl (flip (uncurry _↔_·_)) (neg xs · n) xs ≡⟨⟩
  foldl (flip (uncurry _↔_·_)) (foldl (flip (uncurry _↔_·_)) n (neg xs)) xs ≡⟨⟩
  foldl (flip (uncurry _↔_·_)) (foldl (flip (uncurry _↔_·_)) n (foldl _∘⟨_⟩ ⟨⟩ xs)) xs
    ≡⟨ cong (flip (foldl (flip (uncurry _↔_·_))) xs) (neg-id-lemma₂ xs n) 
  foldl (flip (uncurry _↔_·_)) (foldr (uncurry _↔_·_) n xs) xs
    ≡⟨ neg-id-lemma xs n 
  n 
  
∙-assoc :  xs ys zs  (xs  ys)  zs  xs  (ys  zs)
∙-assoc xs ys zs = sym (++-assoc zs ys xs)