{-# LANGUAGE CApiFFI #-}
{-# LANGUAGE ForeignFunctionInterface #-}
module H3.Internal.FFI
  ( degsToRads
  , radsToDegs
  , getResolution
  , getBaseCellNumber
  , isValidCell
  , isResClassIII
  , isPentagon
  , hsGetIcosahedronFaces
  , hsPolygonToCells 
  , hsGetRes0Cells
  , hsGetPentagons
  , hsGridDisk
  , hsGridDiskUnsafe
  , hsGridDiskDistances 
  , hsGridDiskDistancesSafe 
  , hsGridDiskDistancesUnsafe
  , hsGridRingUnsafe
  , hsGridPathCells
  , hsCellToChildren
  , hsCompactCells 
  , hsUncompactCells 
  , isValidDirectedEdge
  , hsDirectedEdgeToCells
  , hsOriginToDirectedEdges
  , hsCellToVertexes 
  , isValidVertex
  ) where

import Data.Int (Int64)
import Data.Word (Word32)
import System.IO.Unsafe (unsafePerformIO)
import Foreign.C.Types (CInt, CLong)
import Foreign.Ptr (Ptr)
import Foreign.Storable (Storable(peek))
import Foreign.Marshal.Alloc (alloca, free)
import Foreign.Marshal.Array (allocaArray, withArray, peekArray, callocArray, withArray, withArrayLen)
import H3.Internal.H3Api 
  ( H3Index
  , H3Error
  , CGeoPolygon
  , newCGeoPolygonPtr 
  , destroyCGeoPolygonPtr 
  , GeoPolygon
  )


-- |degsToRads converts from degrees to radians.
foreign import capi "h3/h3api.h degsToRads" degsToRads :: Double -> Double

-- |radsToDegs converts from radians to degrees
foreign import capi "h3/h3api.h radsToDegs" radsToDegs :: Double -> Double

-- Inspection

-- | Returns the resolution of the index.
foreign import capi "h3/h3api.h getResolution" getResolution :: H3Index -> Int

-- | Returns the base cell number of the index.
foreign import capi "h3/h3api.h getBaseCellNumber" getBaseCellNumber :: H3Index -> Int

-- | isValidCell returns non-zero if this is a valid H3 cell index
foreign import capi "h3/h3api.h isValidCell" isValidCell :: H3Index -> Int

-- | Returns non-zero if this index has a resolution with Class III orientation.
foreign import capi "h3/h3api.h isResClassIII" isResClassIII :: H3Index -> Int

-- | Returns non-zero if this index represents a pentagonal cell.
foreign import capi "h3/h3api.h isPentagon" isPentagon :: H3Index -> Int

foreign import capi "h3/h3api.h maxFaceCount" c_maxFaceCount :: H3Index -> Ptr CInt -> IO H3Error

foreign import capi "h3/h3api.h getIcosahedronFaces" c_getIcosahedronFaces :: H3Index -> Ptr CInt -> IO H3Error

hsGetIcosahedronFaces :: H3Index -> (H3Error, [Int])
hsGetIcosahedronFaces :: H3Index -> (H3Error, [Int])
hsGetIcosahedronFaces H3Index
h3index = 
  IO (H3Error, [Int]) -> (H3Error, [Int])
forall a. IO a -> a
unsafePerformIO (IO (H3Error, [Int]) -> (H3Error, [Int]))
-> IO (H3Error, [Int]) -> (H3Error, [Int])
forall a b. (a -> b) -> a -> b
$ (Ptr CInt -> IO (H3Error, [Int])) -> IO (H3Error, [Int])
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr CInt -> IO (H3Error, [Int])) -> IO (H3Error, [Int]))
-> (Ptr CInt -> IO (H3Error, [Int])) -> IO (H3Error, [Int])
forall a b. (a -> b) -> a -> b
$ \Ptr CInt
countptr -> do
    h3error <- H3Index -> Ptr CInt -> IO H3Error
c_maxFaceCount H3Index
h3index Ptr CInt
countptr
    if h3error == 0
    then do
      count <- fromIntegral <$> peek countptr
      allocaArray count $ \Ptr CInt
facesptr -> do
        out3error <- H3Index -> Ptr CInt -> IO H3Error
c_getIcosahedronFaces H3Index
h3index Ptr CInt
facesptr
        if out3error == 0
        then do
          faces <- map fromIntegral <$> peekArray count facesptr
          return (out3error, faces)
        else return (out3error, [])
    else return (h3error, [])


-- Regions


foreign import capi "h3/h3api.h maxPolygonToCellsSize" cMaxPolygonToCellsSize :: Ptr CGeoPolygon -> Int -> Word32 -> Ptr CLong -> IO H3Error

