-- | A list of sample offsets and sizes of a track. This tells the decoder where
-- stuff inside an 'mdat' box is, and also where the 'mdat' box /starts/, which
-- is the reason why currently there are several TODOs concercning the offset
-- calculation.
module Data.ByteString.IsoBaseFileFormat.Boxes.TrackRun (trackRunIso5, TrackRun) where

import Data.ByteString.IsoBaseFileFormat.Box
import Data.ByteString.IsoBaseFileFormat.ReExports
import qualified Data.ByteString as BS

-- | Create a track run box. First parameter is the accumulated offset to the
-- /moof/ box. This is needed for data offset calculation. Then follows a list
-- of __sample-duration__ and __sample-sizes__. All samples are flagged
-- /independent/.
trackRunIso5 :: Int32 -> [(Word32, BS.ByteString)] -> Box TrackRun
trackRunIso5 !mdatOffset !samples = Box c
  where
    !c = TrackRun (header <> body)
      where
        !header = h (fromIntegral sampleCount) dataOffset
          where
            !dataOffset       = 8 -- box size field + fourcc code of this very box
                                  + mdatOffset + 8  -- +8 because we want to skip the box header od the mdat box
                                  + fromIntegral
                                  ((headerStaticSize `div` 8)
                                   + sampleCount * (sampleStaticSize `div` 8))
            !h                = bitBuilderWithSize (Proxy @(Header TrackRunFlagsIso5))
            !headerStaticSize = (natVal (Proxy @(SizeInBits (Header TrackRunFlagsIso5))))
            !sampleStaticSize = (natVal (Proxy @(SizeInBits (Sample TrackRunFlagsIso5))))
            !sampleCount      = fromIntegral (length samples)

        !body = mconcat $ s <$> samples
          where
            s (!duration, !bs) = bitBuilderWithSize (Proxy @(Sample TrackRunFlagsIso5)) duration size
              where
                !size = fromIntegral (BS.length bs)

newtype TrackRun where
  TrackRun :: BuilderWithSize -> TrackRun
  deriving (IsBoxContent)

instance IsBox TrackRun
type instance BoxTypeSymbol TrackRun = "trun"

-- class MkTrackRunArgs (t :: Extends (TrackRunFlags sop fsp sdp ssp sfp sop)) where
--   data TrRunArgs (t :: Extends (TrackRunFlags sop fsp sdp ssp sfp sop))

data TrackRunFlags
  (dataOffsetPresent :: Bool)
  (firstSampleFlagsPresent :: Bool)
  (sampleDurationPresent :: Bool)
  (sampleSizePresent :: Bool)
  (sampleFlagsPresent :: Bool)
  (sampleCompositionTimeOffsetPresent :: Bool)

data TrackRunFlagsIso5
  :: Extends (TrackRunFlags 'True 'False 'True 'True 'True 'False)

type Header (t :: Extends (TrackRunFlags dop fsp sdp ssp sfp sctop)) =
      "version"                   @: FieldU8  := 0 -- TODO allow version 1
  .+:                                Field 12 := 0
  .+: "sample-scto-present"       @: Flag     := sctop
  .+: "sample-flags-present"      @: Flag     := sfp
  .+: "sample-size-present"       @: Flag     := ssp
  .+: "sample-duration-present"   @: Flag     := sdp
  .+:                                Field  5 := 0
  .+: "first-sample-flag-present" @: Flag     := fsp
  .+:                                Flag     := 'False
  .+: "data-offset-preset"        @: Flag     := dop
  .+: 'RecordField ("sample-count"  @:: FieldU32)
  :+: WhenR dop
        ('BitRecordMember ("data-offset"        @: FieldI32))
  :+: WhenR fsp
        ('RecordField ("first-sample-flags" @:: FieldU32))


type Sample (t :: Extends (TrackRunFlags dop fsp sdp ssp sfp sctop)) =
      WhenR sdp ('RecordField ("sample-duration" @:: FieldU32))
  :+: WhenR ssp ('RecordField ("sample-size"     @:: FieldU32))
  :+: WhenR sfp ('RecordField ("sample-flags"    @:: FieldU32 :=. 0x02000000))
      -- TODO allow flags as in TrackExtends