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> = mutableMapOf() protected fun state( default: T? = null, required: Boolean = false, writeOnce: Boolean = false ): PropertyDelegate = state(required, writeOnce) { default } protected fun extState( default: T? = null, required: Boolean = false, writeOnce: Boolean = false, equals: ExtendedPropertyDelegate.DiffScope.() -> Boolean ): ExtendedPropertyDelegate = extState(required, writeOnce, { default }, equals) protected fun state(required: Boolean = false, writeOnce: Boolean = false, default: () -> T?) = PropertyDelegate(default, required, writeOnce) protected fun extState( required: Boolean = false, writeOnce: Boolean = false, default: () -> T?, equals: ExtendedPropertyDelegate.DiffScope.() -> Boolean ) = ExtendedPropertyDelegate(default, required, writeOnce, equals) @Suppress("UNCHECKED_CAST") operator fun get(property: KProperty): PropertyDelegate = (properties[property.name] as? PropertyDelegate)!! @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 { if (javaClass != currentState.javaClass) { error("When diffing states both should be the same kind of state") } val changed = mutableSetOf() 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 } }