-- Refer to the eWKB Postgis Documentation <https://postgis.net/docs/using_postgis_dbmanagement.html#EWKB_EWKT>
--
-- Allows parsing of ByteString into a Geospatial Object.
--
-------------------------------------------------------------------
module Data.Ewkb
  ( parseByteString
  , parseHexByteString
  , toByteString
  ) where

import qualified Data.Binary.Get              as BinaryGet
import qualified Data.ByteString.Builder      as ByteStringBuilder
import qualified Data.ByteString.Lazy         as LazyByteString
import qualified Data.Geospatial              as Geospatial
import qualified Data.Hex                     as Hex

import qualified Data.Internal.Ewkb.Geometry  as EwkbGeometry
import qualified Data.Internal.Wkb.Endian     as Endian
import qualified Data.Internal.Wkb.Geospatial as WkbGeospatial

-- |
-- Representation of EWKB as Binary
parseByteString :: LazyByteString.ByteString -> Either String Geospatial.GeospatialGeometry
parseByteString :: ByteString -> Either String GeospatialGeometry
parseByteString ByteString
byteString =
  case Get GeospatialGeometry
-> ByteString
-> Either
     (ByteString, ByteOffset, String)
     (ByteString, ByteOffset, GeospatialGeometry)
forall a.
Get a
-> ByteString
-> Either
     (ByteString, ByteOffset, String) (ByteString, ByteOffset, a)
BinaryGet.runGetOrFail
        ((EndianType -> Get WkbGeometryType) -> Get GeospatialGeometry
WkbGeospatial.getGeospatialGeometry EndianType -> Get WkbGeometryType
EwkbGeometry.getWkbGeom)
        ByteString
byteString of
    Left (ByteString
_, ByteOffset
_, String
err)                 -> String -> Either String GeospatialGeometry
forall a b. a -> Either a b
Left (String -> Either String GeospatialGeometry)
-> String -> Either String GeospatialGeometry
forall a b. (a -> b) -> a -> b
$ String
"Could not parse ewkb: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
err
    Right (ByteString
_, ByteOffset
_, GeospatialGeometry
geoSpatialGeometry) -> GeospatialGeometry -> Either String GeospatialGeometry
forall a b. b -> Either a b
Right GeospatialGeometry
geoSpatialGeometry

-- |
-- Representation of EWKB as a String in Base16/Hex form i.e. "0101000000000000000000f03f0000000000000040" is POINT 1.0 2.0
parseHexByteString :: Hex.Hex -> Either String Geospatial.GeospatialGeometry
parseHexByteString :: Hex -> Either String GeospatialGeometry
parseHexByteString = (ByteString -> Either String GeospatialGeometry)
-> Hex -> Either String GeospatialGeometry
Hex.safeConvert ByteString -> Either String GeospatialGeometry
parseByteString

-- |
-- Produce the binary representation of EWKB given its EndianType (Little or Big - Intel is Little) and SRID (4326 for example).
toByteString :: Endian.EndianType -> EwkbGeometry.SridType -> Geospatial.GeospatialGeometry -> LazyByteString.ByteString
toByteString :: EndianType -> SridType -> GeospatialGeometry -> ByteString
toByteString EndianType
endianType SridType
sridType =
  Builder -> ByteString
ByteStringBuilder.toLazyByteString (Builder -> ByteString)
-> (GeospatialGeometry -> Builder)
-> GeospatialGeometry
-> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. BuilderWkbGeometryType
-> EndianType -> GeospatialGeometry -> Builder
WkbGeospatial.builderGeospatialGeometry
    BuilderWkbGeometryType
mkBuilder EndianType
endianType
  where mkBuilder :: BuilderWkbGeometryType
mkBuilder EndianType
eType WkbGeometryType
gType = EndianType -> EwkbGeometryType -> Builder
EwkbGeometry.builderEwkbGeom EndianType
eType (WkbGeometryType -> SridType -> EwkbGeometryType
EwkbGeometry.EwkbGeom WkbGeometryType
gType SridType
sridType)