aboutsummaryrefslogtreecommitdiff
path: root/src/client/Model/Income.elm
blob: 34578c6bcc8de1649515e11edd7080f2ba30bbdf (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
102
module Model.Income exposing
  ( Incomes
  , Income
  , IncomeId
  , incomesDecoder
  , incomeIdDecoder
  , incomeDefinedForAll
  , userCumulativeIncomeSince
  , cumulativeIncomesSince
  )

import Json.Decode as Decode exposing (Decoder)
import Utils.Json as Json
import Time exposing (Time, hour)
import List exposing (..)
import Dict exposing (Dict)

import Model.Date exposing (timeDecoder)
import Model.User exposing (UserId, userIdDecoder)

import Utils.Maybe as Maybe

type alias Incomes = Dict IncomeId Income

type alias IncomeId = Int

type alias Income =
  { userId : UserId
  , time : Float
  , amount : Int
  }

incomesDecoder : Decoder Incomes
incomesDecoder =
  Json.dictDecoder (Decode.field "id" incomeIdDecoder) <|
    Decode.map3 Income
      (Decode.field "userId" userIdDecoder)
      (Decode.field "date" timeDecoder)
      (Decode.field "amount" Decode.int)

incomeIdDecoder : Decoder IncomeId
incomeIdDecoder = Decode.int

incomeDefinedForAll : List UserId -> Incomes -> Maybe Time
incomeDefinedForAll userIds incomes =
  let userIncomes = List.map (\userId -> List.filter ((==) userId << .userId) << Dict.values <| incomes) userIds
      firstIncomes = map (head << sortBy .time) userIncomes
  in  if all Maybe.isJust firstIncomes
        then head << reverse << List.sort << map .time << Maybe.cat <| firstIncomes
        else Nothing

userCumulativeIncomeSince : Time -> Time -> Incomes -> UserId -> Int
userCumulativeIncomeSince currentTime since incomes userId =
  incomes
    |> Dict.values
    |> List.filter (\income -> income.userId == userId)
    |> cumulativeIncomesSince currentTime since

cumulativeIncomesSince : Time -> Time -> (List Income) -> Int
cumulativeIncomesSince currentTime since incomes =
  cumulativeIncome currentTime (getOrderedIncomesSince since incomes)

getOrderedIncomesSince : Time -> List Income -> List Income
getOrderedIncomesSince time incomes =
  let mbStarterIncome = getIncomeAt time incomes
      orderedIncomesSince = filter (\income -> income.time >= time) incomes
  in  (Maybe.toList mbStarterIncome) ++ orderedIncomesSince

getIncomeAt : Time -> List Income -> Maybe Income
getIncomeAt time incomes =
  case incomes of
    [x] ->
      if x.time < time
        then Just { userId = x.userId, time = time, amount = x.amount }
        else Nothing
    x1 :: x2 :: xs ->
      if x1.time < time && x2.time >= time
        then Just { userId = x1.userId, time = time, amount = x1.amount }
        else getIncomeAt time (x2 :: xs)
    [] ->
      Nothing

cumulativeIncome : Time -> List Income -> Int
cumulativeIncome currentTime incomes =
  getIncomesWithDuration currentTime (List.sortBy .time incomes)
    |> map durationIncome
    |> sum

getIncomesWithDuration : Time -> List Income -> List (Float, Int)
getIncomesWithDuration currentTime incomes =
  case incomes of
    [] ->
      []
    [income] ->
      [(currentTime - income.time, income.amount)]
    (income1 :: income2 :: xs) ->
      (income2.time - income1.time, income1.amount) :: (getIncomesWithDuration currentTime (income2 :: xs))

durationIncome : (Float, Int) -> Int
durationIncome (duration, income) =
  duration * toFloat income / (hour * 24 * 365 / 12)
    |> truncate