module Data.Internal.Wkb.Geospatial
  ( getGeospatialGeometry
  , builderGeospatialGeometry
  ) where

import qualified Data.Binary.Get                      as BinaryGet
import qualified Data.ByteString.Builder              as ByteStringBuilder
import qualified Data.Geospatial                      as Geospatial
import qualified Data.Monoid                          as Monoid

import qualified Data.Internal.Wkb.Endian             as Endian
import qualified Data.Internal.Wkb.Geometry           as Geometry
import qualified Data.Internal.Wkb.GeometryCollection as GeometryCollection
import qualified Data.Internal.Wkb.Line               as Line
import qualified Data.Internal.Wkb.Point              as Point
import qualified Data.Internal.Wkb.Polygon            as Polygon


-- Binary parsers

getGeospatialGeometry :: (Endian.EndianType -> BinaryGet.Get Geometry.WkbGeometryType)
                      -> BinaryGet.Get Geospatial.GeospatialGeometry
getGeospatialGeometry :: (EndianType -> Get WkbGeometryType) -> Get GeospatialGeometry
getGeospatialGeometry EndianType -> Get WkbGeometryType
getWkbGeom = do
  EndianType
endianType <- Get EndianType
Endian.getEndianType
  WkbGeometryType
geometryTypeWithCoords <- EndianType -> Get WkbGeometryType
getWkbGeom EndianType
endianType
  let (Geometry.WkbGeom GeometryType
geomType CoordinateType
coordType) = WkbGeometryType
geometryTypeWithCoords
  GeometryType
-> (EndianType -> Get WkbGeometryType)
-> EndianType
-> CoordinateType
-> Get GeospatialGeometry
getFeature GeometryType
geomType EndianType -> Get WkbGeometryType
getWkbGeom EndianType
endianType CoordinateType
coordType

getFeature :: Geometry.GeometryType
           -> (Endian.EndianType -> BinaryGet.Get Geometry.WkbGeometryType)
           -> Endian.EndianType
           -> Geometry.CoordinateType
           -> BinaryGet.Get Geospatial.GeospatialGeometry
getFeature :: GeometryType
-> (EndianType -> Get WkbGeometryType)
-> EndianType
-> CoordinateType
-> Get GeospatialGeometry
getFeature GeometryType
geomType EndianType -> Get WkbGeometryType
getWkbGeom =
  case GeometryType
geomType of
    GeometryType
Geometry.Geometry           -> EndianType -> CoordinateType -> Get GeospatialGeometry
getNoGeometry
    GeometryType
Geometry.Point              -> EndianType -> CoordinateType -> Get GeospatialGeometry
Point.getPoint
    GeometryType
Geometry.LineString         -> EndianType -> CoordinateType -> Get GeospatialGeometry
Line.getLine
    GeometryType
Geometry.Polygon            -> EndianType -> CoordinateType -> Get GeospatialGeometry
Polygon.getPolygon
    GeometryType
Geometry.MultiPoint         -> (EndianType -> Get WkbGeometryType)
-> EndianType -> CoordinateType -> Get GeospatialGeometry
Point.getMultiPoint EndianType -> Get WkbGeometryType
getWkbGeom
    GeometryType
Geometry.MultiLineString    -> (EndianType -> Get WkbGeometryType)
-> EndianType -> CoordinateType -> Get GeospatialGeometry
Line.getMultiLine EndianType -> Get WkbGeometryType
getWkbGeom
    GeometryType
Geometry.MultiPolygon       -> (EndianType -> Get WkbGeometryType)
-> EndianType -> CoordinateType -> Get GeospatialGeometry
Polygon.getMultiPolygon EndianType -> Get WkbGeometryType
getWkbGeom
    GeometryType
Geometry.GeometryCollection -> Get GeospatialGeometry
-> EndianType -> CoordinateType -> Get GeospatialGeometry
GeometryCollection.getGeometryCollection ((EndianType -> Get WkbGeometryType) -> Get GeospatialGeometry
getGeospatialGeometry EndianType -> Get WkbGeometryType
getWkbGeom)

getNoGeometry :: Endian.EndianType -> Geometry.CoordinateType -> BinaryGet.Get Geospatial.GeospatialGeometry
getNoGeometry :: EndianType -> CoordinateType -> Get GeospatialGeometry
getNoGeometry EndianType
_ CoordinateType
_ =
  GeospatialGeometry -> Get GeospatialGeometry
