module Graphics.Rendering.Cairo.Types (
    PixelData
  , Matrix(Matrix), MatrixPtr
  , Cairo(Cairo), unCairo
  , Surface(Surface), withSurface, mkSurface, manageSurface
  , Pattern(Pattern), unPattern
  , Status(..)
  , Operator(..)
  , Antialias(..)
  , FillRule(..)
  , LineCap(..)
  , LineJoin(..)
  , ScaledFont(..), unScaledFont
  , FontFace(..), unFontFace
  , Glyph, unGlyph
  , TextExtentsPtr
  , TextExtents(..)
  , FontExtentsPtr
  , FontExtents(..)
  , FontSlant(..)
  , FontWeight(..)
  , SubpixelOrder(..)
  , HintStyle(..)
  , HintMetrics(..)
  , FontOptions(..), withFontOptions, mkFontOptions
  , Path(..), unPath
  , RectangleInt(..)
  , RegionOverlap(..)
  , Region(..), withRegion, mkRegion
  , Content(..)
  , Format(..)
  , Extend(..)
  , Filter(..)
  , cIntConv
  , cFloatConv
  , cFromBool
  , cToBool
  , cToEnum
  , cFromEnum
  , peekFloatConv
  , withFloatConv
  ) where
import Graphics.Rendering.Cairo.Matrix
import Foreign hiding (rotate)
import Foreign.C
import Control.Monad (liftM)
type PixelData = Ptr CUChar
newtype Cairo = Cairo (Ptr (Cairo))
unCairo (Cairo x) = x
newtype Surface = Surface (ForeignPtr (Surface))
withSurface (Surface x) = withForeignPtr x
mkSurface :: Ptr Surface -> IO Surface
mkSurface surfacePtr = do
  surfaceForeignPtr <- newForeignPtr_ surfacePtr
  return (Surface surfaceForeignPtr)
manageSurface :: Surface -> IO ()
manageSurface (Surface surfaceForeignPtr) = do
  addForeignPtrFinalizer surfaceDestroy surfaceForeignPtr
foreign import ccall unsafe "&cairo_surface_destroy"
  surfaceDestroy :: FinalizerPtr Surface
newtype Pattern = Pattern (Ptr (Pattern))
unPattern (Pattern x) = x
data Status = StatusSuccess
            | StatusNoMemory
            | StatusInvalidRestore
            | StatusInvalidPopGroup
            | StatusNoCurrentPoint
            | StatusInvalidMatrix
            | StatusInvalidStatus
            | StatusNullPointer
            | StatusInvalidString
            | StatusInvalidPathData
            | StatusReadError
            | StatusWriteError
            | StatusSurfaceFinished
            | StatusSurfaceTypeMismatch
            | StatusPatternTypeMismatch
            | StatusInvalidContent
            | StatusInvalidFormat
            | StatusInvalidVisual
            | StatusFileNotFound
            | StatusInvalidDash
            | StatusInvalidDscComment
            | StatusInvalidIndex
            | StatusClipNotRepresentable
            | StatusTempFileError
            | StatusInvalidStride
            | StatusFontTypeMismatch
            | StatusUserFontImmutable
            | StatusUserFontError
            | StatusNegativeCount
            | StatusInvalidClusters
            | StatusInvalidSlant
            | StatusInvalidWeight
            | StatusInvalidSize
            | StatusUserFontNotImplemented
            | StatusDeviceTypeMismatch
            | StatusDeviceError
            | StatusInvalidMeshConstruction
            | StatusDeviceFinished
            | StatusJbig2GlobalMissing
            | StatusLastStatus
            deriving (Eq,Show)