foreign import capi "h3/h3api.h polygonToCells" cPolygonToCells :: Ptr CGeoPolygon -> Int -> Word32 -> Ptr H3Index -> IO H3Error

hsPolygonToCellsIO :: GeoPolygon -> Int -> Word32 -> IO (H3Error, [H3Index])
hsPolygonToCellsIO :: GeoPolygon -> Int -> H3Error -> IO (H3Error, [H3Index])
hsPolygonToCellsIO GeoPolygon
poly Int
res H3Error
flags = do
  cpolyPtr <- GeoPolygon -> IO (Ptr CGeoPolygon)
newCGeoPolygonPtr GeoPolygon
poly
  (h3error, size) <- alloca $ \Ptr CLong
resultPtr -> do
    h3error <- Ptr CGeoPolygon -> Int -> H3Error -> Ptr CLong -> IO H3Error
cMaxPolygonToCellsSize Ptr CGeoPolygon
cpolyPtr Int
res H3Error
flags Ptr CLong
resultPtr
    result <- peek resultPtr
    return (h3error, result)
  out <- if h3error == 0
         then do let sizei = CLong -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CLong
size
                 resultPtr <- callocArray sizei
                 h3error2 <- cPolygonToCells cpolyPtr res flags resultPtr
                 result <- peekArray sizei resultPtr
                 free resultPtr
                 return (h3error2, result)
         else 
           return (h3error, [])
  destroyCGeoPolygonPtr cpolyPtr 
  return out

hsPolygonToCells :: GeoPolygon -> Int -> Word32 -> (H3Error, [H3Index])
hsPolygonToCells :: GeoPolygon -> Int -> H3Error -> (H3Error, [H3Index])
hsPolygonToCells GeoPolygon
poly Int
res H3Error
flags = IO (H3Error, [H3Index]) -> (H3Error, [H3Index])
forall a. IO a -> a
unsafePerformIO (IO (H3Error, [H3Index]) -> (H3Error, [H3Index]))
-> IO (H3Error, [H3Index]) -> (H3Error, [H3Index])
forall a b. (a -> b) -> a -> b
$ GeoPolygon -> Int -> H3Error -> IO (H3Error, [H3Index])
hsPolygonToCellsIO GeoPolygon
poly Int
res H3Error
flags


-- Miscellaneous


foreign import capi "h3/h3api.h res0CellCount" cRes0CellCount :: IO Int

foreign import capi "h3/h3api.h getRes0Cells" cGetRes0Cells :: Ptr H3Index -> IO H3Error

hsGetRes0Cells :: (H3Error, [H3Index])
hsGetRes0Cells :: (H3Error, [H3Index])
hsGetRes0Cells = IO (H3Error, [H3Index]) -> (H3Error, [H3Index])
forall a. IO a -> a
unsafePerformIO (IO (H3Error, [H3Index]) -> (H3Error, [H3Index]))
-> IO (H3Error, [H3Index]) -> (H3Error, [H3Index])
forall a b. (a -> b) -> a -> b
$ do
  cellCount <- IO Int
cRes0CellCount
  allocaArray cellCount $ \Ptr H3Index
resultPtr -> do
    h3error <- Ptr H3Index -> IO H3Error
cGetRes0Cells Ptr H3Index
resultPtr
    result <- peekArray cellCount resultPtr
    return (h3error, result)

foreign import capi "h3/h3api.h pentagonCount" cPentagonCount :: IO Int

foreign import capi "h3/h3api.h getPentagons" cGetPentagons :: Int -> Ptr H3Index -> IO H3Error

hsGetPentagons :: Int -> (H3Error, [H3Index])
hsGetPentagons :: Int -> (H3Error, [H3Index])
hsGetPentagons Int
res = IO (H3Error, [H3Index]) -> (H3Error, [H3Index])
forall a. IO a -> a
unsafePerformIO (IO (H3Error, [H3Index]) -> (H3Error, [H3Index]))
-> IO (H3Error, [H3Index]) -> (H3Error, [H3Index])
forall a b. (a -> b) -> a -> b
$ do
  cellCount <- IO Int
cPentagonCount
  allocaArray cellCount $ \Ptr H3Index
resultPtr -> do
    h3error <- Int -> Ptr H3Index -> IO H3Error
cGetPentagons Int
res Ptr H3Index
resultPtr
    result <- peekArray cellCount resultPtr
    return (h3error, result)


-- Traversals

foreign import capi "h3/h3api.h maxGridDiskSize" cMaxGridDiskSize :: Int -> Ptr Int64 -> IO H3Error

