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