instance Enum Status where
  fromEnum StatusSuccess = 0
  fromEnum StatusNoMemory = 1
  fromEnum StatusInvalidRestore = 2
  fromEnum StatusInvalidPopGroup = 3
  fromEnum StatusNoCurrentPoint = 4
  fromEnum StatusInvalidMatrix = 5
  fromEnum StatusInvalidStatus = 6
  fromEnum StatusNullPointer = 7
  fromEnum StatusInvalidString = 8
  fromEnum StatusInvalidPathData = 9
  fromEnum StatusReadError = 10
  fromEnum StatusWriteError = 11
  fromEnum StatusSurfaceFinished = 12
  fromEnum StatusSurfaceTypeMismatch = 13
  fromEnum StatusPatternTypeMismatch = 14
  fromEnum StatusInvalidContent = 15
  fromEnum StatusInvalidFormat = 16
  fromEnum StatusInvalidVisual = 17
  fromEnum StatusFileNotFound = 18
  fromEnum StatusInvalidDash = 19
  fromEnum StatusInvalidDscComment = 20
  fromEnum StatusInvalidIndex = 21
  fromEnum StatusClipNotRepresentable = 22
  fromEnum StatusTempFileError = 23
  fromEnum StatusInvalidStride = 24
  fromEnum StatusFontTypeMismatch = 25
  fromEnum StatusUserFontImmutable = 26
  fromEnum StatusUserFontError = 27
  fromEnum StatusNegativeCount = 28
  fromEnum StatusInvalidClusters = 29
  fromEnum StatusInvalidSlant = 30
  fromEnum StatusInvalidWeight = 31
  fromEnum StatusInvalidSize = 32
  fromEnum StatusUserFontNotImplemented = 33
  fromEnum StatusDeviceTypeMismatch = 34
  fromEnum StatusDeviceError = 35
  fromEnum StatusInvalidMeshConstruction = 36
  fromEnum StatusDeviceFinished = 37
  fromEnum StatusJbig2GlobalMissing = 38
  fromEnum StatusLastStatus = 39
  toEnum 0 = StatusSuccess
  toEnum 1 = StatusNoMemory
  toEnum 2 = StatusInvalidRestore
  toEnum 3 = StatusInvalidPopGroup
  toEnum 4 = StatusNoCurrentPoint
  toEnum 5 = StatusInvalidMatrix
  toEnum 6 = StatusInvalidStatus
  toEnum 7 = StatusNullPointer
  toEnum 8 = StatusInvalidString
  toEnum 9 = StatusInvalidPathData
  toEnum 10 = StatusReadError
  toEnum 11 = StatusWriteError
  toEnum 12 = StatusSurfaceFinished
  toEnum 13 = StatusSurfaceTypeMismatch
  toEnum 14 = StatusPatternTypeMismatch
  toEnum 15 = StatusInvalidContent
  toEnum 16 = StatusInvalidFormat
  toEnum 17 = StatusInvalidVisual
  toEnum 18 = StatusFileNotFound
  toEnum 19 = StatusInvalidDash
  toEnum 20 = StatusInvalidDscComment
  toEnum 21 = StatusInvalidIndex
  toEnum 22 = StatusClipNotRepresentable
  toEnum 23 = StatusTempFileError
  toEnum 24 = StatusInvalidStride
  toEnum 25 = StatusFontTypeMismatch
  toEnum 26 = StatusUserFontImmutable
  toEnum 27 = StatusUserFontError
  toEnum 28 = StatusNegativeCount
  toEnum 29 = StatusInvalidClusters
  toEnum 30 = StatusInvalidSlant
  toEnum 31 = StatusInvalidWeight
  toEnum 32 = StatusInvalidSize
  toEnum 33 = StatusUserFontNotImplemented
  toEnum 34 = StatusDeviceTypeMismatch
  toEnum 35 = StatusDeviceError
  toEnum 36 = StatusInvalidMeshConstruction
  toEnum 37 = StatusDeviceFinished
  toEnum 38 = StatusJbig2GlobalMissing
  toEnum 39 = StatusLastStatus
  toEnum unmatched = error ("Status.toEnum: Cannot match " ++ show unmatched)
  succ StatusSuccess = StatusNoMemory
  succ StatusNoMemory = StatusInvalidRestore
  succ StatusInvalidRestore = StatusInvalidPopGroup
  succ StatusInvalidPopGroup = StatusNoCurrentPoint
  succ StatusNoCurrentPoint = StatusInvalidMatrix
  succ StatusInvalidMatrix = StatusInvalidStatus
  succ StatusInvalidStatus = StatusNullPointer
  succ StatusNullPointer = StatusInvalidString
  succ StatusInvalidString = StatusInvalidPathData
  succ StatusInvalidPathData = StatusReadError
  succ StatusReadError = StatusWriteError
  succ StatusWriteError = StatusSurfaceFinished
  succ StatusSurfaceFinished = StatusSurfaceTypeMismatch
  succ StatusSurfaceTypeMismatch = StatusPatternTypeMismatch
  succ StatusPatternTypeMismatch = StatusInvalidContent
  succ StatusInvalidContent = StatusInvalidFormat
  succ StatusInvalidFormat = StatusInvalidVisual
  succ StatusInvalidVisual = StatusFileNotFound
  succ StatusFileNotFound = StatusInvalidDash
  succ StatusInvalidDash = StatusInvalidDscComment
  succ StatusInvalidDscComment = StatusInvalidIndex
  succ StatusInvalidIndex = StatusClipNotRepresentable
  succ StatusClipNotRepresentable = StatusTempFileError
  succ StatusTempFileError = StatusInvalidStride
  succ StatusInvalidStride = StatusFontTypeMismatch
  succ StatusFontTypeMismatch = StatusUserFontImmutable
  succ StatusUserFontImmutable = StatusUserFontError
  succ StatusUserFontError = StatusNegativeCount
  succ StatusNegativeCount = StatusInvalidClusters
  succ StatusInvalidClusters = StatusInvalidSlant
  succ StatusInvalidSlant = StatusInvalidWeight
  succ StatusInvalidWeight = StatusInvalidSize
  succ StatusInvalidSize = StatusUserFontNotImplemented
  succ StatusUserFontNotImplemented = StatusDeviceTypeMismatch
  succ StatusDeviceTypeMismatch = StatusDeviceError
  succ StatusDeviceError = StatusInvalidMeshConstruction
  succ StatusInvalidMeshConstruction = StatusDeviceFinished
  succ StatusDeviceFinished = StatusJbig2GlobalMissing
  succ StatusJbig2GlobalMissing = StatusLastStatus
  succ _ = undefined
  pred StatusNoMemory = StatusSuccess
  pred StatusInvalidRestore = StatusNoMemory
  pred StatusInvalidPopGroup = StatusInvalidRestore
  pred StatusNoCurrentPoint = StatusInvalidPopGroup
  pred StatusInvalidMatrix = StatusNoCurrentPoint
  pred StatusInvalidStatus = StatusInvalidMatrix
  pred StatusNullPointer = StatusInvalidStatus
  pred StatusInvalidString = StatusNullPointer
  pred StatusInvalidPathData = StatusInvalidString
  pred StatusReadError = StatusInvalidPathData
  pred StatusWriteError = StatusReadError
  pred StatusSurfaceFinished = StatusWriteError
  pred StatusSurfaceTypeMismatch = StatusSurfaceFinished
  pred StatusPatternTypeMismatch = StatusSurfaceTypeMismatch
  pred StatusInvalidContent = StatusPatternTypeMismatch
  pred StatusInvalidFormat = StatusInvalidContent
  pred StatusInvalidVisual = StatusInvalidFormat
  pred StatusFileNotFound = StatusInvalidVisual
  pred StatusInvalidDash = StatusFileNotFound
  pred StatusInvalidDscComment = StatusInvalidDash
  pred StatusInvalidIndex = StatusInvalidDscComment
  pred StatusClipNotRepresentable = StatusInvalidIndex
  pred StatusTempFileError = StatusClipNotRepresentable
  pred StatusInvalidStride = StatusTempFileError
  pred StatusFontTypeMismatch = StatusInvalidStride
  pred StatusUserFontImmutable = StatusFontTypeMismatch
  pred StatusUserFontError = StatusUserFontImmutable
  pred StatusNegativeCount = StatusUserFontError
  pred StatusInvalidClusters = StatusNegativeCount
  pred StatusInvalidSlant = StatusInvalidClusters
  pred StatusInvalidWeight = StatusInvalidSlant
  pred StatusInvalidSize = StatusInvalidWeight
  pred StatusUserFontNotImplemented = StatusInvalidSize
  pred StatusDeviceTypeMismatch = StatusUserFontNotImplemented
  pred StatusDeviceError = StatusDeviceTypeMismatch
  pred StatusInvalidMeshConstruction = StatusDeviceError
  pred StatusDeviceFinished = StatusInvalidMeshConstruction
  pred StatusJbig2GlobalMissing = StatusDeviceFinished
  pred StatusLastStatus = StatusJbig2GlobalMissing
  pred _ = undefined
  enumFromTo x y | fromEnum x == fromEnum y = [ y ]
                 | otherwise = x : enumFromTo (succ x) y
  enumFrom x = enumFromTo x StatusLastStatus
  enumFromThen _ _ =     error "Enum Status: enumFromThen not implemented"
  enumFromThenTo _ _ _ =     error "Enum Status: enumFromThenTo not implemented"
