module Model.Income ( Incomes , Income , IncomeId , incomesDecoder , incomeIdDecoder , incomeDefinedForAll , userCumulativeIncomeSince , cumulativeIncomesSince ) where import Json.Decode as Json exposing ((:=)) 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 exposing (isJust, catMaybes, maybeToList) type alias Incomes = Dict IncomeId Income type alias IncomeId = Int type alias Income = { userId : UserId , creation : Time , amount : Int } incomesDecoder : Json.Decoder Incomes incomesDecoder = Json.map Dict.fromList (Json.list incomeWithIdDecoder) incomeWithIdDecoder : Json.Decoder (IncomeId, Income) incomeWithIdDecoder = Json.object2 (,) ("id" := incomeIdDecoder) incomeDecoder incomeIdDecoder : Json.Decoder IncomeId incomeIdDecoder = Json.int incomeDecoder : Json.Decoder Income incomeDecoder = Json.object3 Income ("userId" := userIdDecoder) ("creation" := timeDecoder) ("amount" := Json.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 .creation) userIncomes in if all isJust firstIncomes then head << reverse << List.sort << map .creation << catMaybes <| 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.creation >= time) incomes in (maybeToList mbStarterIncome) ++ orderedIncomesSince getIncomeAt : Time -> List Income -> Maybe Income getIncomeAt time incomes = case incomes of [x] -> if x.creation < time then Just { userId = x.userId, creation = time, amount = x.amount } else Nothing x1 :: x2 :: xs -> if x1.creation < time && x2.creation > time then Just { userId = x2.userId, creation = time, amount = x2.amount } else getIncomeAt time (x2 :: xs) [] -> Nothing cumulativeIncome : Time -> List Income -> Int cumulativeIncome currentTime incomes = getIncomesWithDuration currentTime (List.sortBy .creation incomes) |> map durationIncome |> sum getIncomesWithDuration : Time -> List Income -> List (Float, Int) getIncomesWithDuration currentTime incomes = case incomes of [] -> [] [income] -> [(currentTime - income.creation, income.amount)] (income1 :: income2 :: xs) -> (income2.creation - income1.creation, income1.amount) :: (getIncomesWithDuration currentTime (income2 :: xs)) durationIncome : (Float, Int) -> Int durationIncome (duration, income) = duration * toFloat income / (hour * 24 * 365 / 12) |> truncate