module Geocoder (QueryParameters(..)
,defaultParams
,TokenToGeocode
,GeoCageDeveloperKey
,getAPIResponse
,getAPIResponseWith
,geocode
,geocodeWith
,geocodeGeoTokensList
,createGeocoderParams
,ResponseBody(..)
,Result(..)
,License(..)
,Rate(..)
,Status(..)
,Timestamp(..)
,Components(..)
,Location(..)
,Bounds (..)) where
import qualified Data.Text as T (Text,pack,unpack)
import GHC.Generics (Generic)
import Data.Aeson hiding (Result)
import Control.Applicative ((<$>), (<*>))
import Data.ByteString.Char8 as Bs (ByteString)
import HTTPWrapper
data QueryParameters = QueryParameters {
para_q::T.Text,
para_key::T.Text,
para_language:: Maybe T.Text,
para_pretty::Maybe T.Text,
para_bounds::Maybe T.Text,
para_country::Maybe T.Text,
para_fields::Maybe T.Text
}deriving (Show)
defaultParams :: QueryParameters
defaultParams = QueryParameters {
para_q="",
para_key="",
para_language=Just "en",
para_pretty=Nothing,
para_bounds=Nothing,
para_country=Nothing,
para_fields=Nothing}
type TokenToGeocode = T.Text
type GeoCageDeveloperKey = T.Text
getAPIResponse :: TokenToGeocode
-> GeoCageDeveloperKey
-> IO (Maybe ResponseBody)
getAPIResponse tokenToGeocode developerKey =
getAPIResponseWith parameters
where parameters = defaultParams {para_q= tokenToGeocode,para_key=developerKey}
getAPIResponseWith :: QueryParameters
-> IO (Maybe ResponseBody)
getAPIResponseWith parameters =do
reqSuccesfull <-requestGeocage parameters
case reqSuccesfull of
Left err -> do putStrLn "exception at OpenCage 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 q key lang pre boun cou fields)= [] ++
[("q",T.unpack q),("key",T.unpack key)]
++ toParameter "language" lang
++ toParameter "pretty" pre
++ toParameter "bounds" boun
++ toParameter "country" cou
++ toParameter "fields" fields
where toParameter :: String -> Maybe T.Text -> [(String,String)]
toParameter param mValue = case mValue of
Nothing -> []
Just val -> [(param,T.unpack val)]
geocode :: TokenToGeocode
-> GeoCageDeveloperKey
-> IO [Result]
geocode tokentoGeocode developerKey = geocodeWith params
where params = defaultParams {para_q=tokentoGeocode,para_key=developerKey}
geocodeWith :: QueryParameters
-> IO [Result]
geocodeWith params = do
resp <- getAPIResponseWith params
case resp of
Nothing -> return []
Just r -> return $ results r
geocodeGeoTokensList :: [TokenToGeocode]
-> GeoCageDeveloperKey
-> IO()
geocodeGeoTokensList geoTokens developerKey = do
let geocodeparams = defaultParams {para_key=developerKey,
para_language= Just$ T.pack "en",
para_country = Just $ T.pack "DEU"}
let params = createGeocoderParams geocodeparams geoTokens
res <- mapM geocodeWith params
print res
createGeocoderParams :: QueryParameters
-> [TokenToGeocode]
-> [QueryParameters]
createGeocoderParams params geoTokens = zipWith (\p t -> p {para_q=t})
(replicate (length geoTokens) params)
geoTokens
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
} deriving (Show,Generic)
instance FromJSON Components where
parseJSON (Object v) = Components <$>
(v .:? "country" .!= "") <*>
(v .:? "country_code" .!= "") <*>
(v .:? "county" .!= "") <*>
(v .:? "state" .!= "") <*>
(v .:? "city" .!= "") <*>
(v .:? "road" .!= "")
parseJSON _ = undefined