module Counter( SenateCounter, createSenateCounter, doCount, getBallot, getTotal ) where import qualified Candidate as Typ import qualified Preferences as Pref import qualified Criteria as Crit import qualified CSV as CSV import qualified Storage as Vec import qualified System.IO as IO import qualified File as File import qualified Control.Monad as Con import qualified Data.Either.Unwrap as Either import qualified Data.Maybe as Maybe import qualified Data.List as List data SenateCounter = SenateCounter { prefData :: Vec.Store , ballotMap :: Typ.BelowLineBallot , numBallots :: Int } createSenateCounter :: FilePath -> Typ.AboveLineBallot -> Typ.BelowLineBallot -> IO SenateCounter createSenateCounter f a b = do numLines <- File.countLines f prefStore <- Vec.createStore numLines (length b) h <- IO.openFile f IO.ReadMode let readFunc n p = if (n > numLines) then return p else do t0 <- IO.hGetLine h let prefs = parseRawLine a b t0 result = Maybe.fromJust prefs if (Maybe.isJust prefs) then Vec.setPrefs prefStore n result >> readFunc (n + 1) (p + 1) else readFunc (n + 1) p p <- readFunc 1 0 IO.hClose h return (SenateCounter prefStore b p) parseRawLine :: Typ.AboveLineBallot -> Typ.BelowLineBallot -> String -> Maybe [Pref.Preference] parseRawLine a b input = let t1 = CSV.parseRecord CSV.defaultSettings (input ++ "\n") t2 = Maybe.listToMaybe . reverse . Either.fromRight $ t1 t3 = Pref.parsePreferences (length a) (length b) (Maybe.fromJust t2) t4 = Pref.normalise a b (Either.fromRight t3) in if (Either.isRight t1 && Maybe.isJust t2 && Either.isRight t3) then t4 else Nothing doCount :: SenateCounter -> Crit.Criteria -> IO Int doCount sen criteria = let tailFunc n r = if (n > numBallots sen) then return r else do prefs <- Vec.getPrefs (prefData sen) n if (Crit.evaluate (ballotMap sen) prefs criteria) then tailFunc (n + 1) (r + 1) else tailFunc (n + 1) r in tailFunc 1 0 getBallot :: SenateCounter -> Typ.BelowLineBallot getBallot = ballotMap getTotal :: SenateCounter -> Int getTotal = numBallots