data Operator = OperatorClear
              | OperatorSource
              | OperatorOver
              | OperatorIn
              | OperatorOut
              | OperatorAtop
              | OperatorDest
              | OperatorDestOver
              | OperatorDestIn
              | OperatorDestOut
              | OperatorDestAtop
              | OperatorXor
              | OperatorAdd
              | OperatorSaturate
              | OperatorMultiply
              | OperatorScreen
              | OperatorOverlay
              | OperatorDarken
              | OperatorLighten
              | OperatorColorDodge
              | OperatorColorBurn
              | OperatorHardLight
              | OperatorSoftLight
              | OperatorDifference
              | OperatorExclusion
              | OperatorHslHue
              | OperatorHslSaturation
              | OperatorHslColor
              | OperatorHslLuminosity
              deriving (Enum,Eq,Show)
data Antialias = AntialiasDefault
               | AntialiasNone
               | AntialiasGray
               | AntialiasSubpixel
               | AntialiasFast
               | AntialiasGood
               | AntialiasBest
               deriving (Enum,Eq,Show)
data FillRule = FillRuleWinding
              | FillRuleEvenOdd
              deriving (Enum,Eq,Show)
data LineCap = LineCapButt
             | LineCapRound
             | LineCapSquare
             deriving (Enum,Eq,Show)
