-- | Module to read a jpeg file and split it into segments.
-- This module is an internal module of Graphics.Hexif and should only be used in the hexif project!
module Graphics.Hexif.Jpeg 
  ( Jpeg
  , readJpegFromFile
  , extractExif
) where

import Data.Binary
import Data.Binary.Get   {-( Get
                      , getWord8
                      , getWord16be
                      , getByteString
                      , skip
                      , bytesRead
                      )   -}

import qualified Data.ByteString.Lazy as BL

-- | A JPEG file is a list of so called segments
data Jpeg = Jpeg
    { segments :: [JpegSegment]
 -- , imageData :: B.ByteString      -- later needed for write version
    } 
    deriving Eq

-- | A segment contains an identifying marker and a length
data JpegSegment = JpegSegment
    { segMarker :: Int 
    , segData :: BL.ByteString 
    -- , offset :: Integer              -- for debugging only
    }
    deriving (Eq)
  
-- | Read a Jpeg value from a file
readJpegFromFile :: String -> IO Jpeg
readJpegFromFile fn = do
   bsJpeg <- BL.readFile fn
   return $ readJpeg bsJpeg

-- | Extract the Exif segment from a JPEG value
extractExif :: Jpeg -> BL.ByteString
extractExif jpeg = segData $ head (filter (\seg -> segMarker seg == 0xFFE1) (segments jpeg))

-- | Read a Jpeg value form a lazy ByteString
readJpeg :: BL.ByteString -> Jpeg
readJpeg = runGet getJpeg
  where
    getJpeg :: Get Jpeg
    getJpeg = do
        _ <- getWord16be
        segs <- getSegments 
        return $ Jpeg segs 

-- | get all the segments
getSegments :: Get [JpegSegment]
getSegments = do
    seg <- getSegment
    if segMarker seg == 0xFFDA
        then return [seg]
        else do 
          segs <- getSegments
          return $ seg : segs

-- | get the next segment
getSegment :: Get JpegSegment
getSegment = do
     marker <- getWord16be
     _ <- bytesRead
     len <- getWord16be
     sgData <- getLazyByteString (fromIntegral len - 2)
     return $ JpegSegment (fromIntegral marker) sgData