You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

75 lines
2.5 KiB
Kotlin

package me.eater.hefbrug.state
import me.eater.hefbrug.state.property.ExtendedPropertyDelegate
import me.eater.hefbrug.state.property.PropertyDelegate
import kotlin.reflect.KProperty
abstract class AbstractState(val id: String) {
val properties: MutableMap<String, PropertyDelegate<*>> = mutableMapOf()
protected fun <T> state(
default: T? = null,
required: Boolean = false,
writeOnce: Boolean = false
): PropertyDelegate<T> =
state<T>(required, writeOnce) { default }
protected fun <T> extState(
default: T? = null,
required: Boolean = false,
writeOnce: Boolean = false,
equals: ExtendedPropertyDelegate.DiffScope<T>.() -> Boolean
): ExtendedPropertyDelegate<T> =
extState<T>(required, writeOnce, { default }, equals)
protected fun <T> state(required: Boolean = false, writeOnce: Boolean = false, default: () -> T?) =
PropertyDelegate<T>(default, required, writeOnce)
protected fun <T> extState(
required: Boolean = false,
writeOnce: Boolean = false,
default: () -> T?,
equals: ExtendedPropertyDelegate.DiffScope<T>.() -> Boolean
) =
ExtendedPropertyDelegate<T>(default, required, writeOnce, equals)
@Suppress("UNCHECKED_CAST")
operator fun <T> get(property: KProperty<T>): PropertyDelegate<T> =
(properties[property.name] as? PropertyDelegate<T>)!!
@Suppress("UNCHECKED_CAST")
operator fun get(property: String): PropertyDelegate<*> =
properties[property]!!
override fun toString(): String =
"${this::class.simpleName ?: "State"}[id=$id] {${if (properties.isNotEmpty())
"\n ${this.properties.map { (k, v) -> "[$k]: ${v.get()}" }.joinToString("\n ")}\n"
else ""
}}"
open fun diff(currentState: AbstractState): Set<String> {
if (javaClass != currentState.javaClass) {
error("When diffing states both should be the same kind of state")
}
val changed = mutableSetOf<String>()
for ((name, property) in properties) {
val otherProperty = currentState.properties[name] ?: continue
if (property is ExtendedPropertyDelegate<*> && otherProperty is ExtendedPropertyDelegate<*>) {
if (property.hasChanged(otherProperty)) {
changed.add(name)
}
} else {
if (property.get() != otherProperty.get()) {
changed.add(name)
}
}
}
return changed
}
}