module Main where import Text.ParserCombinators.Parsec import System.Environment import System.Process import System.Exit import System.IO data Config = Config { weatherNormal :: Integer , weatherNormalColor :: String , weatherCritical :: Integer , weatherCriticalColor :: String } defaultConfig :: Config defaultConfig = Config { weatherNormal = 0 , weatherNormalColor = "#00FF00" , weatherCritical = 50 , weatherCriticalColor = "#FF0000" } config :: Config config = defaultConfig data WeatherInfo = Fail String | WI { station :: String , time :: String , temperature :: Int , humidity :: Int } instance Show WeatherInfo where show (Fail _) = "N/A" show (WI st t temp rh) = st ++ ": " ++ (formatWeather temp) ++ "C, rh " ++ formatWeather rh ++ "% (" ++ t ++ ")" parseData :: Parser WeatherInfo parseData = do { st <- manyTill anyChar $ char '(' ; pNL ; manyTill anyChar $ char '/' ; space ; t <- manyTill anyChar newline ; manyTill pNL (string "Temperature") ; temp <- pTemp ; manyTill pNL (string "Relative Humidity") ; rh <- pRh ; manyTill pNL eof ; return $ WI st t temp rh } pTemp :: Parser Int pTemp = do string ": " manyTill anyChar $ char '(' s <- manyTill digit $ (char ' ' <|> char '.') pNL return $read s pRh :: Parser Int pRh = do string ": " s <- manyTill digit $ (char '%' <|> char '.') return $read s pNL :: Parser Char pNL = do many $ noneOf "\n\r" newline runP :: Parser WeatherInfo -> String -> IO WeatherInfo runP p i = do case (parse p "" i) of Left err -> return $ Fail $ show err Right x -> return x formatWeather :: Int -> String formatWeather d | d > fromInteger (weatherCritical config) = setColor str weatherCriticalColor | d > fromInteger (weatherNormal config) = setColor str weatherNormalColor | otherwise = str where str = show d setColor :: String -> (Config -> String) -> String setColor str ty = "" ++ str ++ "" defUrl :: String defUrl = "http://weather.noaa.gov/pub/data/observations/metar/decoded/" getData :: String -> IO String getData url= do (i,o,e,p) <- runInteractiveCommand ("curl " ++ defUrl ++ url ++ ".TXT") exit <- waitForProcess p let closeHandles = do hClose o hClose i hClose e case exit of ExitSuccess -> do str <- hGetContents o return str _ -> do closeHandles return "Could not retrieve data" main :: IO () main = do args <- getArgs str <- if length args /= 1 then error $ "No Station ID specified.\nUsage: weather STATION_ID" ++ "\nExample: xmb-weather LIPB" else getData (args !! 0) i <- runP parseData str putStrLn $ show i