data LineJoin = LineJoinMiter
              | LineJoinRound
              | LineJoinBevel
              deriving (Enum,Eq,Show)
newtype ScaledFont = ScaledFont (Ptr (ScaledFont))
unScaledFont (ScaledFont x) = x
newtype FontFace = FontFace (Ptr (FontFace))
unFontFace (FontFace x) = x
newtype Glyph = Glyph (Ptr (Glyph))
unGlyph (Glyph x) = x
type TextExtentsPtr = Ptr (TextExtents)
data TextExtents = TextExtents {
    textExtentsXbearing :: Double
  , textExtentsYbearing :: Double
  , textExtentsWidth    :: Double
  , textExtentsHeight   :: Double
  , textExtentsXadvance :: Double
  , textExtentsYadvance :: Double
  }
instance Storable TextExtents where
  sizeOf _ = 48
  alignment _ = alignment (undefined :: CDouble)
  peek p = do
    x_bearing <- (\ptr -> do {peekByteOff ptr 0 ::IO CDouble}) p
    y_bearing <- (\ptr -> do {peekByteOff ptr 8 ::IO CDouble}) p
    width     <- (\ptr -> do {peekByteOff ptr 16 ::IO CDouble})     p
    height    <- (\ptr -> do {peekByteOff ptr 24 ::IO CDouble})    p
    x_advance <- (\ptr -> do {peekByteOff ptr 32 ::IO CDouble}) p
    y_advance <- (\ptr -> do {peekByteOff ptr 40 ::IO CDouble}) p
    return $ TextExtents (cFloatConv x_bearing) (cFloatConv y_bearing)
                         (cFloatConv width)     (cFloatConv height)
                         (cFloatConv x_advance) (cFloatConv y_advance)
  poke p (TextExtents x_bearing y_bearing width height x_advance y_advance) = do
    (\ptr val -> do {pokeByteOff ptr 0 (val::CDouble)}) p (cFloatConv x_bearing)
    (\ptr val -> do {pokeByteOff ptr 8 (val::CDouble)}) p (cFloatConv y_bearing)
    (\ptr val -> do {pokeByteOff ptr 16 (val::CDouble)})     p (cFloatConv width)
    (\ptr val -> do {pokeByteOff ptr 24 (val::CDouble)})    p (cFloatConv height)
    (\ptr val -> do {pokeByteOff ptr 32 (val::CDouble)}) p (cFloatConv x_advance)
    (\ptr val -> do {pokeByteOff ptr 40 (val::CDouble)}) p (cFloatConv y_advance)
    return ()