hsMaxGridDiskSize :: Int -> IO (H3Error, Int64)
hsMaxGridDiskSize :: Int -> IO (H3Error, Int64)
hsMaxGridDiskSize Int
k = do
  (Ptr Int64 -> IO (H3Error, Int64)) -> IO (H3Error, Int64)
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr Int64 -> IO (H3Error, Int64)) -> IO (H3Error, Int64))
-> (Ptr Int64 -> IO (H3Error, Int64)) -> IO (H3Error, Int64)
forall a b. (a -> b) -> a -> b
$ \Ptr Int64
maxSizePtr -> do
    h3error <- Int -> Ptr Int64 -> IO H3Error
cMaxGridDiskSize Int
k Ptr Int64
maxSizePtr
    if h3error == 0
    then do
      maxSize <- fromIntegral <$> peek maxSizePtr
      return (h3error, maxSize)
    else do
      return (h3error, 0)

hsGridRingUnsafeSize :: Int -> IO (H3Error, Int64)
hsGridRingUnsafeSize :: Int -> IO (H3Error, Int64)
hsGridRingUnsafeSize Int
k | Int
k Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0     = Int -> IO (H3Error, Int64)
localGridRingUnsafeSize Int
k
                       | Int
k Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0    = (H3Error, Int64) -> IO (H3Error, Int64)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (H3Error
0, Int64
1)
                       | Bool
otherwise = (H3Error, Int64) -> IO (H3Error, Int64)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (H3Error
2, Int64
0) -- domain error
  where localGridRingUnsafeSize :: Int -> IO (H3Error, Int64)
localGridRingUnsafeSize Int
k0 = do
          (h3error0, size0) <- Int -> IO (H3Error, Int64)
hsMaxGridDiskSize Int
k0
          (h3error1, size1) <- hsMaxGridDiskSize (k0-1)
          if (h3error0 == 0) && (h3error1 == 0)
            then return (h3error0, size0 - size1)
          else if h3error0 /= 0
            then return (h3error0, 0)
          else return (h3error1, 0)
 
hsGridDiskUsingMethod :: (H3Index -> Int -> Ptr H3Index -> IO H3Error) -> H3Index -> Int -> IO (H3Error, [H3Index])
hsGridDiskUsingMethod :: (H3Index -> Int -> Ptr H3Index -> IO H3Error)
-> H3Index -> Int -> IO (H3Error, [H3Index])
hsGridDiskUsingMethod H3Index -> Int -> Ptr H3Index -> IO H3Error
diskMethod H3Index
h3index Int
k = do
  (Ptr Int64 -> IO (H3Error, [H3Index])) -> IO (H3Error, [H3Index])
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr Int64 -> IO (H3Error, [H3Index])) -> IO (H3Error, [H3Index]))
-> (Ptr Int64 -> IO (H3Error, [H3Index]))
-> IO (H3Error, [H3Index])
forall a b. (a -> b) -> a -> b
$ \Ptr Int64
maxSizePtr -> do
    sizeh3error <- Int -> Ptr Int64 -> IO H3Error
cMaxGridDiskSize Int
k Ptr Int64
maxSizePtr
    if sizeh3error == 0
    then do
      maxSize <- fromIntegral <$> peek maxSizePtr
      allocaArray maxSize $ \Ptr H3Index
resultPtr -> do
        h3error <- H3Index -> Int -> Ptr H3Index -> IO H3Error
diskMethod H3Index
h3index Int
k Ptr H3Index
resultPtr
        result <- peekArray maxSize resultPtr
        return (h3error, result)
    else do
      return (sizeh3error, [])
 
foreign import capi "h3/h3api.h gridDisk" cGridDisk :: H3Index -> Int -> Ptr H3Index -> IO H3Error

hsGridDisk :: H3Index -> Int -> (H3Error, [H3Index])
hsGridDisk :: H3Index -> Int -> (H3Error, [H3Index])
hsGridDisk H3Index
origin = IO (H3Error, [H3Index]) -> (H3Error, [H3Index])
forall a. IO a -> a
unsafePerformIO (IO (H3Error, [H3Index]) -> (H3Error, [H3Index]))
-> (Int -> IO (H3Error, [H3Index])) -> Int -> (H3Error, [H3Index])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (H3Index -> Int -> Ptr H3Index -> IO H3Error)
-> H3Index -> Int -> IO (H3Error, [H3Index])
hsGridDiskUsingMethod H3Index -> Int -> Ptr H3Index -> IO H3Error
cGridDisk H3Index
origin

foreign import capi "h3/h3api.h gridDiskUnsafe" cGridDiskUnsafe :: H3Index -> Int -> Ptr H3Index -> IO H3Error

