summaryrefslogtreecommitdiff
path: root/src/Counter.hs
blob: 855b2666c0636ea4ac401f5ac7da0a9dead53419 (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
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