module Model.Income ( Income , incomeDecoder , incomeDefinedForAll , cumulativeIncomesSince ) where import Json.Decode as Json exposing ((:=)) import Time exposing (Time, hour) import List exposing (..) import Model.Date exposing (timeDecoder) import Model.User exposing (UserId) import Utils.Maybe exposing (isJust, catMaybes, maybeToList) type alias Income = { creation : Time , amount : Int } incomeDecoder : Json.Decoder Income incomeDecoder = Json.object2 Income ("creation" := timeDecoder) ("amount" := Json.int) incomeDefinedForAll : List (List Income) -> Maybe Time incomeDefinedForAll usersIncomes = let firstIncomes = map (head << sortBy .creation) usersIncomes in if all isJust firstIncomes then head << reverse << List.sort << map .creation << catMaybes <| firstIncomes else Nothing 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 = getIncomesAt time incomes orderedIncomesSince = filter (\income -> income.creation >= time) incomes in (maybeToList mbStarterIncome) ++ orderedIncomesSince getIncomesAt : Time -> List Income -> Maybe Income getIncomesAt time incomes = case incomes of [x] -> if x.creation < time then Just { creation = time, amount = x.amount } else Nothing x1 :: x2 :: xs -> if x1.creation < time && x2.creation > time then Just { creation = time, amount = x2.amount } else getIncomesAt time (x2 :: xs) [] -> Nothing cumulativeIncome : Time -> List Income -> Int cumulativeIncome currentTime incomes = getIncomesWithDuration (incomes ++ [{ creation = currentTime, amount = 0 }]) |> map durationIncome |> sum getIncomesWithDuration : List Income -> List (Float, Int) getIncomesWithDuration incomes = case incomes of (income1 :: income2 :: xs) -> (income2.creation - income1.creation, income1.amount) :: (getIncomesWithDuration (income2 :: xs)) _ -> [] durationIncome : (Float, Int) -> Int durationIncome (duration, income) = duration * toFloat income / (hour * 24 * 365 / 12) |> truncate