summaryrefslogtreecommitdiff
path: root/src/Candidate.hs
blob: e92fd05d117dfb4a8e63cb0871ea1e387b6f4f5a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
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