{-# LANGUAGE ViewPatterns #-}
--------------------------------------------------------------------------------
-- |
-- Module      : ArrayFire.Graphics
-- Copyright   : David Johnson (c) 2019-2020
-- License     : BSD 3
-- Maintainer  : David Johnson <djohnson.m@gmail.com>
-- Stability   : Experimental
-- Portability : GHC
--
--------------------------------------------------------------------------------
module ArrayFire.Graphics where

import Control.Exception
import Foreign.Marshal
import Foreign.Storable
import Foreign.ForeignPtr
import Foreign.C.String

import ArrayFire.Internal.Graphics
import ArrayFire.Exception
import ArrayFire.FFI
import ArrayFire.Internal.Types

-- | Create window
--
-- [ArrayFire Docs](http://arrayfire.org/docs/group__gfx__func__window.htm)
--
-- >>> window <- createWindow 800 600 "New Chart"
--
createWindow
  :: Int
  -- ^ width
  -> Int
  -- ^ height
  -> String
  -- ^ title
  -> IO Window
  -- ^ 'Window' handle
createWindow (fromIntegral -> x) (fromIntegral -> y) str =
  withCString str $ \cstr ->
    createWindow' (\p -> af_create_window p x y cstr)

-- | Sets 'Window' position
--
-- [ArrayFire Docs](http://arrayfire.org/docs/group__gfx__func__window.htm)
--
-- >>> window <- createWindow 800 600 "New Chart"
-- >>> setPosition window 800 600
--
setPosition
  :: Window
  -- ^ 'Window' handle
  -> Int
  -- ^ Horizontal start coordinate
  -> Int
  -- ^ Vertical start coordinate
  -> IO ()
setPosition w (fromIntegral -> x) (fromIntegral -> y) =
  w `opw` (\p -> af_set_position p x y)

-- | Sets 'Window' title
--
-- [ArrayFire Docs](http://arrayfire.org/docs/group__gfx__func__window.htm)
--
-- >>> window <- createWindow 800 600 "New Chart"
-- >>> setTitle window "window title"
--
setTitle
  :: Window
  -- ^ 'Window' handle
  -> String
  -- ^ title
  -> IO ()
setTitle w str = withCString str $ \cstr ->
  w `opw` (\p -> af_set_title p cstr)

-- | Sets 'Window' size
--
-- [ArrayFire Docs](http://arrayfire.org/docs/group__gfx__func__window.htm)
--
-- >>> window <- createWindow 800 600 "New Chart"
-- >>> setSize window 800 600
--
setSize
  :: Window
  -- ^ 'Window' handle
  -> Int
  -- ^ target width of the window
  -> Int
  -- ^ target height of the window
  -> IO ()
setSize w (fromIntegral -> x) (fromIntegral -> y) =
  w `opw` (\p -> af_set_size p x y)

-- | Draw an image onto a Window
--
-- [ArrayFire Docs](http://arrayfire.org/docs/group__gfx__func__draw.htm)
--
-- >>> drawImage window ('constant' \@'Int' 1) ('Cell' 10 10 "test" 'ColorMapSpectrum')
-- 
drawImage
  :: Window
  -- ^ 'Window' handle
  -> Array a
  -- ^ Image
  -> Cell
  -- ^ is structure 'Cell' that has the properties that are used for the current rendering.
  -> IO ()
drawImage (Window wfptr) (Array fptr) cell =
  mask_ $ withForeignPtr fptr $ \aptr ->
    withForeignPtr wfptr $ \wptr ->
      alloca $ \cellPtr -> do
        poke cellPtr =<< cellToAFCell cell
        throwAFError =<< af_draw_image wptr aptr cellPtr
        free cellPtr

-- | Draw a plot onto a 'Window'
--
-- [ArrayFire Docs](http://arrayfire.org/docs/group__gfx__func__draw.htm)
--
-- >>> drawPlot window ('constant' \@'Int' 1) ('constant' \@'Int' 1) ('Cell' 10 10 "test" 'ColorMapSpectrum')
--
-- *Note* X and Y should be vectors.
--
drawPlot
  :: Window
  -- ^ is the window handle
  -> Array a
  -- ^ is an 'Array' with the x-axis data points
  -> Array a
  -- ^ is an 'Array' with the y-axis data points
  -> Cell
  -- ^ is structure 'Cell' that has the properties that are used for the current rendering.
  -> IO ()
drawPlot (Window w) (Array fptr1) (Array fptr2) cell =
  mask_ $ withForeignPtr fptr1 $ \ptr1 ->
    withForeignPtr fptr2 $ \ptr2 ->
      withForeignPtr w $ \wptr ->
      alloca $ \cellPtr -> do
        poke cellPtr =<< cellToAFCell cell
        throwAFError =<< af_draw_plot wptr ptr1 ptr2 cellPtr
        free cellPtr

-- | Draw a plot onto a 'Window'
--
-- [ArrayFire Docs](http://arrayfire.org/docs/group__gfx__func__draw.htm)
--
-- *Note* P should be a 3n x 1 vector or one of a 3xn or nx3 matrices.
--
drawPlot3
  :: Window
  -- ^ the window handle
  -> Array a
  -- ^ is an af_array or matrix with the xyz-values of the points
  -> Cell
  -- ^ is structure af_cell that has the properties that are used for the current rendering.
  -> IO ()
drawPlot3 (Window w) (Array fptr) cell =
  mask_ $ withForeignPtr fptr $ \aptr ->
    withForeignPtr w $ \wptr ->
    alloca $ \cellPtr -> do
      poke cellPtr =<< cellToAFCell cell
      throwAFError =<< af_draw_plot3 wptr aptr cellPtr
      free cellPtr

-- | Draw a plot onto a 'Window'
--
-- [ArrayFire Docs](http://arrayfire.org/docs/group__gfx__func__draw.htm)
--
-- *Note* in must be 2d and of the form [n, order], where order is either 2 or 3. If order is 2, then chart is 2D and if order is 3, then chart is 3D.
--
drawPlotNd
  :: Window
  -- ^ is the window handle
  -> Array a
  -- ^ is an 'Array' or matrix with the xyz-values of the points
  -> Cell
  -- ^ is structure 'Cell' that has the properties that are used for the current rendering.
  -> IO ()
drawPlotNd (Window w) (Array fptr) cell =
  mask_ $ withForeignPtr fptr $ \aptr ->
    withForeignPtr w $ \wptr ->
    alloca $ \cellPtr -> do
      poke cellPtr =<< cellToAFCell cell
      throwAFError =<< af_draw_plot_nd wptr aptr cellPtr
      free cellPtr

-- | Draw a plot onto a 'Window'
--
-- [ArrayFire Docs](http://arrayfire.org/docs/group__gfx__func__draw.htm)
--
-- *Note* X and Y should be vectors.
--
drawPlot2d
  :: Window
  -- ^ is the window handle
  -> Array a
  -- ^ is an 'Array' with the x-axis data points
  -> Array a
  -- ^ is an 'Array' with the y-axis data points
  -> Cell
  -- ^ is structure 'Cell' that has the properties that are used for the current rendering.
  -> IO ()
drawPlot2d (Window w) (Array fptr1) (Array fptr2) cell =
  mask_ $ withForeignPtr fptr1 $ \ptr1 ->
    withForeignPtr fptr2 $ \ptr2 ->
     withForeignPtr w $ \wptr ->
      alloca $ \cellPtr -> do
        poke cellPtr =<< cellToAFCell cell
        throwAFError =<< af_draw_plot_2d wptr ptr1 ptr2 cellPtr
        free cellPtr

-- | Draw a 3D plot onto a 'Window'
--
-- [ArrayFire Docs](http://arrayfire.org/docs/group__gfx__func__draw.htm)
--
-- *Note* X, Y and Z should be vectors.
--
drawPlot3d
  :: Window
  -- ^ is the window handle
  -> Array a
  -- ^ is an 'Array' with the x-axis data points
  -> Array a
  -- ^ is an 'Array' with the y-axis data points
    -> Array a
  -- ^ is an 'Array' with the z-axis data points
  -> Cell
  -- ^ is structure 'Cell' that has the properties that are used for the current rendering.
  -> IO ()
drawPlot3d (Window w) (Array fptr1) (Array fptr2) (Array fptr3) cell =
  mask_ $ withForeignPtr fptr1 $ \ptr1 ->
    withForeignPtr fptr2 $ \ptr2 ->
      withForeignPtr fptr3 $ \ptr3 ->
        withForeignPtr w $ \wptr ->
          alloca $ \cellPtr -> do
            poke cellPtr =<< cellToAFCell cell
            throwAFError =<< af_draw_plot_3d wptr ptr1 ptr2 ptr3 cellPtr
            free cellPtr

-- | Draw a scatter plot onto a 'Window'
--
-- [ArrayFire Docs](http://arrayfire.org/docs/group__gfx__func__draw.htm)
--
-- *Note* X and Y should be vectors.
--
drawScatter
  :: Window
  -- ^ is the window handle
  -> Array a
  -- ^ is an 'Array' with the x-axis data points
  -> Array a
  -- ^ is an 'Array' with the y-axis data points
  -> MarkerType
  -- ^ enum specifying which marker to use in the scatter plot
  -> Cell
  -- ^ is structure 'Cell' that has the properties that are used for the current rendering.
  -> IO ()
drawScatter (Window w) (Array fptr1) (Array fptr2) (fromMarkerType -> m) cell =
  mask_ $ withForeignPtr fptr1 $ \ptr1 ->
    withForeignPtr fptr2 $ \ptr2 ->
     withForeignPtr w $ \wptr ->
      alloca $ \cellPtr -> do
        poke cellPtr =<< cellToAFCell cell
        throwAFError =<< af_draw_scatter wptr ptr1 ptr2 m cellPtr
        free cellPtr

-- | Draw a scatter plot onto a 'Window'
--
-- [ArrayFire Docs](http://arrayfire.org/docs/group__gfx__func__draw.htm#ga764410fbdf0cd60c7044c77e36fb2577)
--
-- *Note* X and Y should be vectors.
--
drawScatter3
  :: Window
  -- ^ is the window handle
  -> Array a
  -- ^ is an af_array or matrix with the xyz-values of the points
  -> MarkerType
  -- ^ is an af_marker_type enum specifying which marker to use in the scatter plot
  -> Cell
  -- ^ is structure af_cell that has the properties that are used for the current rendering.
  -> IO ()
drawScatter3 (Window w) (Array fptr1) (fromMarkerType -> m) cell =
  mask_ $ withForeignPtr fptr1 $ \ptr1 ->
   withForeignPtr w $ \wptr ->
    alloca $ \cellPtr -> do
      poke cellPtr =<< cellToAFCell cell
      throwAFError =<< af_draw_scatter3 wptr ptr1 m cellPtr
      free cellPtr

-- | Draw a scatter plot onto a 'Window'
--
-- [ArrayFire Docs](http://arrayfire.org/docs/group__gfx__func__draw.htm#ga9991b93681e0c18693a5464458781d22)
--
-- *Note* in must be 2d and of the form [n, order], where order is either 2 or 3. If order is 2, then chart is 2D and if order is 3, then chart is 3D.
--
drawScatterNd
  :: Window
  -- ^ is the window handle
  -> Array a
  -- ^ is an 'Array' or matrix with the xyz-values of the points
  -> MarkerType
  -- ^ is an af_marker_type enum specifying which marker to use in the scatter plot
  -> Cell
  -- ^ is structure af_cell that has the properties that are used for the current rendering.
  -> IO ()
drawScatterNd (Window w) (Array fptr1) (fromMarkerType -> m) cell =
  mask_ $ withForeignPtr fptr1 $ \ptr1 ->
   withForeignPtr w $ \wptr ->
    alloca $ \cellPtr -> do
      poke cellPtr =<< cellToAFCell cell
      throwAFError =<< af_draw_scatter_nd wptr ptr1 m cellPtr
      free cellPtr

-- | Draw a scatter plot onto a 'Window'
--
-- [ArrayFire Docs](http://arrayfire.org/docs/group__gfx__func__draw.htm#ga79417722c69883e7a91282b138288010)
--
-- *Note* in must be 2d and of the form [n, order], where order is either 2 or 3. If order is 2, then chart is 2D and if order is 3, then chart is 3D.
--
drawScatter2d
  :: Window
  -- ^ is the window handle
  -> Array a
  -- ^ is an af_array with the x-axis data points
  -> Array a
  -- ^ is an af_array with the y-axis data points
  -> MarkerType
  -- ^ is an af_marker_type enum specifying which marker to use in the scatter plot
  -> Cell
  -- ^ is structure af_cell that has the properties that are used for the current rendering.
  -> IO ()
drawScatter2d (Window w) (Array fptr1) (Array fptr2) (fromMarkerType -> m) cell =
  mask_ $ withForeignPtr fptr1 $ \ptr1 ->
   withForeignPtr w $ \wptr ->
   withForeignPtr fptr2 $ \ptr2 ->
    alloca $ \cellPtr -> do
      poke cellPtr =<< cellToAFCell cell
      throwAFError =<< af_draw_scatter_2d wptr ptr1 ptr2 m cellPtr
      free cellPtr

-- | Draw a scatter plot onto a 'Window'
--
-- [ArrayFire Docs](http://arrayfire.org/docs/group__gfx__func__draw.htm#ga2b3d0dd690ebcba4c4dbb09cdcaed304)
--
-- *Note* X, Y and Z should be vectors.
--
drawScatter3d
  :: Window
  -- ^ is the window handle
  -> Array a
  -- ^ is an af_array with the x-axis data points
  -> Array a
  -- ^ is an af_array with the y-axis data points
  -> Array a
  -- ^ is an af_array with the z-axis data points  
  -> MarkerType
  -- ^ is an af_marker_type enum specifying which marker to use in the scatter plot
  -> Cell
  -- ^ is structure af_cell that has the properties that are used for the current rendering.
  -> IO ()
drawScatter3d (Window w) (Array fptr1) (Array fptr2) (Array fptr3) (fromMarkerType -> m) cell =
  mask_ $ withForeignPtr fptr1 $ \ptr1 ->
   withForeignPtr w $ \wptr ->
   withForeignPtr fptr2 $ \ptr2 ->
    withForeignPtr fptr3 $ \ptr3 ->
      alloca $ \cellPtr -> do
        poke cellPtr =<< cellToAFCell cell
        throwAFError =<< af_draw_scatter_3d wptr ptr1 ptr2 ptr3 m cellPtr
        free cellPtr

-- | Draw a Histogram onto a 'Window'
--
-- [ArrayFire Docs](http://arrayfire.org/docs/group__gfx__func__draw.htm#gaf1648ee35739c86116bfa9c22644dbd7)
--
-- *Note* X should be a vector.
--
drawHistogram
  :: Window
  -- ^ is the window handle
  -> Array a
  -- ^ is the data frequency af_array
  -> Double
  -- ^ is the value of the minimum data point of the array whose histogram(X) is going to be rendered.
  -> Double
  -- ^ is the value of the maximum data point of the array whose histogram(X) is going to be rendered.
  -> Cell
  -- ^ is structure 'Cell' that has the properties that are used for the current rendering.
  -> IO ()
drawHistogram (Window w) (Array fptr1) minval maxval cell =
  mask_ $ withForeignPtr fptr1 $ \ptr1 ->
   withForeignPtr w $ \wptr ->
    alloca $ \cellPtr -> do
      poke cellPtr =<< cellToAFCell cell
      throwAFError =<< af_draw_hist wptr ptr1 minval maxval cellPtr

-- | Draw a Surface onto a 'Window'
--
-- [ArrayFire Docs](http://arrayfire.org/docs/group__gfx__func__draw.htm#gaaee14e457272b2cd1bd4ed1228370229)
--
-- *Note* X and Y should be vectors. S should be a 2D array
--
drawSurface
  :: Window
  -- ^ is the window handle
  -> Array a
  -- ^ is an af_array with the x-axis data points
  -> Array a
  -- ^ is an af_array with the y-axis data points
  -> Array a
  -- ^ is an af_array with the z-axis data points
  -> Cell
  -- ^ is structure af_cell that has the properties that are used for the current rendering.
  -> IO ()
drawSurface (Window w) (Array fptr1) (Array fptr2) (Array fptr3) cell =
  mask_ $ withForeignPtr fptr1 $ \ptr1 ->
   withForeignPtr w $ \wptr ->
   withForeignPtr fptr2 $ \ptr2 ->
    withForeignPtr fptr3 $ \ptr3 ->
      alloca $ \cellPtr -> do
        poke cellPtr =<< cellToAFCell cell
        throwAFError =<< af_draw_surface wptr ptr1 ptr2 ptr3 cellPtr
        free cellPtr

-- | Draw a Vector Field onto a 'Window'
--
-- [ArrayFire Docs](http://arrayfire.org/docs/group__gfx__func__draw.htm#ga2d31a148578d749be4224e7119b386bc)
--
-- *Note* all the 'Array' inputs should be vectors and the same size
--
drawVectorFieldND
  :: Window
  -- ^ is the window handle
  -> Array a
  -- ^ is an 'Array' with the points
  -> Array a
  -- ^ is an 'Array' with the directions
  -> Cell
  -- ^ is structure 'Cell' that has the properties that are used for the current rendering.
  -> IO ()
drawVectorFieldND (Window w) (Array fptr1) (Array fptr2) cell =
  mask_ $ withForeignPtr fptr1 $ \ptr1 ->
   withForeignPtr fptr2 $ \ptr2 ->
     withForeignPtr w $ \wptr ->
      alloca $ \cellPtr -> do
        poke cellPtr =<< cellToAFCell cell
        throwAFError =<< af_draw_vector_field_nd wptr ptr1 ptr2 cellPtr
        free cellPtr

-- | Draw a Vector Field onto a 'Window'
--
-- [ArrayFire Docs](http://arrayfire.org/docs/group__gfx__func__draw.htm#gaf2d3be32c1b6a9034a3bb851206b4b5a)
--
-- *Note* all the 'Array' inputs should be vectors and the same size
--
drawVectorField3d
  :: Window
  -- ^ is the window handle
  -> Array a
  -- ^ is an 'Array' with the x-axis points
  -> Array a
  -- ^ is an 'Array' with the y-axis points
  -> Array a
  -- ^ is an 'Array' with the z-axis points
  -> Array a
  -- ^ is an 'Array' with the x-axis directions
  -> Array a
  -- ^ is an 'Array' with the y-axis directions
  -> Array a
  -- ^ is an 'Array' with the z-axis directions
  -> Cell
  -- ^ is structure 'Cell' that has the properties that are used for the current rendering.
  -> IO ()
drawVectorField3d (Window w) (Array fptr1) (Array fptr2) (Array fptr3)
  (Array fptr4) (Array fptr5) (Array fptr6) cell =
  mask_ $ do
   withForeignPtr w $ \wptr ->
    withForeignPtr fptr1 $ \ptr1 ->
      withForeignPtr fptr2 $ \ptr2 ->
        withForeignPtr fptr3 $ \ptr3 ->
          withForeignPtr fptr4 $ \ptr4 ->
            withForeignPtr fptr5 $ \ptr5 ->
              withForeignPtr fptr6 $ \ptr6 -> do
                alloca $ \cellPtr -> do
                  poke cellPtr =<< cellToAFCell cell
                  throwAFError =<< af_draw_vector_field_3d wptr ptr1 ptr2 ptr3 ptr4 ptr5 ptr6 cellPtr
                  free cellPtr

-- | Draw a Vector Field onto a 'Window'
--
-- [ArrayFire Docs](http://arrayfire.org/docs/group__gfx__func__draw.htm#gaa1a667e4d29ab089629acd5296f29a7b)
--
-- *Note* all the 'Array' inputs should be vectors and the same size
--
drawVectorField2d
  :: Window
  -- ^ is the window handle
  -> Array a
  -- ^ is an 'Array' with the x-axis points
  -> Array a
  -- ^ is the window handle
  -> Array a
  -- ^ is the window handle
  -> Array a
  -- ^ is the window handle
  -> Cell
  -- ^ is the window handle
  -> IO ()
drawVectorField2d (Window w) (Array fptr1) (Array fptr2) (Array fptr3) (Array fptr4) cell =
  mask_ $ do
   withForeignPtr w $ \wptr ->
    withForeignPtr fptr1 $ \ptr1 ->
      withForeignPtr fptr2 $ \ptr2 ->
        withForeignPtr fptr3 $ \ptr3 ->
          withForeignPtr fptr4 $ \ptr4 ->
            alloca $ \cellPtr -> do
              poke cellPtr =<< cellToAFCell cell
              throwAFError =<< af_draw_vector_field_2d wptr ptr1 ptr2 ptr3 ptr4 cellPtr
              free cellPtr

-- | Draw a grid onto a 'Window'
--
-- [ArrayFire Docs](http://arrayfire.org/docs/group__gfx__func__window.htm#ga37fc7eb00ae11c25e1a60d341663d68d)
--
-- *Note* all the 'Array' inputs should be vectors and the same size
--
grid
  :: Window
  -- ^ is the window handle
  -> Int
  -- ^ is number of rows you want to show in a window
  -> Int
  -- ^ is number of coloumns you want to show in a window
  -> IO ()
grid (Window w) (fromIntegral -> rows) (fromIntegral -> cols) =
  mask_ . withForeignPtr w $ \wptr ->
    throwAFError =<< af_grid wptr rows cols

-- | Setting axes limits for a histogram/plot/surface/vector field.
--
-- [ArrayFire Docs](http://arrayfire.org/docs/group__gfx__func__window.htm#ga62d2cad30e3aad06c24999fe5ac34598)
--
-- *Note* Set to NULL if the chart is 2D.
--
setAxesLimitsCompute
  :: Window
  -- ^ is the window handle
  -> Array a
  -- ^ the data to compute the limits for x-axis.
  -> Array a
  -- ^ the data to compute the limits for y-axis.
  -> Array a
  -- ^ the data to compute the limits for z-axis.
  -> Bool
  -- ^ is for using the exact min/max values from x, y and z. If exact is false then the most significant digit is rounded up to next power of 2 and the magnitude remains the same.
  -> Cell
  -- ^ is structure 'Cell' that has the properties that are used for the current rendering.
  -> IO ()
setAxesLimitsCompute (Window w) (Array fptr1) (Array fptr2) (Array fptr3) (fromIntegral . fromEnum -> exact) cell =
  mask_ $ do
   withForeignPtr w $ \wptr ->
    withForeignPtr fptr1 $ \ptr1 ->
      withForeignPtr fptr2 $ \ptr2 ->
        withForeignPtr fptr3 $ \ptr3 ->
          alloca $ \cellPtr -> do
            poke cellPtr =<< cellToAFCell cell
            throwAFError =<< af_set_axes_limits_compute wptr ptr1 ptr2 ptr3 exact cellPtr
            free cellPtr

-- | Setting axes limits for a 2D histogram/plot/surface/vector field.
--
-- [ArrayFire Docs](http://arrayfire.org/docs/group__gfx__func__window.htm#gadadc41caf7d6a9b7ca2e674079971895)
--
setAxesLimits2d
  :: Window
  -- ^ is the window handle
  -> Float
  -- ^ is the minimum on x-axis
  -> Float
  -- ^ is the maximum on x-axis
  -> Float
  -- ^ is the minimum on y-axis
  -> Float
  -- ^ is the maximum on y-axis
  -> Bool
  -- ^ is for using the exact min/max values from x, and y. If exact is false then the most significant digit is rounded up to next power of 2 and the magnitude remains the same.
  -> Cell
  -- ^ is structure af_cell that has the properties that are used for the current rendering.
  -> IO ()
setAxesLimits2d (Window w) xmin xmax ymin ymax (fromIntegral . fromEnum -> exact) cell =
  mask_ $ do
   withForeignPtr w $ \wptr ->
    alloca $ \cellPtr -> do
      poke cellPtr =<< cellToAFCell cell
      throwAFError =<< af_set_axes_limits_2d wptr xmin xmax ymin ymax exact cellPtr
      free cellPtr

-- | Setting axes limits for a 3D histogram/plot/surface/vector field.
--
-- [ArrayFire Docs](http://arrayfire.org/docs/group__gfx__func__window.htm#gadcd1bd46b9d6fabc047365ca5dc3f73d)
--
setAxesLimits3d
  :: Window
  -- ^ is the window handle
  -> Float
  -- ^ is the minimum on x-axis
  -> Float
  -- ^ is the maximum on x-axis
  -> Float
  -- ^ is the minimum on y-axis
  -> Float
  -- ^ is the maximum on y-axis
  -> Float
  -- ^ is the minimum on z-axis
  -> Float
  -- ^ is the maximum on z-axis
  -> Bool
  -- ^ is for using the exact min/max values from x, y and z. If exact is false then the most significant digit is rounded up to next power of 2 and the magnitude remains the same.
  -> Cell
  -- ^ is structure 'Cell' that has the properties that are used for the current rendering.
  -> IO ()
setAxesLimits3d (Window w) xmin xmax ymin ymax zmin zmax (fromIntegral . fromEnum -> exact) cell =
  mask_ $ do
   withForeignPtr w $ \wptr ->
    alloca $ \cellPtr -> do
      poke cellPtr =<< cellToAFCell cell
      throwAFError =<< af_set_axes_limits_3d wptr xmin xmax ymin ymax zmin zmax exact cellPtr
      free cellPtr


-- | Setting axes titles
--
-- [ArrayFire Docs](http://arrayfire.org/docs/group__gfx__func__window.htm#gadcd1bd46b9d6fabc047365ca5dc3f73d)
--
setAxesTitles
  :: Window
  -- ^ is the window handle
  -> String
  -- ^ is the name of the x-axis
  -> String
  -- ^ is the name of the y-axis
  -> String
  -- ^ is the name of the z-axis
  -> Cell
  -- ^ is structure 'Cell' that has the properties that are used for the current rendering.
  -> IO ()
setAxesTitles (Window w) x y z cell =
  mask_ $ do
   withForeignPtr w $ \wptr ->
    alloca $ \cellPtr -> do
      withCString x $ \xstr ->
        withCString y $ \ystr ->
          withCString z $ \zstr -> do
            poke cellPtr =<< cellToAFCell cell
            throwAFError =<< af_set_axes_titles wptr xstr ystr zstr cellPtr
            free cellPtr

-- | Displays 'Window'
--
-- [ArrayFire Docs](http://arrayfire.org/docs/group__gfx__func__window.htm#ga50dae861324dca1cce9f583256f5a654)
--
showWindow
  :: Window
  -- ^ 'Window' handle
   -> IO ()
showWindow = (`opw` af_show)

-- | Checks if 'Window' is closed
--
-- [ArrayFire Docs](http://arrayfire.org/docs/group__gfx__func__window.htm#ga50dae861324dca1cce9f583256f5a654)
--
isWindowClosed :: Window -> IO Bool
isWindowClosed w =
  toEnum . fromIntegral
    <$> (w `opw1` af_is_window_closed)

-- | Sets 'Window' visibility
--
-- [ArrayFire Docs](http://arrayfire.org/docs/group__gfx__func__window.htm#gad7b63c70d45e101c4d8d500273e310c7)
--
setVisibility
  :: Window
  -- ^ 'Window' handle
  -> Bool
  -- ^ Set to 'True' to display 'Window'
  -> IO ()
setVisibility w (fromIntegral . fromEnum -> b) = w `opw` (`af_set_visibility` b)