module Candidate( Ranking, Position, CandidateID, AboveLineBallot, BelowLineBallot, readCandidates ) where -- This source is licensed under Creative Commons CC0 v1.0. -- To read the full text, see license.txt in the main directory of this repository -- or go to https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt -- For a human readable summary, go to https://creativecommons.org/publicdomain/zero/1.0/ import qualified CSV as CSV import qualified Miscellaneous as Misc import qualified System.IO as IO import qualified Data.List as List import qualified Data.Either.Unwrap as Either import qualified Data.Maybe as Maybe type Ranking = Int type Position = Int type CandidateID = String -- positions in the uppermap list correspond to the boxes above the line, -- and the lists of candidateIDs are the boxes below the line type AboveLineBallot = [[Position]] -- a list of candidates in the order of how they were placed below the line type BelowLineBallot = [CandidateID] readCandidates :: FilePath -> String -> IO (AboveLineBallot, BelowLineBallot) readCandidates inputFile state = do h <- IO.openFile inputFile IO.ReadMode e <- IO.hIsEOF h let readFunc r c = if c then return r else do t0 <- IO.hGetLine h let t1 = CSV.parseRecord CSV.defaultSettings t0 t2 = Misc.selectFrom [5,6,7,8,9] [(2,"S"),(3,state)] (Either.fromRight t1) t3 = Maybe.fromJust t2 tx <- IO.hIsEOF h if (Either.isRight t1) && (Maybe.isJust t2) then readFunc (t3:r) tx else readFunc r tx raw <- readFunc [] e >>= return . (List.sortBy candRecComp) IO.hClose h return (makeAboveBallot raw, makeBelowBallot raw) -- assumes there are at least two items in each list -- see the above function for the things it gets applied on for why candRecComp :: [String] -> [String] -> Ordering candRecComp a b = let lenResult = compare (length (head a)) (length (head b)) in if (lenResult == EQ) then compare (take 2 a) (take 2 b) else lenResult -- very hacky, pls revise makeAboveBallot :: [[String]] -> AboveLineBallot makeAboveBallot input = let comp x y = (head x) == (head y) grouped = List.groupBy comp (filter ((/= "UG") . head) input) numFunc n r t = if (t == []) then r else numFunc (n + (length (head t))) (r ++ [(map fst (zip [n, n+1 ..] (head t)))]) (tail t) in numFunc (fromIntegral 1) [] grouped makeBelowBallot :: [[String]] -> BelowLineBallot makeBelowBallot input = let f (_:_:c:d:e:[]) = d ++ " " ++ c ++ ", " ++ e in map f input