summaryrefslogtreecommitdiff
path: root/src/main/kotlin/io/dico/parcels2/Privilege.kt
blob: 135d7c1edbe428bcc387b8f617689eccd7ecd8aa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package io.dico.parcels2

import io.dico.parcels2.Privilege.DEFAULT
import java.util.Collections

typealias PrivilegeKey = PlayerProfile.Real
typealias PrivilegeMap = Map<PrivilegeKey, Privilege>
typealias MutablePrivilegeMap = MutableMap<PrivilegeKey, Privilege>

@Suppress("FunctionName")
fun MutablePrivilegeMap(): MutablePrivilegeMap = hashMapOf()

@Suppress("UNCHECKED_CAST")
val EmptyPrivilegeMap = Collections.emptyMap<Any, Any>() as MutablePrivilegeMap

enum class Privilege(
    val number: Int,
    val transient: Boolean = false
) {
    BANNED(1),
    DEFAULT(2),
    CAN_BUILD(3),
    CAN_MANAGE(4),

    OWNER(-1, transient = true),
    ADMIN(-1, transient = true);

    fun implies(other: Privilege): Boolean =
        when {
            other > DEFAULT -> this >= other
            other == DEFAULT -> this == other
            else -> this <= other
        }

    fun isChangeInDirection(positiveDirection: Boolean, update: Privilege): Boolean =
        if (positiveDirection) update > this
        else update < this

    fun requireNonTransient(): Privilege {
        if (transient) {
            throw IllegalArgumentException("Transient privilege $this is invalid")
        }
        return this
    }

    companion object {
        fun getByNumber(id: Int) =
            when (id) {
                1 -> BANNED
                2 -> DEFAULT
                3 -> CAN_BUILD
                4 -> CAN_MANAGE
                else -> null
            }
    }
}

interface RawPrivileges {
    val privilegeMap: PrivilegeMap
    var privilegeOfStar: Privilege

    fun getRawStoredPrivilege(key: PrivilegeKey): Privilege
    fun setRawStoredPrivilege(key: PrivilegeKey, privilege: Privilege): Boolean
    fun hasAnyDeclaredPrivileges(): Boolean
}

open class PrivilegesHolder(override var privilegeMap: MutablePrivilegeMap = EmptyPrivilegeMap) : RawPrivileges {
    private var _privilegeOfStar: Privilege = DEFAULT

    override /*open*/ var privilegeOfStar: Privilege
        get() = _privilegeOfStar
        set(value) = run { _privilegeOfStar = value }

    protected val isEmpty
        inline get() = privilegeMap === EmptyPrivilegeMap

    override fun getRawStoredPrivilege(key: PrivilegeKey) =
        if (key.isStar) _privilegeOfStar
        else privilegeMap.getOrDefault(key, _privilegeOfStar)

    override fun setRawStoredPrivilege(key: PrivilegeKey, privilege: Privilege): Boolean {
        privilege.requireNonTransient()

        if (key.isStar) {
            if (_privilegeOfStar == privilege) return false
            _privilegeOfStar = privilege
            return true
        }

        if (isEmpty) {
            if (privilege == DEFAULT) return false
            privilegeMap = MutablePrivilegeMap()
        }

        return if (privilege == DEFAULT) privilegeMap.remove(key) != null
        else privilegeMap.put(key, privilege) != privilege
    }

    override fun hasAnyDeclaredPrivileges(): Boolean {
        return privilegeMap.isNotEmpty() || privilegeOfStar != DEFAULT
    }

    fun copyPrivilegesFrom(other: PrivilegesHolder) {
        privilegeMap = other.privilegeMap
        privilegeOfStar = other.privilegeOfStar
    }

}

private fun <K, V> MutableMap<K, V>.put(key: K, value: V, override: Boolean) {
    if (override) this[key] = value
    else putIfAbsent(key, value)
}

fun RawPrivileges.filterProfilesWithPrivilegeTo(map: MutableMap<PrivilegeKey, Privilege>, privilege: Privilege) {
    if (privilegeOfStar.implies(privilege)) {
        map.putIfAbsent(PlayerProfile.Star, privilegeOfStar)
    }

    for ((profile, declaredPrivilege) in privilegeMap) {
        if (declaredPrivilege.implies(privilege)) {
            map.putIfAbsent(profile, declaredPrivilege)
        }
    }
}