From 1e47a7754ca38bd1a6c74765d8378caf68ce4619 Mon Sep 17 00:00:00 2001 From: Joris Date: Sun, 26 Mar 2017 21:10:42 +0200 Subject: Separate client and server watch --- src/client/Model/Income.elm | 102 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 src/client/Model/Income.elm (limited to 'src/client/Model/Income.elm') diff --git a/src/client/Model/Income.elm b/src/client/Model/Income.elm new file mode 100644 index 0000000..34578c6 --- /dev/null +++ b/src/client/Model/Income.elm @@ -0,0 +1,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 -- cgit v1.2.3