forall (f :: * -> *) a. Applicative f => a -> f a
pure GeospatialGeometry
Geospatial.NoGeometry


-- Binary builders

builderGeospatialGeometry :: Geometry.BuilderWkbGeometryType
                          -> Endian.EndianType
                          -> Geospatial.GeospatialGeometry
                          -> ByteStringBuilder.Builder
builderGeospatialGeometry :: BuilderWkbGeometryType
-> EndianType -> GeospatialGeometry -> Builder
builderGeospatialGeometry BuilderWkbGeometryType
builderWkbGeom EndianType
endianType GeospatialGeometry
geospatialGeometry =
  case GeospatialGeometry
geospatialGeometry of
    GeospatialGeometry
Geospatial.NoGeometry                   -> Builder
forall a. Monoid a => a
Monoid.mempty
    Geospatial.Point GeoPoint
geoPoint               -> (BuilderWkbGeometryType -> EndianType -> GeoPoint -> Builder)
-> GeoPoint -> Builder
forall t. (BuilderWkbGeometryType -> EndianType -> t) -> t
build BuilderWkbGeometryType -> EndianType -> GeoPoint -> Builder
Point.builderPoint GeoPoint
geoPoint
    Geospatial.Line GeoLine
geoLine                 -> (BuilderWkbGeometryType -> EndianType -> GeoLine -> Builder)
-> GeoLine -> Builder
forall t. (BuilderWkbGeometryType -> EndianType -> t) -> t
build BuilderWkbGeometryType -> EndianType -> GeoLine -> Builder
Line.builderLine GeoLine
geoLine
    Geospatial.Polygon GeoPolygon
geoPolygon           -> (BuilderWkbGeometryType -> EndianType -> GeoPolygon -> Builder)
-> GeoPolygon -> Builder
forall t. (BuilderWkbGeometryType -> EndianType -> t) -> t
build BuilderWkbGeometryType -> EndianType -> GeoPolygon -> Builder
Polygon.builderPolygon GeoPolygon
geoPolygon
    Geospatial.MultiPoint GeoMultiPoint
geoMultiPoint     -> (BuilderWkbGeometryType -> EndianType -> GeoMultiPoint -> Builder)
-> GeoMultiPoint -> Builder
forall t. (BuilderWkbGeometryType -> EndianType -> t) -> t
build BuilderWkbGeometryType -> EndianType -> GeoMultiPoint -> Builder
Point.builderMultiPoint GeoMultiPoint
geoMultiPoint
    Geospatial.MultiLine GeoMultiLine
geoMultiLine       -> (BuilderWkbGeometryType -> EndianType -> GeoMultiLine -> Builder)
-> GeoMultiLine -> Builder
forall t. (BuilderWkbGeometryType -> EndianType -> t) -> t
build BuilderWkbGeometryType -> EndianType -> GeoMultiLine -> Builder
Line.builderMultiLine GeoMultiLine
geoMultiLine
    Geospatial.MultiPolygon GeoMultiPolygon
geoMultiPolygon -> (BuilderWkbGeometryType
 -> EndianType -> GeoMultiPolygon -> Builder)
-> GeoMultiPolygon -> Builder
forall t. (BuilderWkbGeometryType -> EndianType -> t) -> t
build BuilderWkbGeometryType -> EndianType -> GeoMultiPolygon -> Builder
Polygon.builderMultiPolygon GeoMultiPolygon
geoMultiPolygon
    Geospatial.Collection Seq GeospatialGeometry
geoCollection     -> EndianType -> Seq GeospatialGeometry -> Builder
builderGeometryCollection EndianType
endianType Seq GeospatialGeometry
geoCollection
  where builderGeometryCollection :: EndianType -> Seq GeospatialGeometry -> Builder
builderGeometryCollection =
          (BuilderWkbGeometryType
 -> EndianType -> GeospatialGeometry -> Builder)
-> BuilderWkbGeometryType
-> EndianType
-> Seq GeospatialGeometry
-> Builder
GeometryCollection.builderGeometryCollection BuilderWkbGeometryType
-> EndianType -> GeospatialGeometry -> Builder
builderGeospatialGeometry BuilderWkbGeometryType
builderWkbGeom
        build :: (BuilderWkbGeometryType -> EndianType -> t) -> t
build BuilderWkbGeometryType -> EndianType -> t
builder = BuilderWkbGeometryType -> EndianType -> t
builder BuilderWkbGeometryType
builderWkbGeom EndianType
endianType