{-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE QuasiQuotes #-} module Main ( main ) where import Control.Arrow ((&&&)) import Control.Monad (when) import Data.Version (showVersion) import GHC.Generics (Generic) import System.Environment (getArgs) import System.Exit (die) import Data.Aeson (FromJSON, eitherDecode, encode) import qualified Data.ByteString.Lazy as L import qualified Data.HashMap.Strict as HM import qualified System.Console.Docopt.NoTH as O import Text.InterpolatedString.Perl6 (qc) import Malodivo.Budget (manyToOne) import Malodivo.Types.Bill (Bill) import Malodivo.Types.District (District) import Paths_malodivo (version) -- from cabal usage :: String usage = "malodivo " ++ showVersion version ++ " - budget planning tool for the Kingdom of Malodivo" ++ [qc| This utility reads input JSON data from standard input and writes output JSON data to standard output. Usage: malodivo [options] < input.json > output.json Options: -h, --help Show this message and exit |] data DistrictInfo = DistrictInfo { name :: District , availableFunds :: Integer } deriving (Generic, FromJSON) data SimpleInput = SimpleInput { bills :: [Bill] , districts :: [DistrictInfo] } deriving (Generic, FromJSON) process :: IO () process = do input <- L.getContents case eitherDecode input of Left err -> die err Right si -> do let nbills = length . bills $ si funds = HM.fromListWith (+) . map (name &&& availableFunds) $ districts si when (nbills /= 1) $ die "We needs exactly one bill in input" when (HM.null funds) $ die "We needs at least one district" L.putStr . encode $ manyToOne funds (head . bills $ si) main :: IO () main = do doco <- O.parseUsageOrExit usage args <- O.parseArgsOrExit doco =<< getArgs if args `O.isPresent` O.longOption "help" then putStrLn $ O.usage doco else process