type FontExtentsPtr = Ptr (FontExtents)
data FontExtents = FontExtents {
    fontExtentsAscent      :: Double
  , fontExtentsDescent     :: Double
  , fontExtentsHeight      :: Double
  , fontExtentsMaxXadvance :: Double
  , fontExtentsMaxYadvance :: Double
  }
instance Storable FontExtents where
  sizeOf _ = 40
  alignment _ = alignment (undefined :: CDouble)
  peek p = do
    ascent        <- (\ptr -> do {peekByteOff ptr 0 ::IO CDouble})        p
    descent       <- (\ptr -> do {peekByteOff ptr 8 ::IO CDouble})       p
    height        <- (\ptr -> do {peekByteOff ptr 16 ::IO CDouble})        p
    max_x_advance <- (\ptr -> do {peekByteOff ptr 24 ::IO CDouble}) p
    max_y_advance <- (\ptr -> do {peekByteOff ptr 32 ::IO CDouble}) p
    return $ FontExtents (cFloatConv ascent) (cFloatConv descent) (cFloatConv height)
                         (cFloatConv max_x_advance) (cFloatConv max_y_advance)
  poke p (FontExtents ascent descent height max_x_advance max_y_advance) = do
    (\ptr val -> do {pokeByteOff ptr 0 (val::CDouble)})        p (cFloatConv ascent)
    (\ptr val -> do {pokeByteOff ptr 8 (val::CDouble)})       p (cFloatConv descent)
    (\ptr val -> do {pokeByteOff ptr 16 (val::CDouble)})        p (cFloatConv height)
    (\ptr val -> do {pokeByteOff ptr 24 (val::CDouble)}) p (cFloatConv max_x_advance)
    (\ptr val -> do {pokeByteOff ptr 32 (val::CDouble)}) p (cFloatConv max_y_advance)
    return ()
data FontSlant = FontSlantNormal
               | FontSlantItalic
               | FontSlantOblique
               deriving (Enum,Eq,Show)
data FontWeight = FontWeightNormal
                | FontWeightBold
                deriving (Enum,Eq,Show)
data SubpixelOrder = SubpixelOrderDefault
                   | SubpixelOrderRgb
                   | SubpixelOrderBgr
                   | SubpixelOrderVrgb
                   | SubpixelOrderVbgr
                   deriving (Enum,Eq,Show)
data HintStyle = HintStyleDefault
               | HintStyleNone
               | HintStyleSlight
               | HintStyleMedium
               | HintStyleFull
               deriving (Enum)
data HintMetrics = HintMetricsDefault
                 | HintMetricsOff
                 | HintMetricsOn
                 deriving (Enum,Eq,Show)
newtype FontOptions = FontOptions (ForeignPtr (FontOptions))
withFontOptions (FontOptions fptr) = withForeignPtr fptr
mkFontOptions :: Ptr FontOptions -> IO FontOptions
mkFontOptions fontOptionsPtr = do
  fontOptionsForeignPtr <- newForeignPtr fontOptionsDestroy fontOptionsPtr
  return (FontOptions fontOptionsForeignPtr)
foreign import ccall unsafe "&cairo_font_options_destroy"
  fontOptionsDestroy :: FinalizerPtr FontOptions
newtype Path = Path (Ptr (Path))
unPath (Path x) = x
type RectangleIntPtr = Ptr (RectangleInt)
data RectangleInt = RectangleInt {
    x      :: Int
  , y      :: Int
  , width  :: Int
  , height :: Int
  }
