module Longest where

import Control.Monad
import Control.Monad.Error
import Control.Monad.State
import Data.List
import System.Directory
import System.Environment
import System.Exit
import System.IO

getLength :: String -> ErrorT String IO Int

getLength filename =
    do exists <- lift $ doesFileExist filename
       unless exists (throwError (filename ++ " does not exist"))
       contents <- lift $ readFile filename
       return $ length (lines contents)

updateBestWith :: (String, Int) -> StateT (String, Int) IO ()

updateBestWith (currentName, currentCount) =
    do (bestName, bestCount) <- get
       when (currentCount > bestCount) (put (currentName, currentCount))

printError :: String -> IO a

printError message =
    do programName <- getProgName
       hPutStrLn stderr (programName ++ ": " ++ message)
       exitFailure

handleError :: ErrorT String IO a -> IO a

handleError action =
    do result <- runErrorT action
       either printError return result

doNext :: String -> StateT (String, Int) IO ()

doNext filename =
    do count <- lift $ handleError (getLength filename)
       updateBestWith (filename, count)

longestFile :: [String] -> IO (String, Int)

longestFile filenames =
    execStateT (mapM_ doNext filenames) ("none", 0)

processArgs :: [String] -> IO ()

processArgs [] =
    printError "must supply filenames as arguments"

processArgs filenames =
    do (filename, count) <- longestFile filenames
       putStrLn ("Longest file is " ++ filename ++ 
                 " which is " ++ show count ++ " lines long")    

main :: IO ()

main = getArgs >>= processArgs
