Egg.kt
package de.pflugradts.passbird.domain.model.egg
import de.pflugradts.kotlinextensions.MutableOption
import de.pflugradts.kotlinextensions.MutableOption.Companion.mutableOptionOf
import de.pflugradts.passbird.domain.model.ddd.AggregateRoot
import de.pflugradts.passbird.domain.model.egg.EggId.Companion.createEggId
import de.pflugradts.passbird.domain.model.egg.Password.Companion.createPassword
import de.pflugradts.passbird.domain.model.egg.Protein.Companion.createProtein
import de.pflugradts.passbird.domain.model.event.EggCreated
import de.pflugradts.passbird.domain.model.event.EggDiscarded
import de.pflugradts.passbird.domain.model.event.EggMoved
import de.pflugradts.passbird.domain.model.event.EggRenamed
import de.pflugradts.passbird.domain.model.event.EggUpdated
import de.pflugradts.passbird.domain.model.event.ProteinCreated
import de.pflugradts.passbird.domain.model.event.ProteinDiscarded
import de.pflugradts.passbird.domain.model.event.ProteinUpdated
import de.pflugradts.passbird.domain.model.shell.EncryptedShell
import de.pflugradts.passbird.domain.model.slot.Slot
class Egg private constructor(
private var slot: Slot,
private val eggId: EggId,
private val password: Password,
val proteins: List<MutableOption<Protein>>,
) : AggregateRoot() {
init {
registerDomainEvent(EggCreated(this))
}
fun associatedNest() = slot
fun viewEggId() = eggId.view()
fun viewPassword() = password.view()
fun rename(eggIdShell: EncryptedShell) {
eggId.rename(eggIdShell)
registerDomainEvent(EggRenamed(this))
}
fun updatePassword(encryptedShell: EncryptedShell) {
password.update(encryptedShell)
registerDomainEvent(EggUpdated(this))
}
fun updateProtein(slot: Slot, typeShell: EncryptedShell, structureShell: EncryptedShell) {
val proteinOption = proteins[slot.index()]
val previousProtein = proteinOption.orNull()
val newProtein = createProtein(typeShell, structureShell)
proteinOption.set(newProtein)
if (previousProtein != null) {
registerDomainEvent(ProteinUpdated(this, slot, previousProtein, newProtein))
} else {
registerDomainEvent(ProteinCreated(this, newProtein))
}
}
fun moveToNestAt(slot: Slot) {
this.slot = slot
registerDomainEvent(EggMoved(this))
}
fun discard() {
password.discard()
registerDomainEvent(EggDiscarded(this))
}
fun discardProtein(slot: Slot) {
val proteinOption = proteins[slot.index()]
if (proteinOption.isPresent) {
val discardedProtein = proteinOption.get()
proteinOption.set(null)
registerDomainEvent(ProteinDiscarded(this, discardedProtein))
}
}
fun copy() = Egg(
slot = slot,
eggId = createEggId(eggId.view()),
password = createPassword(password.view()),
proteins = proteins.map { protein -> protein.mapMutable { createProtein(it.viewType(), it.viewStructure()) } },
).also { it.clearDomainEvents() }
override fun equals(other: Any?) = (other as? Egg)?.let {
it.viewEggId() == viewEggId() && it.associatedNest() == slot
} ?: false
override fun hashCode() = slot.hashCode() + 31 * eggId.hashCode()
companion object {
fun createEgg(
slot: Slot,
eggIdShell: EncryptedShell,
passwordShell: EncryptedShell,
proteins: List<MutableOption<Protein>> = emptyProteins(),
) = Egg(slot = slot, eggId = createEggId(eggIdShell), password = createPassword(passwordShell), proteins = proteins)
}
}
private val emptyProteins = {
listOf<MutableOption<Protein>>(
mutableOptionOf(),
mutableOptionOf(),
mutableOptionOf(),
mutableOptionOf(),
mutableOptionOf(),
mutableOptionOf(),
mutableOptionOf(),
mutableOptionOf(),
mutableOptionOf(),
mutableOptionOf(),
)
}