module Opentype.Fileformat.Head where
import Opentype.Fileformat.Types
import Data.Time
import Data.Binary
import Data.Binary.Get
import Data.Binary.Put
import Control.Monad
import Data.Int
data HeadTable = HeadTable {
  
  headVersion :: Fixed,
  
  fontRevision :: Fixed,
  
  baselineYZero :: Bool,
  
  sidebearingXZero :: Bool,
  
  pointsizeDepend :: Bool,
  
  
  integerScaling :: Bool,  
  
  alterAdvanceWidth :: Bool,
  
  
  
  
  
  
  verticalFont :: Bool,
  
  
  linguisticRenderingLayout :: Bool,
  
  
  metamorphosisEffects :: Bool,
  
  
  rightToLeftGlyphs :: Bool,
  
  
  indicRearrangements :: Bool,
  
  
  
  
  
  
  
  
  losslessFontData :: Bool,
  
  convertedFont :: Bool,
  
  
  
  
  clearTypeOptimized :: Bool,
    
  
  
  
  
  lastResortFont :: Bool,
  
  
  
  unitsPerEm :: Word16,
  created :: UTCTime,  modified :: UTCTime,
  
  xMin :: FWord,
  
  yMin :: FWord,
  
  xMax :: FWord,
  
  yMax :: FWord,
  
  
  boldStyle :: Bool,
  italicStyle :: Bool,
  underlineStyle :: Bool,
  outlineStyle :: Bool,
  shadowStyle :: Bool,
  condensedStyle :: Bool,
  extendedStyle :: Bool,
  
  lowerRecPPEM :: Word16,
  
  fontDirectionHint :: Int16,
  
  longLocIndices :: Bool,
  
  glyphDataFormat :: Int16
  }
  deriving Show
getHeadTable :: Get HeadTable
getHeadTable = do
    major <- getWord16be
    minor <- getWord16be
    when (major /= 1 && minor /= 0)
      (fail "Invalid head table")
    revision <- getWord32be
    _ <- getWord32be
    magic <- getWord32be
    when (magic /= 0x5F0F3CF5)
      (fail "Invalid magic value in head table")
    flags <- getWord16be
    uPe <- getWord16be
    created_ <- getInt64be
    modified_ <- getInt64be
    xMin_ <- getInt16be
    yMin_ <- getInt16be
    xMax_ <- getInt16be
    yMax_ <- getInt16be
    mcStyle <- getWord16be
    lRec <- getWord16be
    fDir <- getInt16be
    iToL <- getInt16be
    gd <- getInt16be
    let flagAt = byteAt flags
        styleAt = byteAt mcStyle
    return $ HeadTable 0x00010000 revision
      (flagAt 0) (flagAt 1) (flagAt 2) (flagAt 3)
      (flagAt 4) (flagAt 5) (flagAt 7) (flagAt 8) (flagAt 9)
      (flagAt 10) (flagAt 11) (flagAt 12) (flagAt 13) (flagAt 14) 
      uPe (getTime created_) (getTime modified_)
      xMin_ yMin_ xMax_ yMax_
      (styleAt 0) (styleAt 1) (styleAt 2) (styleAt 3) (styleAt 4)
      (styleAt 5) (styleAt 6) lRec fDir (iToL /= 0) gd
putHeadTable :: HeadTable -> Put
putHeadTable headTbl = do
  putWord16be 1
  putWord16be 0
  putWord32be $ fontRevision headTbl
  putWord32be 0
  putWord32be 0x5F0F3CF5
  putWord16be $ makeFlag $ map ($ headTbl)
    [baselineYZero, sidebearingXZero, pointsizeDepend, integerScaling, alterAdvanceWidth,
    const False, verticalFont, linguisticRenderingLayout, metamorphosisEffects, rightToLeftGlyphs,
    indicRearrangements, losslessFontData, convertedFont, clearTypeOptimized, lastResortFont, const False]
  putWord16be $ unitsPerEm headTbl
  putInt64be $ putTime $ created headTbl
  putInt64be $ putTime $ modified headTbl
  putInt16be $ xMin headTbl
  putInt16be $ yMin headTbl
  putInt16be $ xMax headTbl
  putInt16be $ yMax headTbl
  putWord16be $ makeFlag $ map ($ headTbl)
    [boldStyle, italicStyle, underlineStyle, outlineStyle, shadowStyle, condensedStyle, extendedStyle]
  putWord16be $ lowerRecPPEM headTbl
  putInt16be 2 
  putInt16be $ fromIntegral $ fromEnum $ longLocIndices headTbl
  putInt16be 0 
secDay :: Int64
secDay = 60 * 60 * 24
diffSeconds :: Int64
diffSeconds =
  secDay * fromIntegral (fromGregorian 1858 11 17 `diffDays` fromGregorian 1904 1 1)
getTime :: Int64  -> UTCTime
getTime secs = UTCTime (ModifiedJulianDay $ fromIntegral d) (secondsToDiffTime $ fromIntegral t)
  where (d,t) = (secs  diffSeconds) `quotRem` fromIntegral secDay
putTime :: UTCTime -> Int64
putTime (UTCTime (ModifiedJulianDay d) t) =
  fromIntegral d * secDay + diffTimeToSeconds t + diffSeconds
diffTimeToSeconds :: DiffTime -> Int64
diffTimeToSeconds d =
  fromIntegral $ diffTimeToPicoseconds d `quot` 1000000000