module RevGeocoder (QueryParameters(..)
,defaultParams
,GeoCageDeveloperKey
,GeoCageLatitude
,GeoCageLongitude
,reverseGeocode
,reverseGeocodeWith
,getReverseAPIResponse
,getReverseAPIResponseWith
,ResponseBody(..)
,Result(..)
,License(..)
,Rate(..)
,Status(..)
,Timestamp(..)
,Components(..)
,Location(..)
,Bounds (..)) where
import HTTPWrapper
import qualified Data.Text as T (Text,unpack)
import GHC.Generics (Generic)
import Data.Aeson hiding (Result)
import Data.ByteString.Char8 as Bs (ByteString)
import Control.Applicative ((<$>), (<*>))
data QueryParameters = QueryParameters {
para_latitude::Double,
para_longitude::Double,
para_key::T.Text,
para_language:: Maybe T.Text,
para_pretty::Maybe T.Text,
para_jsonp:: Maybe T.Text
}deriving (Show,Generic)
defaultParams :: QueryParameters
defaultParams = RevGeocoder.QueryParameters {
para_latitude=0
,para_longitude=0
,para_key=""
,para_language=Just "en"
,para_pretty=Nothing
,para_jsonp=Nothing}
type GeoCageDeveloperKey = T.Text
type GeoCageLatitude = Double
type GeoCageLongitude = Double
reverseGeocode :: GeoCageLatitude
-> GeoCageLongitude
-> GeoCageDeveloperKey
-> IO [Result]
reverseGeocode latt long developerKey = reverseGeocodeWith params
where params = defaultParams {para_latitude=latt, para_longitude=long,para_key=developerKey}
reverseGeocodeWith :: QueryParameters
-> IO [Result]
reverseGeocodeWith params = do
r <- getReverseAPIResponseWith params
case r of
Nothing -> return []
Just a -> return $ results a
getReverseAPIResponse :: GeoCageLatitude
-> GeoCageLongitude
-> GeoCageDeveloperKey
-> IO (Maybe ResponseBody)
getReverseAPIResponse latt long developerKey = getReverseAPIResponseWith params
where params = defaultParams {para_latitude=latt, para_longitude=long,para_key=developerKey}
getReverseAPIResponseWith :: QueryParameters
-> IO (Maybe ResponseBody)
getReverseAPIResponseWith parameters =do
reqSuccesfull <-requestGeocage parameters
case reqSuccesfull of
Left err -> do putStrLn "exception at geoCage request, issue:"
print err
return Nothing
Right response -> case eitherDecodeStrict response of
Left exception -> do putStrLn
"exception at ByteString to JSON conversion, issue:"
print exception
return Nothing
Right resultBody -> return $ Just resultBody
where requestGeocage :: QueryParameters -> IO (Either String ByteString)
requestGeocage params = download geocageUrl para
where geocageUrl = "http://api.opencagedata.com/geocode/v1/json?"
para = convertQParamstoOptionsList params
convertQParamstoOptionsList :: QueryParameters
-> [(String,String)]
convertQParamstoOptionsList (QueryParameters para_lat para_long key lang pre jsonp )= [] ++
[("q", show para_lat++","++show para_long),("key",T.unpack key)]
++ toParameter "language" lang
++ toParameter "pretty" pre
++ toParameter "jsonp" jsonp
where toParameter :: String -> Maybe T.Text -> [(String,String)]
toParameter param mValue = case mValue of
Nothing -> []
Just val -> [(param,T.unpack val)]
data ResponseBody = ResponseBody {licenses :: [License],
rate :: Rate,
results :: [Result],
status :: Status,
thanks :: T.Text,
timestamp :: Timestamp,
total_results :: Integer,
we_are_hiring :: T.Text
} deriving (Show,Generic)
instance FromJSON ResponseBody
data License = License {
name :: T.Text,
url :: T.Text
} deriving (Show, Generic)
instance FromJSON License
data Rate = Rate {
limit :: Integer,
remaining::Integer,
reset::Double
} deriving (Show, Generic)
instance FromJSON Rate
data Result = Result {
bounds :: Bounds,
components:: Components,
confidence:: Integer,
formatted:: T.Text ,
geometry:: Location
} deriving (Show,Generic)
instance FromJSON Result where
parseJSON (Object v) = Result <$>
v .: "bounds" <*>
v .: "components"<*>
v .: "confidence"<*>
(v .:? "formatted" .!= "") <*>
v .: "geometry"
parseJSON _ = undefined
data Status = Status {
code::Integer,
message::T.Text
} deriving (Show, Generic)
instance FromJSON Status
data Timestamp = Timestamp {
created_http::T.Text,
created_unix:: Integer
} deriving (Show,Generic)
instance FromJSON Timestamp
data Bounds = Bounds {
northeast:: Location,
southwest::Location
} deriving (Show, Generic)
instance FromJSON Bounds
data Location = Location {
lat::Double,
lng :: Double
} deriving (Show, Generic)
instance FromJSON Location
data Components = Components {
country :: T.Text,
country_code:: T.Text,
county:: T.Text,
state:: T.Text,
city:: T.Text,
road :: T.Text,
clothes :: T.Text
} deriving (Show,Generic)
instance FromJSON Components where
parseJSON (Object v) = Components <$>
(v .:? "country" .!= "") <*>
(v .:? "country_code" .!= "") <*>
(v .:? "county" .!= "") <*>
(v .:? "state" .!= "") <*>
(v .:? "city" .!= "") <*>
(v .:? "road" .!= "") <*>
(v .:? "clothes" .!= "")
parseJSON _ = undefined