🔀 Merge “release/v81” into “master”
[Sone.git] / src / main / kotlin / net / pterodactylus / sone / notify / ListNotification.kt
1 /*
2  * Sone - ListNotification.kt - Copyright Â© 2010–2020 David Roden
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 package net.pterodactylus.sone.notify
19
20 import net.pterodactylus.util.notify.*
21 import net.pterodactylus.util.template.*
22 import java.lang.System.*
23 import java.util.concurrent.*
24
25 /**
26  * Notification that maintains a list of elements.
27  *
28  * @param <T>
29  * The type of the items
30  */
31 class ListNotification<T> : TemplateNotification {
32
33         private val key: String
34         private val realElements = CopyOnWriteArrayList<T>()
35
36         val elements: List<T> get() = realElements.toList()
37
38         val isEmpty
39                 get() = elements.isEmpty()
40
41         @JvmOverloads
42         constructor(id: String, key: String, template: Template, dismissable: Boolean = true) : super(id, currentTimeMillis(), currentTimeMillis(), dismissable, template) {
43                 this.key = key
44                 template.initialContext.set(key, realElements)
45         }
46
47         constructor(listNotification: ListNotification<T>) : super(listNotification.id, listNotification.createdTime, listNotification.lastUpdatedTime, listNotification.isDismissable, Template()) {
48                 this.key = listNotification.key
49                 template.add(listNotification.template)
50                 template.initialContext.set(key, realElements)
51         }
52
53         fun setElements(elements: Collection<T>) {
54                 realElements.clear()
55                 realElements.addAll(elements.distinct())
56                 touch()
57         }
58
59         fun add(element: T) {
60                 if (element !in realElements) {
61                         realElements.add(element)
62                         touch()
63                 }
64         }
65
66         fun remove(element: T) {
67                 while (realElements.remove(element)) {
68                         /* do nothing, just remove all instances of the element. */
69                 }
70                 if (realElements.isEmpty()) {
71                         dismiss()
72                 }
73                 touch()
74         }
75
76         override fun dismiss() {
77                 super.dismiss()
78                 realElements.clear()
79         }
80
81         override fun hashCode() =
82                         realElements.fold(super.hashCode()) { hash, element -> hash xor element.hashCode() }
83
84         override fun equals(other: Any?): Boolean {
85                 if (other !is ListNotification<*>) {
86                         return false
87                 }
88                 val listNotification = other as ListNotification<*>?
89                 if (!super.equals(listNotification)) {
90                         return false
91                 }
92                 return (key == listNotification.key) && (realElements == listNotification.realElements)
93         }
94
95 }