hsGridDiskUnsafe :: H3Index -> Int -> (H3Error, [H3Index])
hsGridDiskUnsafe :: H3Index -> Int -> (H3Error, [H3Index])
hsGridDiskUnsafe H3Index
origin = IO (H3Error, [H3Index]) -> (H3Error, [H3Index])
forall a. IO a -> a
unsafePerformIO (IO (H3Error, [H3Index]) -> (H3Error, [H3Index]))
-> (Int -> IO (H3Error, [H3Index])) -> Int -> (H3Error, [H3Index])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (H3Index -> Int -> Ptr H3Index -> IO H3Error)
-> H3Index -> Int -> IO (H3Error, [H3Index])
hsGridDiskUsingMethod H3Index -> Int -> Ptr H3Index -> IO H3Error
cGridDiskUnsafe H3Index
origin

hsGridDiskDistancesUsingMethod :: (H3Index -> Int -> Ptr H3Index -> Ptr CInt -> IO H3Error) -> H3Index -> Int -> IO (H3Error, ([H3Index], [Int]))
hsGridDiskDistancesUsingMethod :: (H3Index -> Int -> Ptr H3Index -> Ptr CInt -> IO H3Error)
-> H3Index -> Int -> IO (H3Error, ([H3Index], [Int]))
hsGridDiskDistancesUsingMethod H3Index -> Int -> Ptr H3Index -> Ptr CInt -> IO H3Error
diskDistanceMethod H3Index
h3index Int
k = do
  (Ptr Int64 -> IO (H3Error, ([H3Index], [Int])))
-> IO (H3Error, ([H3Index], [Int]))
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr Int64 -> IO (H3Error, ([H3Index], [Int])))
 -> IO (H3Error, ([H3Index], [Int])))
-> (Ptr Int64 -> IO (H3Error, ([H3Index], [Int])))
-> IO (H3Error, ([H3Index], [Int]))
forall a b. (a -> b) -> a -> b
$ \Ptr Int64
maxSizePtr -> do
    sizeh3error <- Int -> Ptr Int64 -> IO H3Error
cMaxGridDiskSize Int
k Ptr Int64
maxSizePtr
    if sizeh3error == 0
    then do
      maxSize <- fromIntegral <$> peek maxSizePtr
      allocaArray maxSize $ \Ptr H3Index
indexResultPtr -> do
        Int
-> (Ptr CInt -> IO (H3Error, ([H3Index], [Int])))
-> IO (H3Error, ([H3Index], [Int]))
forall a b. Storable a => Int -> (Ptr a -> IO b) -> IO b
allocaArray Int
maxSize ((Ptr CInt -> IO (H3Error, ([H3Index], [Int])))
 -> IO (H3Error, ([H3Index], [Int])))
-> (Ptr CInt -> IO (H3Error, ([H3Index], [Int])))
-> IO (H3Error, ([H3Index], [Int]))
forall a b. (a -> b) -> a -> b
$ \Ptr CInt
distanceResultPtr -> do
          h3error <- H3Index -> Int -> Ptr H3Index -> Ptr CInt -> IO H3Error
diskDistanceMethod H3Index
h3index Int
k Ptr H3Index
indexResultPtr Ptr CInt
distanceResultPtr
          indexResult <- peekArray maxSize indexResultPtr
          distanceResult <- map fromIntegral <$> peekArray maxSize distanceResultPtr
          return (h3error, (indexResult, distanceResult))
    else do
      return (sizeh3error, ([], []))

foreign import capi "h3/h3api.h gridDiskDistances" cGridDiskDistances :: H3Index -> Int -> Ptr H3Index -> Ptr CInt -> IO H3Error

hsGridDiskDistances :: H3Index -> Int -> (H3Error, ([H3Index], [Int]))
hsGridDiskDistances :: H3Index -> Int -> (H3Error, ([H3Index], [Int]))
hsGridDiskDistances H3Index
origin = IO (H3Error, ([H3Index], [Int])) -> (H3Error, ([H3Index], [Int]))
forall a. IO a -> a
unsafePerformIO (IO (H3Error, ([H3Index], [Int])) -> (H3Error, ([H3Index], [Int])))
-> (Int -> IO (H3Error, ([H3Index], [Int])))
-> Int
-> (H3Error, ([H3Index], [Int]))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (H3Index -> Int -> Ptr H3Index -> Ptr CInt -> IO H3Error)
-> H3Index -> Int -> IO (H3Error, ([H3Index], [Int]))
hsGridDiskDistancesUsingMethod H3Index -> Int -> Ptr H3Index -> Ptr CInt -> IO H3Error
cGridDiskDistances H3Index
origin

foreign import capi "h3/h3api.h gridDiskDistancesSafe" cGridDiskDistancesSafe :: H3Index -> Int -> Ptr H3Index -> Ptr CInt -> IO H3Error

