{-# LANGUAGE GADTs #-}





-----------------------------------------------------------------------------
-- |
-- Module      :  Data.TASequence.FingerTree
-- Copyright   :  (c) Atze van der Ploeg 2014
-- License     :  BSD-style
-- Maintainer  :  atzeus@gmail.org
-- Stability   :  provisional
-- Portability :  portable
--
-- A type aligned sequence, a catanable deque, with amortized /O(log n)/ case constant time: '><','<|',|>', 'tviewl' and 'tviewr'.
--
-- Based on:  "Finger trees: a simple general-purpose data structure"
--   Ralf Hinze and Ross Paterson. in Journal of Functional Programming16:2 (2006), pages 197-217.
--
-----------------------------------------------------------------------------
module Data.TASequence.FingerTree (module Data.TASequence.Class, FingerTree ) where



import Data.TASequence.Class


data FingerTree r a b where
  Empty  :: FingerTree r a a
  Single :: r a b -> FingerTree r a b
  Deep   :: !(Digit r a b) -> FingerTree (Node r) b c -> !(Digit r c d) -> FingerTree r a d


data Node r a b where
  Node2 :: r a b -> r b c -> Node r a c
  Node3 :: r a b -> r b c -> r c d -> Node r a d

data Digit r a b where
  One   :: r a b -> Digit r a b
  Two   :: r a b -> r b c -> Digit r a c
  Three :: r a b -> r b c -> r c d -> Digit r a d
  Four  :: r a b -> r b c -> r c d -> r d e -> Digit r a e

instance TASequence FingerTree where
  tempty = Empty
  tsingleton = Single

  Empty                     |> a = Single a
  Single b                  |> a = Deep (One b) Empty (One a)
  Deep pr m (Four e d c b)  |> a = Deep pr (m |> Node3 e d c) (Two b a)
  Deep pr m sf              |> a = Deep pr m (appendd sf (One a))

  a <| Empty                     = Single a
  a <| Single b                  = Deep (One a) Empty (One b) 
  a <| Deep (Four b c d e) m sf  = Deep (Two a b) (Node3 c d e <| m) sf
  a <| Deep pr m sf              = Deep (appendd (One a) pr) m sf

  tviewl Empty = TAEmptyL
  tviewl (Single a) = a :< Empty
  tviewl (Deep pr m sf) = case toList pr of
              h ::: t -> h :< deepl t m sf

  tviewr Empty = TAEmptyR
  tviewr (Single a) = Empty :> a 
  tviewr (Deep pr m sf) = case toListR sf of
            h :::< t -> deepr pr m t :> h

  xs >< ys = app3 xs ZNil ys



toTree :: Digit r a b -> FingerTree r a b
toTree (One a)         = Single a
toTree (Two a b)       = Deep (One a) Empty (One b)
toTree (Three a b c)   = Deep (Two a b) Empty (One c)
toTree (Four a b c d)  = Deep (Two a b) Empty (Two c d)


appendd :: Digit r a b -> Digit r b c -> Digit r a c
appendd (One a)        (One b)        = Two a b
appendd (One a)        (Two b c)      = Three a b c
appendd (Two a b)      (One c)        = Three a b c
appendd (One a)        (Three b c d)  = Four a b c d
appendd (Two a b)      (Two c d)      = Four a b c d
appendd (Three a b c)  (One d)        = Four a b c d






infixr 5 ::: 


data ZList r a b where
  ZNil :: ZList r a a
  (:::) :: r a b -> ZList r b c -> ZList r a c

toList (One a) = a ::: ZNil 
toList (Two a b) = a ::: b ::: ZNil
toList (Three a b c) = a ::: b ::: c ::: ZNil
toList (Four a b c d) = a ::: b ::: c ::: d ::: ZNil




fromList :: ZList r a b -> Digit r a b
fromList (a ::: ZNil) = One a
fromList (a ::: b ::: ZNil) = Two a b
fromList (a ::: b ::: c ::: ZNil) = Three a b c
fromList (a ::: b ::: c ::: d ::: ZNil) = Four a b c d

append :: ZList r a b -> ZList r b c -> ZList r a c
append ZNil t = t
append (h ::: t) r = h ::: append t r


deepl :: ZList r a b -> FingerTree (Node r) b c -> Digit r c d -> FingerTree r a d
deepl ZNil m sf = case tviewl m of
           TAEmptyL -> toTree sf
           a :< m' -> Deep (nodeToDigit a) m' sf 
deepl pr m sf = Deep (fromList pr) m sf

infixr 5 :::< 

data ZListR r a b where
  ZNilR :: ZListR r a a
  (:::<) :: r b c -> ZListR r a b -> ZListR r a c

toListR :: Digit r a b -> ZListR r a b
toListR (One a) = a :::< ZNilR
toListR (Two a b) = b :::< a :::< ZNilR
toListR (Three a b c) = c :::< b :::< a :::< ZNilR
toListR (Four a b c d) = d:::< c :::< b :::< a :::< ZNilR



fromListR :: ZListR r a b -> Digit r a b
fromListR (a :::< ZNilR) = One a
fromListR (b :::< a :::< ZNilR) = Two a b
fromListR (c :::< b :::< a :::< ZNilR) = Three a b c
fromListR (d :::< c :::< b :::< a :::< ZNilR) = Four a b c d


rev = toList . fromListR 



deepr :: Digit r a b -> FingerTree (Node r) b c -> ZListR r c d -> FingerTree r a d
deepr pr m ZNilR = case tviewr m of
           TAEmptyR -> toTree pr
           m' :> a -> Deep pr m' (nodeToDigit a)
deepr pr m sf = Deep pr m (fromListR sf)


nodeToDigit :: Node r a b -> Digit r a b
nodeToDigit (Node2 a b) = Two a b
nodeToDigit (Node3 a b c) = Three a b c



addAlll :: ZList r a b -> FingerTree r b c -> FingerTree r a c
addAlll ZNil m = m
addAlll (h ::: t) m = h <| addAlll t m

addAllr :: FingerTree r a b -> ZList r b c  -> FingerTree r a c
addAllr m ZNil  = m
addAllr m (h ::: t) = addAllr (m |> h) t

  

app3 :: FingerTree r a b -> ZList r b c -> FingerTree r c d -> FingerTree r a d
app3 Empty ts xs = addAlll ts xs
app3 xs ts Empty = addAllr xs ts
app3 (Single x) ts xs = x <| (addAlll ts xs)
app3 xs ts (Single x) = (addAllr xs ts) |> x
app3 (Deep pr1 m1 sf1) ts (Deep pr2 m2 sf2) =
    Deep pr1 
        (app3 m1 (nodes (append (toList sf1) (append ts (toList pr2)))) m2) sf2


nodes :: ZList r a b -> ZList (Node r) a b
nodes (a ::: b ::: ZNil) = Node2 a b ::: ZNil
nodes (a ::: b ::: c ::: ZNil) = Node3 a b c ::: ZNil
nodes (a ::: b ::: c ::: d ::: ZNil) = Node2 a b ::: Node2 c d ::: ZNil
nodes (a ::: b ::: c ::: xs) = Node3 a b c ::: nodes xs