{-# LANGUAGE UndecidableInstances #-}

module Data.MediaBus.Segment
    ( CanSegment(..)
    , Segment(..)
    , segmentContent
    ) where

import           Data.MediaBus.Ticks
import           Control.Lens
import           Data.Default
import           Data.Proxy
import           Test.QuickCheck
import           Control.DeepSeq
import           Text.Printf

-- | A segment is some content with a fixed (type level) duration.
newtype Segment (duration :: StaticTicks) c = MkSegment { _segmentContent :: c }
    deriving (NFData, Default, Arbitrary, Functor, Eq)

instance (HasStaticDuration d, Show c) =>
         Show (Segment d c) where
    show (MkSegment c) = printf "[| %s |%10s]"
                                (show c)
                                (show (getStaticDuration (Proxy :: Proxy d)))

makeLenses ''Segment

instance KnownStaticTicks d =>
         HasStaticDuration (Segment d x) where
    type SetStaticDuration (Segment d x) pt = Segment pt x
    type GetStaticDuration (Segment d x) = d

instance HasStaticDuration d =>
         HasDuration (Segment d x) where
    getDuration _ = getStaticDuration (Proxy :: Proxy d)

-- | Class of types that support splitting of from the front a packet containing
-- roughly a certain duration.
class CanSegment a where
    -- | Try to split the packet into the a part which has at most the given
    -- duration and a rest. If not possible, e.g. because the input data is
    -- already shorter than the given duration, return `Nothing`.
    splitAfterDuration :: (HasStaticDuration d)
                       => proxy d
                       -> a
                       -> Maybe (Segment d a, a)-- TODO make the repacketization create ONLY valid sized packets, even if that means dropping content
                                                       -- TODO allow repacketization to combine the packets
                                                       -- TODO use 'Segment' to automatically derive the ptime