instance Storable RectangleInt where
  sizeOf _ = 16
  alignment _ = alignment (undefined :: CInt)
  peek p = do
    x      <- (\ptr -> do {peekByteOff ptr 0 ::IO CInt})      p
    y      <- (\ptr -> do {peekByteOff ptr 4 ::IO CInt})      p
    width  <- (\ptr -> do {peekByteOff ptr 8 ::IO CInt})  p
    height <- (\ptr -> do {peekByteOff ptr 12 ::IO CInt}) p
    return $ RectangleInt (fromIntegral x) (fromIntegral y) (fromIntegral width) (fromIntegral height)
  poke p (RectangleInt {..}) = do
    (\ptr val -> do {pokeByteOff ptr 0 (val::CInt)})      p (fromIntegral x)
    (\ptr val -> do {pokeByteOff ptr 4 (val::CInt)})      p (fromIntegral y)
    (\ptr val -> do {pokeByteOff ptr 8 (val::CInt)})  p (fromIntegral width)
    (\ptr val -> do {pokeByteOff ptr 12 (val::CInt)}) p (fromIntegral height)
    return ()
data RegionOverlap = RegionOverlapIn
                   | RegionOverlapOut
                   | RegionOverlapPart
                   deriving (Enum,Eq,Show)
newtype Region = Region (ForeignPtr (Region))
withRegion (Region fptr) = withForeignPtr fptr
mkRegion :: Ptr Region -> IO Region
mkRegion regionPtr = do
  regionForeignPtr <- newForeignPtr regionDestroy regionPtr
  return (Region regionForeignPtr)
foreign import ccall unsafe "&cairo_region_destroy"
  regionDestroy :: FinalizerPtr Region
data Content = ContentColor
             | ContentAlpha
             | ContentColorAlpha
             deriving (Eq,Show)
instance Enum Content where
  fromEnum ContentColor = 4096
  fromEnum ContentAlpha = 8192
  fromEnum ContentColorAlpha = 12288
  toEnum 4096 = ContentColor
  toEnum 8192 = ContentAlpha
  toEnum 12288 = ContentColorAlpha
  toEnum unmatched = error ("Content.toEnum: Cannot match " ++ show unmatched)
  succ ContentColor = ContentAlpha
  succ ContentAlpha = ContentColorAlpha
  succ _ = undefined
  pred ContentAlpha = ContentColor
  pred ContentColorAlpha = ContentAlpha
  pred _ = undefined
  enumFromTo x y | fromEnum x == fromEnum y = [ y ]
                 | otherwise = x : enumFromTo (succ x) y
  enumFrom x = enumFromTo x ContentColorAlpha
  enumFromThen _ _ =     error "Enum Content: enumFromThen not implemented"
  enumFromThenTo _ _ _ =     error "Enum Content: enumFromThenTo not implemented"
data Format = FormatARGB32
            | FormatRGB24
            | FormatA8
            | FormatA1
            deriving (Enum,Show,Eq)
data Extend = ExtendNone
            | ExtendRepeat
            | ExtendReflect
            | ExtendPad
            deriving (Enum,Eq,Show)
data Filter = FilterFast
            | FilterGood
            | FilterBest
            | FilterNearest
            | FilterBilinear
            | FilterGaussian
            deriving (Enum,Eq,Show)
cIntConv :: (Integral a, Integral b) => a -> b
cIntConv  = fromIntegral
cFloatConv :: (RealFloat a, RealFloat b) => a -> b
cFloatConv  = realToFrac
cFromBool :: Num a => Bool -> a
cFromBool  = fromBool
cToBool :: (Eq a, Num a) => a -> Bool
cToBool  = toBool
cToEnum :: (Integral i, Enum e) => i -> e
cToEnum  = toEnum . cIntConv
cFromEnum :: (Enum e, Integral i) => e -> i
cFromEnum  = cIntConv . fromEnum
peekFloatConv :: (Storable a, RealFloat a, RealFloat b) =>  Ptr a -> IO b
peekFloatConv  = liftM cFloatConv . peek
withFloatConv :: (Storable b, RealFloat a, RealFloat b) => a -> (Ptr b -> IO c) -> IO c
withFloatConv  = with . cFloatConv
withArrayFloatConv :: (Storable b, RealFloat a, RealFloat b) => [a] -> (Ptr b -> IO b1) -> IO b1
withArrayFloatConv = withArray . map (cFloatConv)