{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell   #-}
module Data.Geospatial.Internal.CRS (
    
        CRSObject(..)
    
    ,   defaultCRS
    
    ,   _NoCRS
    ,   _NamedCRS
    ,   _EPSG
    ,   _LinkedCRS
    ) where
import           Data.Geospatial.Internal.BasicTypes
import           Control.Applicative                 ((<$>), (<*>))
import           Control.Lens                        (makePrisms)
import           Control.Monad                       (mzero)
import           Data.Aeson                          (FromJSON (..), Object,
                                                      ToJSON (..), Value (..),
                                                      object, (.:), (.=))
import           Data.Aeson.Types                    (Parser)
import           Data.Text                           (Text)
data CRSObject =
        NoCRS
    |   NamedCRS !Name
    |   EPSG Code
    |   LinkedCRS !Href !FormatString  deriving (Show, Eq)
makePrisms ''CRSObject
defaultCRS :: CRSObject
defaultCRS = EPSG 4326
instance FromJSON CRSObject where
    parseJSON Null = return NoCRS
    parseJSON (Object obj) = do
        crsType <- obj .: "type"
        crsObjectFromAeson crsType obj
    parseJSON _ = mzero
instance ToJSON CRSObject where
    toJSON (NamedCRS name)          = object ["type" .= ("name" :: Text), "properties" .= object ["name" .= name]]
    toJSON (EPSG code)              = object ["type" .= ("epsg" :: Text), "properties" .= object ["code" .= code]]
    toJSON (LinkedCRS href format)  = object ["type" .= ("link" :: Text), "properties" .= object ["href" .= href, "type" .= format]]
    toJSON NoCRS                    = Null
crsPropertyFromAesonObj :: (FromJSON a) => Text -> Object -> Parser a
crsPropertyFromAesonObj name obj = do
    props <- obj .: "properties"
    props .: name
crsObjectFromAeson :: Text -> Object -> Parser CRSObject
crsObjectFromAeson "name" obj   = NamedCRS <$> crsPropertyFromAesonObj "name" obj
crsObjectFromAeson "epsg" obj   = EPSG <$> crsPropertyFromAesonObj "code" obj
crsObjectFromAeson "link" obj   = LinkedCRS <$> crsPropertyFromAesonObj "href" obj <*> crsPropertyFromAesonObj "type" obj
crsObjectFromAeson _ _          = mzero