hsGridDiskDistancesSafe :: H3Index -> Int -> (H3Error, ([H3Index], [Int]))
hsGridDiskDistancesSafe :: H3Index -> Int -> (H3Error, ([H3Index], [Int]))
hsGridDiskDistancesSafe H3Index
origin = IO (H3Error, ([H3Index], [Int])) -> (H3Error, ([H3Index], [Int]))
forall a. IO a -> a
unsafePerformIO (IO (H3Error, ([H3Index], [Int])) -> (H3Error, ([H3Index], [Int])))
-> (Int -> IO (H3Error, ([H3Index], [Int])))
-> Int
-> (H3Error, ([H3Index], [Int]))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (H3Index -> Int -> Ptr H3Index -> Ptr CInt -> IO H3Error)
-> H3Index -> Int -> IO (H3Error, ([H3Index], [Int]))
hsGridDiskDistancesUsingMethod H3Index -> Int -> Ptr H3Index -> Ptr CInt -> IO H3Error
cGridDiskDistancesSafe H3Index
origin

foreign import capi "h3/h3api.h gridDiskDistancesUnsafe" cGridDiskDistancesUnsafe :: H3Index -> Int -> Ptr H3Index -> Ptr CInt -> IO H3Error

hsGridDiskDistancesUnsafe :: H3Index -> Int -> (H3Error, ([H3Index], [Int]))
hsGridDiskDistancesUnsafe :: H3Index -> Int -> (H3Error, ([H3Index], [Int]))
hsGridDiskDistancesUnsafe H3Index
origin = IO (H3Error, ([H3Index], [Int])) -> (H3Error, ([H3Index], [Int]))
forall a. IO a -> a
unsafePerformIO (IO (H3Error, ([H3Index], [Int])) -> (H3Error, ([H3Index], [Int])))
-> (Int -> IO (H3Error, ([H3Index], [Int])))
-> Int
-> (H3Error, ([H3Index], [Int]))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (H3Index -> Int -> Ptr H3Index -> Ptr CInt -> IO H3Error)
-> H3Index -> Int -> IO (H3Error, ([H3Index], [Int]))
hsGridDiskDistancesUsingMethod H3Index -> Int -> Ptr H3Index -> Ptr CInt -> IO H3Error
cGridDiskDistancesUnsafe H3Index
origin

foreign import capi "h3/h3api.h gridRingUnsafe" cGridRingUnsafe :: H3Index -> Int -> Ptr H3Index -> IO H3Error

hsGridRingUnsafe :: H3Index -> Int -> (H3Error, [H3Index])
hsGridRingUnsafe :: H3Index -> Int -> (H3Error, [H3Index])
hsGridRingUnsafe H3Index
origin Int
k = IO (H3Error, [H3Index]) -> (H3Error, [H3Index])
forall a. IO a -> a
unsafePerformIO (IO (H3Error, [H3Index]) -> (H3Error, [H3Index]))
-> IO (H3Error, [H3Index]) -> (H3Error, [H3Index])
forall a b. (a -> b) -> a -> b
$ do
  (sizeh3error, maxSize64) <- Int -> IO (H3Error, Int64)
hsGridRingUnsafeSize Int
k
  let maxSize = Int64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
maxSize64
  if sizeh3error == 0
  then do
    withArray (replicate maxSize 0) $ \Ptr H3Index
resultPtr -> do
      h3error <- H3Index -> Int -> Ptr H3Index -> IO H3Error
cGridRingUnsafe H3Index
origin Int
k Ptr H3Index
resultPtr
      if h3error == 0
      then do
        result <- peekArray maxSize resultPtr
        return (h3error, result)
      else return (h3error, [])
  else return (sizeh3error, [])

foreign import capi "h3/h3api.h gridPathCellsSize" cGridPathCellsSize :: H3Index -> H3Index -> Ptr Int64 -> IO H3Error

foreign import capi "h3/h3api.h gridPathCells" cGridPathCells :: H3Index -> H3Index -> Ptr H3Index -> IO H3Error

hsGridPathCells :: H3Index -> H3Index -> (H3Error, [H3Index])
hsGridPathCells :: H3Index -> H3Index -> (H3Error, [H3Index])
hsGridPathCells H3Index
origin H3Index
h3 = 
  IO (H3Error, [H3Index]) -> (H3Error, [H3Index])
forall a. IO a -> a
unsafePerformIO (IO (H3Error, [H3Index]) -> (H3Error, [H3Index]))
-> IO (H3Error, [H3Index]) -> (H3Error, [H3Index])
forall a b. (a -> b) -> a -> b
$ (Ptr Int64 -> IO (H3Error, [H3Index])) -> IO (H3Error, [H3Index])
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr Int64 -> IO (H3Error, [H3Index])) -> IO (H3Error, [H3Index]))
-> (Ptr Int64 -> IO (H3Error, [H3Index]))
-> IO (H3Error, [H3Index])
forall a b. (a -> b) -> a -> b
$ \Ptr Int64
sizePtr -> do
    sizeh3error <- H3Index -> H3Index -> Ptr Int64 -> IO H3Error
