580f2275c4294538812a60414b49752b705886dc
[Sone.git] / src / main / kotlin / net / pterodactylus / sone / core / UpdatedSoneProcessor.kt
1 package net.pterodactylus.sone.core
2
3 import com.google.common.eventbus.EventBus
4 import com.google.inject.ImplementedBy
5 import net.pterodactylus.sone.core.event.NewPostFoundEvent
6 import net.pterodactylus.sone.core.event.NewPostReplyFoundEvent
7 import net.pterodactylus.sone.core.event.PostRemovedEvent
8 import net.pterodactylus.sone.core.event.PostReplyRemovedEvent
9 import net.pterodactylus.sone.data.Sone
10 import net.pterodactylus.sone.data.Sone.SoneStatus
11 import net.pterodactylus.sone.database.Database
12 import net.pterodactylus.sone.utils.ifFalse
13 import net.pterodactylus.util.logging.Logging
14 import javax.inject.Inject
15
16 /**
17  * An `UpdatedSoneProcessor` is called to process a [Sone] after it has been
18  * downloaded from Freenet.
19  */
20 @ImplementedBy(DefaultUpdateSoneProcessor::class)
21 interface UpdatedSoneProcessor {
22
23         fun updateSone(sone: Sone)
24
25 }
26
27 abstract class BasicUpdateSoneProcessor(private val database: Database, private val eventBus: EventBus) :
28                 UpdatedSoneProcessor {
29
30         private val logger = Logging.getLogger(UpdatedSoneProcessor::javaClass.name)!!
31
32         override fun updateSone(sone: Sone) {
33                 val storedSone = database.getSone(sone.id) ?: return
34                 if (!soneCanBeUpdated(storedSone, sone)) {
35                         logger.fine("Downloaded Sone $sone can not update stored Sone $storedSone.")
36                         return
37                 }
38                 collectEventsForChanges(storedSone, sone)
39                                 .also { database.storeSone(sone) }
40                                 .forEach(eventBus::post)
41                 sone.options = storedSone.options
42                 sone.isKnown = storedSone.isKnown
43                 sone.status = if (sone.time != 0L) SoneStatus.idle else SoneStatus.unknown
44         }
45
46         protected abstract fun soneCanBeUpdated(storedSone: Sone, newSone: Sone): Boolean
47
48         private val Sone.followingTime get() = database.getFollowingTime(id) ?: 0
49
50         private fun collectEventsForChanges(oldSone: Sone, newSone: Sone): List<Any> =
51                         SoneChangeCollector(oldSone)
52                                         .onNewPost { post -> if (post.time <= newSone.followingTime) post.isKnown = true }
53                                         .newPostEvent { post -> post.isKnown.ifFalse { NewPostFoundEvent(post) } }
54                                         .removedPostEvent { PostRemovedEvent(it) }
55                                         .onNewPostReply { postReply -> if (postReply.time <= newSone.followingTime) postReply.isKnown = true }
56                                         .newPostReplyEvent { postReply -> postReply.isKnown.ifFalse { NewPostReplyFoundEvent(postReply) } }
57                                         .onRemovedPostReply { PostReplyRemovedEvent(it) }
58                                         .detectChanges(newSone)
59
60 }
61
62 class DefaultUpdateSoneProcessor @Inject constructor(database: Database, eventBus: EventBus) :
63                 BasicUpdateSoneProcessor(database, eventBus) {
64
65         override fun soneCanBeUpdated(storedSone: Sone, newSone: Sone) =
66                         newSone.time > storedSone.time
67
68 }