module Data.Locations.Postcodes (getPostcode, getPostcodesInRange, getPostcodeAtLocation, Postcode(..)) where
import Control.Applicative ((<$>), (<*>), pure)
import Data.Aeson
import qualified Data.ByteString.Lazy.Char8 as BL
import Data.Char (toUpper)
import Network.HTTP
data Postcode = Postcode {_postcode :: String,
_latitude :: Float,
_longitude :: Float,
_constituency :: Maybe String,
_district :: Maybe String}
deriving (Show, Eq)
instance FromJSON Postcode where
parseJSON (Object v) = Postcode <$> v .: "postcode"
<*> (read <$> getInP "lat" geo)
<*> (read <$> getInP "lng" geo)
<*> (Just <$> (getInP "title" . getInP "constituency" $ admin))
<*> (Just <$> (getInP "title" . getInP "district" $ admin))
where geo = v .: "geo"
admin = v .: "administrative"
getInP k p = flip (.:) k =<< p
instance FromJSON (Float, Postcode) where
parseJSON (Object v) = (,) <$> (read <$> v .: "distance")
<*> (Postcode <$> v .: "postcode"
<*> (read <$> v.: "lat")
<*> (read <$> v.: "lng")
<*> pure Nothing <*> pure Nothing)
baseURL :: String
baseURL = "http://uk-postcodes.com"
getPostcode :: String
-> IO (Maybe Postcode)
getPostcode pc = postcodeRequest ("/postcode/" ++ sanatisePostcode pc ++ ".json")
getPostcodesInRange :: String
-> Float
-> IO (Maybe [(Float, Postcode)])
getPostcodesInRange pc range = postcodeRequest ("/distance.php?postcode=" ++ sanatisePostcode pc ++ "&distance=" ++ show range ++ "&format=json")
getPostcodeAtLocation :: Float
-> Float
-> IO (Maybe Postcode)
getPostcodeAtLocation lat lng = postcodeRequest ("/latlng/" ++ show lat ++ "," ++ show lng ++ ".json")
postcodeRequest :: FromJSON a => String -> IO (Maybe a)
postcodeRequest url = do
response <- getResponseBody =<< simpleHTTP (getRequest $ baseURL ++ url)
return (decode $ BL.pack response)
sanatisePostcode :: String -> String
sanatisePostcode = removeSpace . map toUpper
removeSpace :: String -> String
removeSpace = filter (/= ' ')