cGridPathCellsSize H3Index
origin H3Index
h3 Ptr Int64
sizePtr
    if sizeh3error == 0
    then do
      size <- fromIntegral <$> peek sizePtr
      allocaArray size $ \Ptr H3Index
resultPtr -> do
        h3error <- H3Index -> H3Index -> Ptr H3Index -> IO H3Error
cGridPathCells H3Index
origin H3Index
h3 Ptr H3Index
resultPtr
        result <- peekArray size resultPtr
        return (h3error, result)
    else do
      return (sizeh3error, [])

-- Note: We are skipping the binding of gridDisksUnsafe at this time, 
--       as we are not certain about the sizing of the output array of H3Index values 
--       at this time.


-- Hierarchy


foreign import capi "h3/h3api.h cellToChildrenSize" cCellToChildrenSize :: H3Index -> Int -> Ptr Int64 -> IO H3Error

foreign import capi "h3/h3api.h cellToChildren" cCellToChildren :: H3Index -> Int -> Ptr H3Index -> IO H3Error

hsCellToChildren :: H3Index -> Int -> (H3Error, [H3Index])
hsCellToChildren :: H3Index -> Int -> (H3Error, [H3Index])
hsCellToChildren H3Index
cell Int
childRes = IO (H3Error, [H3Index]) -> (H3Error, [H3Index])
forall a. IO a -> a
unsafePerformIO (IO (H3Error, [H3Index]) -> (H3Error, [H3Index]))
-> IO (H3Error, [H3Index]) -> (H3Error, [H3Index])
forall a b. (a -> b) -> a -> b
$ do
  (Ptr Int64 -> IO (H3Error, [H3Index])) -> IO (H3Error, [H3Index])
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr Int64 -> IO (H3Error, [H3Index])) -> IO (H3Error, [H3Index]))
-> (Ptr Int64 -> IO (H3Error, [H3Index]))
-> IO (H3Error, [H3Index])
forall a b. (a -> b) -> a -> b
$ \Ptr Int64
sizePtr -> do
    sizeh3error <- H3Index -> Int -> Ptr Int64 -> IO H3Error
cCellToChildrenSize H3Index
cell Int
childRes Ptr Int64
sizePtr
    if sizeh3error == 0
    then do
      size <- fromIntegral <$> peek sizePtr
      allocaArray size $ \Ptr H3Index
resultPtr -> do
        h3error <- H3Index -> Int -> Ptr H3Index -> IO H3Error
cCellToChildren H3Index
cell Int
childRes Ptr H3Index
resultPtr
        if h3error == 0
        then do
          result <- peekArray size resultPtr
          return (h3error, result)
        else return (h3error, [])
    else return (sizeh3error, [])

-- Normally a method like compactCells would be in H3Api.chs, but the order of the arguments 
-- reduces the benefit of c2hs fun hooks
foreign import capi "h3/h3api.h compactCells" cCompactCells :: Ptr H3Index -> Ptr H3Index -> Int64 -> IO H3Error

hsCompactCells :: [H3Index] -> (H3Error, [H3Index])
hsCompactCells :: [H3Index] -> (H3Error, [H3Index])
hsCompactCells [H3Index]
cellSet = IO (H3Error, [H3Index]) -> (H3Error, [H3Index])
forall a. IO a -> a
unsafePerformIO (IO (H3Error, [H3Index]) -> (H3Error, [H3Index]))
-> IO (H3Error, [H3Index]) -> (H3Error, [H3Index])
forall a b. (a -> b) -> a -> b
$ do
  [H3Index]
-> (Ptr H3Index -> IO (H3Error, [H3Index]))
-> IO (H3Error, [H3Index])
forall a b. Storable a => [a] -> (Ptr a -> IO b) -> IO b
withArray [H3Index]
cellSet ((Ptr H3Index -> IO (H3Error, [H3Index]))
 -> IO (H3Error, [H3Index]))
-> (Ptr H3Index -> IO (H3Error, [H3Index]))
-> IO (H3Error, [H3Index])
forall a b. (a -> b) -> a -> b
$ \Ptr H3Index
cellSetPtr -> do
    let size :: Int
size = [H3Index] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [H3Index]
cellSet
    Int
-> (Ptr H3Index -> IO (H3Error, [H3Index]))
-> IO (H3Error, [H3Index])
forall a b. Storable a => Int -> (Ptr a -> IO b) -> IO b
allocaArray Int
size ((Ptr H3Index -> IO (H3Error, [H3Index]))
 -> IO (H3Error, [H3Index]))
