module Graphics.Exif (Exif, 
                      fromFile, fromData, 
                      getTag, allTags) where

import Graphics.Exif.Internals

import Control.Monad
import Foreign


newtype Exif = Exif (ForeignPtr ExifData)


fromFile :: FilePath -> IO Exif
fromFile f = dataFromFile f >>= mkExif

fromData :: Ptr () -> Int -> IO Exif
fromData p c = dataFromData p c >>= mkExif

getTag :: Exif -> String -> IO (Maybe String)
getTag x s = withExif x f
    where f d = do t <- tagFromName s
                   es <- dataGetEntries d
                   e <- firstFilterM (entryHasTag t) es
                   maybe (return Nothing) (fmap Just . entryGetValue) e

allTags :: Exif -> IO [(String,String)]
allTags x = withExif x f
    where f d = dataGetEntries d >>= mapM g
          g e = do t <- entryGetTag e
                   n <- tagName t
                   v <- entryGetValue e
                   return (n,v)

-- Internal stuff

mkExif :: Ptr ExifData -> IO Exif
mkExif p | p == nullPtr = fail "mkExif: NULL"
         | otherwise = liftM Exif $ newForeignPtr dataFree p

withExif :: Exif -> (Ptr ExifData -> IO a) -> IO a
withExif (Exif e) f = withForeignPtr e f

dataGetEntries :: Ptr ExifData -> IO [Ptr ExifEntry]
dataGetEntries d = dataGetContents d >>= liftM concat . mapM contentGetEntries

entryHasTag :: ExifTag -> Ptr ExifEntry -> IO Bool
entryHasTag t e = liftM (==t) $ entryGetTag e


-- Utilities

firstFilterM :: Monad m => (a -> m Bool) -> [a] -> m (Maybe a)
firstFilterM _ []     = return Nothing
firstFilterM f (x:xs) = 
    f x >>= \b -> if b then return (Just x) else firstFilterM f xs