· 5 years ago · May 28, 2020, 06:14 AM
1package com.flexsentlabs.tip.timeline.gateway
2
3import com.flexsentlabs.tip.timeline.api.TimelineApi
4import com.flexsentlabs.tip.timeline.domain.TimelineEvent
5import com.flexsentlabs.tip.timeline.domain.TimelineEventWithParticipants
6import com.flexsentlabs.tip.timeline.domain.TimelineUser
7import com.flexsentlabs.tip.user.api.User
8import com.flexsentlabs.tip.user.api.UserApi
9import io.reactivex.Completable
10import io.reactivex.Single
11
12class TimelineGateway(
13 private val timelineApi: TimelineApi,
14 private val userApi: UserApi
15) {
16
17 fun getTimelineEventsForLastDay(): Single<List<TimelineEventWithParticipants>> {
18 return mergeTimelineEventsWithParticipants(
19 timelineApi.getTimelineForLastDay()
20 .map { response -> response.timeLine }
21 )
22 }
23
24 fun getTimelineForLast2Days(): Single<List<TimelineEventWithParticipants>> {
25 return mergeTimelineEventsWithParticipants(
26 timelineApi.getTimelineForDays(2)
27 .map { response -> response.timeLine }
28 )
29 }
30
31 private fun mergeTimelineEventsWithParticipants(input: Single<List<TimelineEvent>>):
32 Single<List<TimelineEventWithParticipants>> {
33 /**
34 * The main problem is that API treats TimelineEvent as an event which has owner
35 * and participants. So for 1 owner and 5 participants there will be 5 timeline events.
36 * That's why we need to pick all events first, get each participant [User] and
37 * combine to [TimelineEventWithParticipants]
38 */
39 return Single.create { singleEmitter ->
40 val combineAllParticipants: HashMap<Pair<Int, String>, MutableList<TimelineUser>> =
41 HashMap()
42 var timelineEvents: List<TimelineEvent>? = null
43
44 input
45 .map {
46 timelineEvents = it // remember timeline events
47 it
48 }
49 .flattenAsObservable { it }
50 .flatMapCompletable { timelineEvent ->
51 Completable.create { completableEmitter ->
52 // Create a key which represent a timeline event for owner
53 val key = Pair(
54 timelineEvent.ownerId,
55 timelineEvent.startTime
56 )
57
58 userApi.getUserById(timelineEvent.participantId)
59 .map { participant ->
60 TimelineUser(
61 participant.id,
62 participant.firstName ?: "",
63 participant.lastName ?: "",
64 participant.businessProfile?.profession
65 ?: "N/A",
66 participant.avatarLink ?: "", // TODO: default avatar
67 participant.businessProfile != null,
68 // thanks - 1 point, tip - 2 points
69 participant.reputation.thanksReceived +
70 participant.reputation.tipsReceived * 2
71 )
72 }
73 .subscribe(
74 { timelineUser ->
75 // add participant to what we treat as a timeline event
76 if (combineAllParticipants.containsKey(key)) {
77 combineAllParticipants[key]?.add(timelineUser)
78 } else {
79 combineAllParticipants[key] = mutableListOf(timelineUser)
80 }
81 completableEmitter.onComplete()
82 },
83 // Escalate any errors which appear while fetching participant [User] data
84 { completableEmitter.onError(it) }
85 )
86 }
87 }
88 .subscribe(
89 {
90 singleEmitter.onSuccess(
91 // Flatten the map to the list of unique items
92 combineAllParticipants.entries.mapNotNull { entry ->
93 timelineEvents?.find { it.ownerId == entry.key.first }?.let {
94 TimelineEventWithParticipants(
95 it,
96 entry.value.toList()
97 )
98 }
99 }
100 )
101 },
102 // Pass errors of getting the timeline events
103 { singleEmitter.onError(it) }
104 )
105 }
106 }
107}