-> (Ptr H3Index -> IO (H3Error, [H3Index]))
-> IO (H3Error, [H3Index])
forall a b. (a -> b) -> a -> b
$ \Ptr H3Index
compactedSetPtr -> do
      h3error <- Ptr H3Index -> Ptr H3Index -> Int64 -> IO H3Error
cCompactCells Ptr H3Index
cellSetPtr Ptr H3Index
compactedSetPtr (Int -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
size)
      if h3error == 0
      then do
        result <- peekArray size compactedSetPtr
        return (h3error, result)
      else return (h3error, [])

foreign import capi "h3/h3api.h uncompactCellsSize" cUncompactCellsSize :: Ptr H3Index -> Int64 -> Int -> Ptr Int64 -> IO H3Error

foreign import capi "h3/h3api.h uncompactCells" cUncompactCells :: Ptr H3Index -> Int64 -> Ptr H3Index -> Int64 -> Int -> IO H3Error

hsUncompactCells :: [H3Index] -> Int -> (H3Error, [H3Index])
hsUncompactCells :: [H3Index] -> Int -> (H3Error, [H3Index])
hsUncompactCells [H3Index]
compactedSet Int
res = IO (H3Error, [H3Index]) -> (H3Error, [H3Index])
forall a. IO a -> a
unsafePerformIO (IO (H3Error, [H3Index]) -> (H3Error, [H3Index]))
-> IO (H3Error, [H3Index]) -> (H3Error, [H3Index])
forall a b. (a -> b) -> a -> b
$ do
  [H3Index]
-> (Int -> Ptr H3Index -> IO (H3Error, [H3Index]))
-> IO (H3Error, [H3Index])
forall a b. Storable a => [a] -> (Int -> Ptr a -> IO b) -> IO b
withArrayLen [H3Index]
compactedSet ((Int -> Ptr H3Index -> IO (H3Error, [H3Index]))
 -> IO (H3Error, [H3Index]))
-> (Int -> Ptr H3Index -> IO (H3Error, [H3Index]))
-> IO (H3Error, [H3Index])
forall a b. (a -> b) -> a -> b
$ \Int
numCells Ptr H3Index
compactedSetPtr -> do
    (sizeh3error, maxCells) <- (Ptr Int64 -> IO (H3Error, Int64)) -> IO (H3Error, Int64)
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr Int64 -> IO (H3Error, Int64)) -> IO (H3Error, Int64))
-> (Ptr Int64 -> IO (H3Error, Int64)) -> IO (H3Error, Int64)
forall a b. (a -> b) -> a -> b
$ \Ptr Int64
maxCellsPtr -> do
      sizeh3error <- Ptr H3Index -> Int64 -> Int -> Ptr Int64 -> IO H3Error
cUncompactCellsSize Ptr H3Index
compactedSetPtr (Int -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
numCells) Int
res Ptr Int64
maxCellsPtr
      if sizeh3error == 0
      then do
        size <- peek maxCellsPtr
        return (sizeh3error, size)
      else return (sizeh3error, 0)
    if sizeh3error == 0
    then do
      let maxCellsInt = Int64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
maxCells
      allocaArray maxCellsInt $ \Ptr H3Index
cellSetPtr -> do
        h3error <- Ptr H3Index -> Int64 -> Ptr H3Index -> Int64 -> Int -> IO H3Error
cUncompactCells Ptr H3Index
compactedSetPtr (Int -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
numCells) Ptr H3Index
cellSetPtr Int64
maxCells Int
res
        if h3error == 0
        then do
          cellSet <- peekArray maxCellsInt cellSetPtr
          return (h3error, cellSet)
        else return (h3error, [])
    else return (sizeh3error, [])

-- Directed edges


foreign import capi "h3/h3api.h isValidDirectedEdge" cIsValidDirectedEdge :: H3Index -> Int

-- |Determines if the provided 'H3Index' is a valid unidirectional edge index.
isValidDirectedEdge :: H3Index -> Bool
isValidDirectedEdge :: H3Index -> Bool
isValidDirectedEdge = (Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/=Int
0) (Int -> Bool) -> (H3Index -> Int) -> H3Index -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. H3Index -> Int
cIsValidDirectedEdge

foreign import capi "h3/h3api.h directedEdgeToCells" cDirectedEdgeToCells :: H3Index -> Ptr H3Index -> IO H3Error

hsDirectedEdgeToCells :: H3Index -> (H3Error, [H3Index])
hsDirectedEdgeToCells :: H3Index -> (H3Error, [H3Index])
hsDirectedEdgeToCells H3Index
h3index = IO (H3Error, [H3Index]) -> (H3Error, [H3Index])
forall a. IO a -> a
unsafePerformIO (IO (H3Error, [H3Index]) -> (H3Error, [H3Index]))
-> IO (H3Error, [H3Index]) -> (H3Error, [H3Index])
forall a b. (a -> b) -> a -> b
$ do
  Int
