{-# LANGUAGE GeneralizedNewtypeDeriving, DeriveDataTypeable, MultiParamTypeClasses, FlexibleContexts, TypeSynonymInstances #-}
module Data.Rope.Body
    ( Body
    , Offset(..)
    , Chunk(..)
    , measureBody
    , consBody
    , snocBody
    , packBody
    ) where

import Prelude hiding (null, length)
import Data.FingerTree (FingerTree,(<|),(|>),Measured,measure,empty, singleton)
import Data.Data
import Data.Monoid
import Data.ByteString (ByteString, null, length)

newtype Offset = Offset { getOffset :: Int } deriving (Eq,Ord,Num,Show,Read,Enum,Data,Typeable)

instance Monoid Offset where
    mempty = 0
    mappend = (+)

newtype Chunk = Chunk { unchunk :: ByteString } deriving (Eq,Ord,Show,Read,Data,Typeable)

instance Measured Offset Chunk where
    measure = Offset . length . unchunk

type Body = FingerTree Offset Chunk 

measureBody :: Measured Offset a => FingerTree Offset a -> Int
measureBody = getOffset . measure

consBody :: ByteString -> Body -> Body
b `consBody` t | null b = t
           | otherwise = Chunk b <| t

snocBody :: Body -> ByteString -> Body
t `snocBody` b | null b = t
           | otherwise = t |> Chunk b

packBody :: ByteString -> FingerTree Offset Chunk
packBody b | null b = empty
           | otherwise = singleton (Chunk b)