{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeOperators #-} module Main where import Control.Monad (liftM2) import Control.Monad.IO.Class (liftIO) import Data.Aeson (ToJSON (..)) import qualified Data.Map as Map (fromList, lookup) import Data.Maybe (fromMaybe) import Data.Text (Text) import GHC.Generics (Generic) import Network.HTTP.Client (Manager) import Network.HTTP.Client.TLS (newTlsManager) import Network.Wai.Handler.Warp (runEnv) import Onomap.Stoepel import Onomap.Svg (renderMap) import Onomap.Types import Servant import Servant.HTML.Blaze (HTML) import Text.Blaze (ToMarkup (..)) data Response = Response {color :: [Text], areas :: [Area], statistics :: [(Text, ByArea Double)], svgSettings :: SvgSettings} deriving (Generic) instance ToMarkup Response where toMarkup response = preEscapedToMarkup $ renderMap (svgSettings response) (color response) (areas response) (statistics response) instance ToJSON Response where toJSON response = toJSON $ Map.fromList $ map ( \area -> ( name area , Map.fromList $ ("population", toJSON $ population area) : map ( \(surname, stats) -> ( surname , toJSON $ Map.lookup (key area) (getByArea stats) ) ) (statistics response) ) ) (areas response) type OnomapApi = Capture "mode" Mode :> QueryParams "name" Text :> QueryParam "by" AreaKind :> QueryParams "color" Text :> QueryParam "scale" ScaleToMaximum :> Get '[HTML] Response app :: Manager -> ([Area], [Area]) -> Application app manager' (theDistricts, theStates) = serve onomapApi server where server :: Server OnomapApi server = \mode (surnames :: [Text]) maybeAreaKind colors scaleTo -> liftIO $ runStoepel manager' $ do let areaMode = fromMaybe District maybeAreaKind computeFunction = case mode of Relative -> relativeCount Absolute -> absoluteCount theAreas = case areaMode of State -> theStates District -> theDistricts theNames = map Just surnames theStats <- case areaMode of State -> mapM stateStatistics theNames District -> mapM districtStatistics theNames let stats = map (computeAreaStatistics computeFunction theAreas) theStats return Response { color = colors ++ defaultColorPalette , areas = theAreas , svgSettings = SvgSettings{scaleToMaximum = fromMaybe Global scaleTo} , statistics = zip surnames stats } onomapApi :: Proxy OnomapApi onomapApi = Proxy main :: IO () main = do manager' <- newTlsManager runEnv 8081 . app manager' =<< runStoepel manager' (liftM2 (,) districts states)