-> (Ptr H3Index -> IO (H3Error, [H3Index]))
-> IO (H3Error, [H3Index])
forall a b. Storable a => Int -> (Ptr a -> IO b) -> IO b
allocaArray Int
2 ((Ptr H3Index -> IO (H3Error, [H3Index]))
 -> IO (H3Error, [H3Index]))
-> (Ptr H3Index -> IO (H3Error, [H3Index]))
-> IO (H3Error, [H3Index])
forall a b. (a -> b) -> a -> b
$ \Ptr H3Index
originDestinationPtr -> do
    h3error <- H3Index -> Ptr H3Index -> IO H3Error
cDirectedEdgeToCells H3Index
h3index Ptr H3Index
originDestinationPtr 
    if h3error == 0
    then do
      originDestination <- peekArray 2 originDestinationPtr
      return (h3error, originDestination)
    else return (h3error, [])

foreign import capi "h3/h3api.h originToDirectedEdges" cOriginToDirectedEdges :: H3Index -> Ptr H3Index -> IO H3Error

hsOriginToDirectedEdges :: H3Index -> (H3Error, [H3Index])
hsOriginToDirectedEdges :: H3Index -> (H3Error, [H3Index])
hsOriginToDirectedEdges H3Index
h3index = IO (H3Error, [H3Index]) -> (H3Error, [H3Index])
forall a. IO a -> a
unsafePerformIO (IO (H3Error, [H3Index]) -> (H3Error, [H3Index]))
-> IO (H3Error, [H3Index]) -> (H3Error, [H3Index])
forall a b. (a -> b) -> a -> b
$ do
  Int
-> (Ptr H3Index -> IO (H3Error, [H3Index]))
-> IO (H3Error, [H3Index])
forall a b. Storable a => Int -> (Ptr a -> IO b) -> IO b
allocaArray Int
edgeCount ((Ptr H3Index -> IO (H3Error, [H3Index]))
 -> IO (H3Error, [H3Index]))
-> (Ptr H3Index -> IO (H3Error, [H3Index]))
-> IO (H3Error, [H3Index])
forall a b. (a -> b) -> a -> b
$ \Ptr H3Index
edgesPtr -> do
    h3error <- H3Index -> Ptr H3Index -> IO H3Error
cOriginToDirectedEdges H3Index
h3index Ptr H3Index
edgesPtr
    if h3error == 0
    then do
      edges <- peekArray edgeCount edgesPtr
      return (h3error, edges)
    else return (h3error, [])
  where edgeCount :: Int
edgeCount = Int
6


-- Vertexes 


foreign import capi "h3/h3api.h cellToVertexes" cCellToVertexes :: H3Index -> Ptr H3Index -> IO H3Error

hsCellToVertexes :: H3Index -> (H3Error, [H3Index])
hsCellToVertexes :: H3Index -> (H3Error, [H3Index])
hsCellToVertexes H3Index
origin = IO (H3Error, [H3Index]) -> (H3Error, [H3Index])
forall a. IO a -> a
unsafePerformIO (IO (H3Error, [H3Index]) -> (H3Error, [H3Index]))
-> IO (H3Error, [H3Index]) -> (H3Error, [H3Index])
forall a b. (a -> b) -> a -> b
$ do
  Int
-> (Ptr H3Index -> IO (H3Error, [H3Index]))
-> IO (H3Error, [H3Index])
forall a b. Storable a => Int -> (Ptr a -> IO b) -> IO b
allocaArray Int
vertexCount ((Ptr H3Index -> IO (H3Error, [H3Index]))
 -> IO (H3Error, [H3Index]))
-> (Ptr H3Index -> IO (H3Error, [H3Index]))
-> IO (H3Error, [H3Index])
forall a b. (a -> b) -> a -> b
$ \Ptr H3Index
outPtr -> do
    h3error <- H3Index -> Ptr H3Index -> IO H3Error
cCellToVertexes H3Index
origin Ptr H3Index
outPtr
    if h3error == 0
    then do
      out <- peekArray vertexCount outPtr
      return (h3error, out)
    else return (h3error, [])
  where vertexCount :: Int
vertexCount = Int
6

foreign import capi "h3/h3api.h isValidVertex" cIsValidVertex :: H3Index -> Int

-- | Returns True if the given index represents a valid H3 vertex.
isValidVertex :: H3Index -> Bool
isValidVertex :: H3Index -> Bool
isValidVertex = (Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/=Int
0) (Int -> Bool) -> (H3Index -> Int) -> H3Index -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. H3Index -> Int
cIsValidVertex